Антологията „Събеседници на ангелите“ ще бъде представена в Регионалната библиотека в Ловеч


Антологията „Събеседници на ангелите“ на Ивона Тачева ще бъде представена в Регионалната библиотека „Проф. Беню Цонев“ в Ловеч, съобщиха за БТА от културната институция. Срещата е във вторник, 19 декември, входът е свободен.
Изданието включва български народни песни и стихотворения за Пресвета Богородица – от фолклора и възрожденската традиция до съвременната поезия. Книгата събира автентични песни от различни краища на България, Македония и българските общности в Украйна, както и стихове от Климент Охридски до днешни автори. Образът на Божията Майка е пресъздаден с дълбока почит и въображение, в преплитане на християнски и митологични мотиви. Включени са и редки, малко познати текстове на класически и съвременни поети, посветени на Мадоната и християнската духовност.

Кюстендил

В Кюстендил наградиха победителите в общинския конкурс за детско творчество „Коледа е, стават чудеса“

В Кюстендил наградиха победителите в общинския конкурс за детско творчество „Коледа е, стават чудеса“, който се организира от Община Кюстендил...

София

БНР обяви носителите на отличието "Българските посланици на културата 2024"

Българското национално радио (БНР) обяви носителите на отличието „Българските посланици на културата 2024“ на официална церемония днес в София в...

София

„Колибри“ представя в ново издание слово за поета и есеист Кирил Кадийски, произнесено от неговия колега в класическия стих Георги Борисов

Издателство „Колибри" представи в ново издание слово за поета и есеист Кирил Кадийски, произнесено от поета и преводач Георги Борисов...

Смолян

Шестгодишният Рагнар Борк получи наградата „Читател на годината 2025“ на Регионална библиотека „Николай Вранчев“ в Смолян

Шестгодишният Рагнар Йорг Борк – син на румънка и германец, получи наградата „Читател на годината 2025“ в Детския отдел на...

София

Националният литературен музей взе решение да бъде учредена награда на името на писателя Никола Радев

Националният литературен музей (НЛМ) взе решение да учреди награда на името на писателя Никола Радев. На литературно-музикална вечер в памет...

Пловдив

Пловдивският митрополит Николай присъства на коледния концерт „Заедно към вярата и надеждата“ на Държавна опера – Пловдив

С благословението на Пловдивския митрополит Николай Държавна опера – Пловдив изнесе „Музика на светлината“ – Рождественски концерт „Заедно към вярата...

(function(window, document) { 'use strict'; var CDP_VERSION = '1.0.0'; var config = { writeKey: null, apiHost: '', siteName: 'Paragrafa', siteId: 'paragrafa-com', debug: false, // Article detection selectors (customized for Paragrafa.com) selectors: { articlePage: '.article-content, .single-article, article.full', articleTitle: 'h1, .article-title, .article-block h4', articleContent: '.article-content, .article-body, .content', articleAuthor: '.author, .article-author, [rel="author"]', articleCategory: '.category a, .breadcrumb a, [class*="category"]', articleDate: '.date, .article-date, time, [datetime]', articleTags: '.tags a, .article-tags a, [rel="tag"]', }, // Category mapping (Bulgarian to English for analytics) categoryMap: { 'българия': 'Bulgaria', 'свят': 'World', 'балкани': 'Balkans', 'икономика': 'Economy', 'спорт': 'Sport', 'култура': 'Culture', 'региони': 'Regions', 'it': 'Technology', 'политика': 'Politics', 'общество': 'Society', 'здраве': 'Health', 'наука': 'Science' }, // Reading thresholds readThreshold: { scrollPercent: 75, timeSeconds: 60 }, // Engagement threshold engageThreshold: { scrollPercent: 50, timeSeconds: 30 } }; // State var state = { initialized: false, anonymousId: null, userId: null, sessionId: null, currentPage: null, articleMetadata: null, readingStartTime: null, maxScrollDepth: 0, hasTrackedView: false, hasTrackedRead: false, hasTrackedEngage: false, scrollMilestones: { 25: false, 50: false, 75: false, 100: false } }; // Utility functions function generateId() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0; var v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } function getOrCreateAnonymousId() { var storageKey = 'cdp_anonymous_id'; var id = localStorage.getItem(storageKey); if (!id) { id = generateId(); localStorage.setItem(storageKey, id); } return id; } function getSessionId() { var sessionKey = 'cdp_session_id'; var sessionTimeKey = 'cdp_session_time'; var sessionTimeout = 30 * 60 * 1000; // 30 minutes var now = Date.now(); var lastTime = parseInt(localStorage.getItem(sessionTimeKey) || '0', 10); var sessionId = localStorage.getItem(sessionKey); if (!sessionId || (now - lastTime) > sessionTimeout) { sessionId = generateId(); localStorage.setItem(sessionKey, sessionId); } localStorage.setItem(sessionTimeKey, now.toString()); return sessionId; } function log() { if (config.debug && console && console.log) { console.log.apply(console, ['[CDP News]'].concat(Array.prototype.slice.call(arguments))); } } function getContext() { return { page: { url: window.location.href, path: window.location.pathname, title: document.title, referrer: document.referrer }, userAgent: navigator.userAgent, locale: navigator.language, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, screen: { width: window.screen.width, height: window.screen.height }, session: { id: state.sessionId } }; } // Translate Bulgarian category to English function translateCategory(category) { if (!category) return null; var lower = category.toLowerCase().trim(); return config.categoryMap[lower] || category; } // Extract article metadata from page function extractArticleMetadata() { var sel = config.selectors; // Check if we're on an article page var articleContainer = document.querySelector(sel.articlePage); if (!articleContainer && !window.location.pathname.includes('/article/')) { return null; } // Extract title var titleEl = document.querySelector(sel.articleTitle); var title = titleEl ? titleEl.textContent.trim() : document.title; // Extract author var authorEl = document.querySelector(sel.articleAuthor); var author = authorEl ? authorEl.textContent.trim() : null; // Extract category (first category link found) var categoryEl = document.querySelector(sel.articleCategory); var category = categoryEl ? translateCategory(categoryEl.textContent.trim()) : null; // Extract date var dateEl = document.querySelector(sel.articleDate); var publishDate = null; if (dateEl) { publishDate = dateEl.getAttribute('datetime') || dateEl.textContent.trim(); } // Extract tags var tagEls = document.querySelectorAll(sel.articleTags); var tags = []; for (var i = 0; i < tagEls.length; i++) { tags.push(tagEls[i].textContent.trim()); } // Calculate word count var contentEl = document.querySelector(sel.articleContent); var wordCount = 0; if (contentEl) { wordCount = contentEl.textContent.trim().split(/\s+/).length; } // Generate article ID from URL var articleId = window.location.pathname.replace(/\//g, '-').replace(/^-|-$/g, '') || generateId(); return { articleId: articleId, title: title, author: author, category: category, tags: tags, publishDate: publishDate, wordCount: wordCount, url: window.location.href, siteName: config.siteName, siteId: config.siteId }; } // Detect page type function detectPageType() { var path = window.location.pathname; if (path === '/' || path === '') { return 'homepage'; } if (path.includes('/article/') || path.includes('/news/')) { return 'article'; } if (path.includes('/category/') || path.includes('/section/')) { return 'category'; } if (path.includes('/author/')) { return 'author'; } if (path.includes('/search')) { return 'search'; } if (path.includes('/tag/')) { return 'tag'; } // Check if page has article content var hasArticleContent = document.querySelector(config.selectors.articlePage); if (hasArticleContent) { return 'article'; } return 'other'; } // Send event to CDP function sendEvent(eventName, properties) { if (!config.writeKey) { log('No write key configured'); return; } var payload = { type: 'track', anonymousId: state.anonymousId, userId: state.userId, event: eventName, properties: properties || {}, context: getContext(), timestamp: new Date().toISOString() }; log('Sending event:', eventName, properties); var xhr = new XMLHttpRequest(); xhr.open('POST', config.apiHost + '/v1/events', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('Authorization', 'Bearer ' + config.writeKey); xhr.send(JSON.stringify(payload)); } // Send page view function sendPageView(properties) { if (!config.writeKey) return; var payload = { type: 'page', anonymousId: state.anonymousId, userId: state.userId, name: properties.name || document.title, properties: properties || {}, context: getContext(), timestamp: new Date().toISOString() }; log('Sending page view:', properties); var xhr = new XMLHttpRequest(); xhr.open('POST', config.apiHost + '/v1/events', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('Authorization', 'Bearer ' + config.writeKey); xhr.send(JSON.stringify(payload)); } // Calculate scroll depth function getScrollDepth() { var scrollTop = window.pageYOffset || document.documentElement.scrollTop; var scrollHeight = document.documentElement.scrollHeight; var clientHeight = document.documentElement.clientHeight; var scrollable = scrollHeight - clientHeight; if (scrollable <= 0) return 100; return Math.min(100, Math.round((scrollTop / scrollable) * 100)); } // Scroll handler function handleScroll() { if (!state.articleMetadata) return; var depth = getScrollDepth(); state.maxScrollDepth = Math.max(state.maxScrollDepth, depth); // Track scroll milestones var milestones = [25, 50, 75, 100]; for (var i = 0; i < milestones.length; i++) { var milestone = milestones[i]; if (depth >= milestone && !state.scrollMilestones[milestone]) { state.scrollMilestones[milestone] = true; sendEvent('Article Scroll Milestone', { milestone: milestone, articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category }); } } // Check for engagement threshold var timeSpent = (Date.now() - state.readingStartTime) / 1000; if (!state.hasTrackedEngage && depth >= config.engageThreshold.scrollPercent && timeSpent >= config.engageThreshold.timeSeconds) { state.hasTrackedEngage = true; sendEvent('Article Engaged', { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category, author: state.articleMetadata.author, scrollDepth: depth, timeSpent: Math.round(timeSpent), siteName: config.siteName }); } // Check for read threshold if (!state.hasTrackedRead && (depth >= config.readThreshold.scrollPercent || timeSpent >= config.readThreshold.timeSeconds)) { state.hasTrackedRead = true; sendEvent('Article Read', { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category, author: state.articleMetadata.author, tags: state.articleMetadata.tags, wordCount: state.articleMetadata.wordCount, scrollDepth: state.maxScrollDepth, timeSpent: Math.round(timeSpent), siteName: config.siteName }); } } // Page unload handler - send final reading session function handleUnload() { if (!state.articleMetadata || !state.readingStartTime) return; var timeSpent = (Date.now() - state.readingStartTime) / 1000; // Use sendBeacon for reliable delivery on page unload var payload = { type: 'track', anonymousId: state.anonymousId, userId: state.userId, event: 'Article Reading Session', properties: { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category, author: state.articleMetadata.author, scrollDepth: state.maxScrollDepth, timeSpent: Math.round(timeSpent), wasRead: state.hasTrackedRead, wasEngaged: state.hasTrackedEngage, siteName: config.siteName }, context: getContext(), timestamp: new Date().toISOString() }; if (navigator.sendBeacon && config.writeKey) { var blob = new Blob([JSON.stringify(payload)], { type: 'application/json' }); navigator.sendBeacon(config.apiHost + '/v1/events?key=' + config.writeKey, blob); } } // Initialize tracking for article page function initArticleTracking() { state.articleMetadata = extractArticleMetadata(); if (!state.articleMetadata) { log('Not an article page or could not extract metadata'); return; } log('Article detected:', state.articleMetadata); state.readingStartTime = Date.now(); state.maxScrollDepth = getScrollDepth(); // Track article view if (!state.hasTrackedView) { state.hasTrackedView = true; sendEvent('Article Viewed', { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category, author: state.articleMetadata.author, tags: state.articleMetadata.tags, wordCount: state.articleMetadata.wordCount, publishDate: state.articleMetadata.publishDate, siteName: config.siteName }); } // Set up scroll tracking var scrollTimer = null; window.addEventListener('scroll', function() { if (scrollTimer) clearTimeout(scrollTimer); scrollTimer = setTimeout(handleScroll, 100); }); // Periodic check for time-based reading setInterval(handleScroll, 5000); // Handle page unload window.addEventListener('beforeunload', handleUnload); window.addEventListener('pagehide', handleUnload); } // Public API window.cdpNews = { // Initialize the SDK init: function(writeKey, options) { if (state.initialized) { log('Already initialized'); return; } options = options || {}; config.writeKey = writeKey; config.apiHost = options.apiHost || ''; config.siteName = options.siteName || config.siteName; config.siteId = options.siteId || config.siteId; config.debug = options.debug || false; if (options.selectors) { for (var key in options.selectors) { if (options.selectors.hasOwnProperty(key)) { config.selectors[key] = options.selectors[key]; } } } if (options.categoryMap) { for (var cat in options.categoryMap) { if (options.categoryMap.hasOwnProperty(cat)) { config.categoryMap[cat.toLowerCase()] = options.categoryMap[cat]; } } } state.anonymousId = getOrCreateAnonymousId(); state.sessionId = getSessionId(); state.initialized = true; log('Initialized with write key:', writeKey.substring(0, 8) + '...'); // Auto-detect page type and start tracking var pageType = detectPageType(); state.currentPage = pageType; log('Page type:', pageType); // Send page view sendPageView({ pageType: pageType, siteName: config.siteName }); // Initialize article tracking if on article page if (pageType === 'article') { // Wait for DOM to be fully loaded if (document.readyState === 'complete') { initArticleTracking(); } else { window.addEventListener('load', initArticleTracking); } } }, // Identify user identify: function(userId, traits) { state.userId = userId; var payload = { type: 'identify', anonymousId: state.anonymousId, userId: userId, traits: traits || {}, context: getContext(), timestamp: new Date().toISOString() }; log('Identify:', userId, traits); if (config.writeKey) { var xhr = new XMLHttpRequest(); xhr.open('POST', config.apiHost + '/v1/events', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('Authorization', 'Bearer ' + config.writeKey); xhr.send(JSON.stringify(payload)); } }, // Track custom event track: function(eventName, properties) { sendEvent(eventName, properties); }, // Track article share trackShare: function(channel) { if (!state.articleMetadata) return; sendEvent('Article Shared', { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category, channel: channel || 'unknown', siteName: config.siteName }); }, // Track comment trackComment: function() { if (!state.articleMetadata) return; sendEvent('Comment Posted', { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category, siteName: config.siteName }); }, // Track article save/bookmark trackSave: function() { if (!state.articleMetadata) return; sendEvent('Article Saved', { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, category: state.articleMetadata.category, siteName: config.siteName }); }, // Track search trackSearch: function(query, resultsCount) { sendEvent('Search Performed', { query: query, resultsCount: resultsCount || 0, siteName: config.siteName }); }, // Track newsletter signup trackNewsletterSignup: function(email) { sendEvent('Newsletter Subscribed', { email: email, siteName: config.siteName }); }, // Get current reading state (for debugging) getReadingState: function() { if (!state.articleMetadata) return null; var timeSpent = state.readingStartTime ? (Date.now() - state.readingStartTime) / 1000 : 0; return { articleId: state.articleMetadata.articleId, title: state.articleMetadata.title, scrollDepth: state.maxScrollDepth, timeSpent: Math.round(timeSpent), hasTrackedRead: state.hasTrackedRead, hasTrackedEngage: state.hasTrackedEngage }; }, // Debug mode debug: function(enabled) { config.debug = enabled !== false; log('Debug mode:', config.debug ? 'enabled' : 'disabled'); } }; log('CDP News SDK loaded (Paragrafa.com version)'); })(window, document);