# обязательно подключение глобальных массивов
globalThis.renderFns = require 'pug.json'
globalThis.stylFns = require 'styl.json'
# подключение мета информации (строго в данном фиде)
document.head.insertAdjacentHTML 'beforeend',''
document.head.insertAdjacentHTML 'beforeend',''
document.head.insertAdjacentHTML('beforeend','
Кохи Борбад - Концертный зал Душанбе')
# Настройка tailwind
tailwind.config = require 'tailwind.config.js'
# подключение основных стилей
## tailwind
document.head.insertAdjacentHTML('beforeend','')
## базовой стиль приложения
document.head.insertAdjacentHTML('beforeend','')
# Создаем глобальную шину событий
class AppEventBus
constructor: ->
@events = {}
on: (event, callback) ->
if !@events[event]
@events[event] = []
@events[event].push(callback)
emit: (event, data) ->
if @events[event]
for callback in @events[event]
try
callback(data)
catch error
debug.log "Event bus error: " + error
off: (event, callback) ->
if @events[event]
@events[event] = @events[event].filter (cb) -> cb != callback
# Создаем глобально
globalThis.EventBus = new AppEventBus()
# Класс для работы с мультиязычными данными
class MultilingualData
constructor: ->
@currentLanguage = 'ru'
@availableLanguages = ['ru', 'en', 'tj']
@fallbackLanguage = 'ru'
# Установка текущего языка
setLanguage: (language) ->
if language in @availableLanguages
@currentLanguage = language
EventBus.emit('language_changed', language)
debug.log "Язык изменен на: "+language
# Получение текста для текущего языка
getText: (textArray, fallback = '') ->
if not textArray or not Array.isArray(textArray)
return fallback
languageIndex = @availableLanguages.indexOf(@currentLanguage)
if languageIndex is -1 or languageIndex >= textArray.length
languageIndex = @availableLanguages.indexOf(@fallbackLanguage)
return textArray[languageIndex] or fallback
# Получение всех текстов для отладки
getAllTexts: (textArray) ->
if not textArray or not Array.isArray(textArray)
return {}
result = {}
for lang, index in @availableLanguages
if textArray[index]
result[lang] = textArray[index]
return result
# Класс для работы с базой данных
class AppDatabase
constructor: ->
@db = null
@baseUrl = 'https://oleg:631074@couchdb.favt.ru.net'
@dbName = 'borbad_events'
@initialized = false
@multilingual = new MultilingualData()
# Инициализация базы данных
initialize: ->
try
PouchDB = require 'pouchdb'
@db = new PouchDB(@baseUrl+"/"+@dbName)
# Проверяем соединение
info = await @db.info()
debug.log "База данных подключена: "+info.db_name
@initialized = true
EventBus.emit('database_ready', @db)
catch error
debug.log "Ошибка подключения к базе данных: "+error
EventBus.emit('database_error', error)
# Получение документов по типу с мультиязычной обработкой
getDocumentsByType: (type, options = {}) ->
if not @initialized
throw new Error("База данных не инициализирована")
try
viewName = options.view or 'published_by_domain_language'
designDoc = options.designDoc or 'multilingual_content'
result = await @db.query(designDoc+'/'+viewName, {
startkey: [options.domain or 'borbad.s5l.ru', @multilingual.currentLanguage]
endkey: [options.domain or 'borbad.s5l.ru', @multilingual.currentLanguage, {}]
include_docs: true
descending: options.descending or true
limit: options.limit or 10
skip: options.skip or 0
})
# Обрабатываем мультиязычные данные
processedDocs = result.rows.map (row) =>
@processMultilingualDocument(row.doc)
return processedDocs
catch error
debug.log "Ошибка получения документов типа "+type+": "+error
return []
# Обработка мультиязычного документа
processMultilingualDocument: (doc) ->
if not doc
return null
processedDoc = Object.assign({}, doc)
# Обрабатываем мультиязычные поля
multilingualFields = ['title', 'content', 'excerpt', 'author', 'name', 'description', 'location']
for field in multilingualFields
if doc[field] and Array.isArray(doc[field])
processedDoc[field] = @multilingual.getText(doc[field])
# Обрабатываем вложенные мультиязычные структуры
if doc.seo
processedDoc.seo = {}
if doc.seo.description and Array.isArray(doc.seo.description)
processedDoc.seo.description = @multilingual.getText(doc.seo.description)
if doc.seo.title and Array.isArray(doc.seo.title)
processedDoc.seo.title = @multilingual.getText(doc.seo.title)
if doc.seo.keywords and Array.isArray(doc.seo.keywords)
processedDoc.seo.keywords = @multilingual.getText(doc.seo.keywords, [])
# Обрабатываем специфичные данные для разных типов
if doc.type is 'event' and doc.event_data
processedDoc.event_data = Object.assign({}, doc.event_data)
if doc.event_data.location and Array.isArray(doc.event_data.location)
processedDoc.event_data.location = @multilingual.getText(doc.event_data.location)
if doc.event_data.price and Array.isArray(doc.event_data.price)
processedDoc.event_data.price = @multilingual.getText(doc.event_data.price)
if doc.type is 'product' and doc.product_data
processedDoc.product_data = Object.assign({}, doc.product_data)
if doc.product_data.price and Array.isArray(doc.product_data.price)
processedDoc.product_data.price = @multilingual.getText(doc.product_data.price)
if doc.type is 'slide' and doc.slide_data
processedDoc.slide_data = Object.assign({}, doc.slide_data)
if doc.slide_data.button_text and Array.isArray(doc.slide_data.button_text)
processedDoc.slide_data.button_text = @multilingual.getText(doc.slide_data.button_text)
if doc.slide_data.button_link and Array.isArray(doc.slide_data.button_link)
processedDoc.slide_data.button_link = @multilingual.getText(doc.slide_data.button_link)
return processedDoc
# Получение блог постов
getBlogPosts: (options = {}) ->
options.type = 'blog_post'
return await @getDocumentsByType('blog_post', options)
# Получение мероприятий
getEvents: (options = {}) ->
options.type = 'event'
options.view = 'by_date_multilingual'
return await @getDocumentsByType('event', options)
# Получение предстоящих мероприятий
getUpcomingEvents: (options = {}) ->
options.type = 'event'
options.view = 'upcoming_events'
return await @getDocumentsByType('event', options)
# Получение товаров
getProducts: (options = {}) ->
options.type = 'product'
options.view = 'by_status_multilingual'
return await @getDocumentsByType('product', options)
# Получение слайдов
getSlides: (options = {}) ->
options.type = 'slide'
options.view = 'active_ordered_multilingual'
options.descending = false
return await @getDocumentsByType('slide', options)
# Получение категорий
getCategories: (options = {}) ->
if not @initialized
throw new Error("База данных не инициализирована")
try
result = await @db.query('categories_hierarchical_multilingual/by_level_multilingual', {
startkey: [options.domain or 'borbad.s5l.ru', @multilingual.currentLanguage, 0]
endkey: [options.domain or 'borbad.s5l.ru', @multilingual.currentLanguage, 0, {}]
include_docs: true
ascending: true
})
processedCategories = result.rows.map (row) =>
@processMultilingualDocument(row.doc)
return processedCategories
catch error
debug.log "Ошибка получения категорий: "+error
return []
# Поиск по контенту
searchContent: (query, options = {}) ->
if not @initialized
throw new Error("База данных не инициализирована")
try
result = await @db.query('universal_multilingual_search/content_search', {
startkey: [options.domain or 'borbad.s5l.ru', @multilingual.currentLanguage, query.toLowerCase()]
endkey: [options.domain or 'borbad.s5l.ru', @multilingual.currentLanguage, query.toLowerCase() + "\ufff0"]
include_docs: true
limit: options.limit or 20
})
processedResults = result.rows.map (row) =>
@processMultilingualDocument(row.doc)
return processedResults
catch error
debug.log "Ошибка поиска: "+error
return []
# Получение документа по ID
getDocumentById: (id) ->
if not @initialized
throw new Error("База данных не инициализирована")
try
doc = await @db.get(id)
return @processMultilingualDocument(doc)
catch error
debug.log "Ошибка получения документа "+id+": "+error
return null
# Создаем глобальные экземпляры
globalThis.AppDB = new AppDatabase()
globalThis.Multilingual = new MultilingualData()
# Маршруты
routes = [
{ path: '/', component: require 'app/pages/Home' }
{ path: '/events', component: require 'app/pages/Events' }
{ path: '/events/:id', component: require 'app/pages/EventDetail' }
# { path: '/blog', component: require 'app/pages/Blog' }
# { path: '/blog/:id', component: require 'app/pages/BlogDetail' }
# { path: '/products', component: require 'app/pages/Products' }
# { path: '/products/:id', component: require 'app/pages/ProductDetail' }
{ path: '/about', component: require 'app/pages/About' }
{ path: '/contacts', component: require 'app/pages/Contacts' }
]
# Глобальное определение vuejs приложения
app = Vue.createApp
name: 'app'
data: ()->
return
dbReady: false
loading: true
error: null
currentLanguage: 'ru'
availableLanguages: ['ru', 'en', 'tj']
# Глобальное состояние приложения
appState:
slides: []
featuredEvents: []
blogPosts: []
products: []
categories: []
loading: true
error: null
# Состояние модальных окон
modalState:
isVisible: false
component: null
props: {}
beforeMount: ()->
debug.log "start beforeMount"
# определение контекста vuejs приложения как глобальной переменной _
globalThis._ = @
# Инициализация базы данных
AppDB.initialize().then =>
@dbReady = true
@loadInitialData()
# Слушаем события смены языка
EventBus.on 'language_changed', (language) =>
@currentLanguage = language
@loadInitialData()
mounted: ->
debug.log "App mounted"
methods:
# Загрузка начальных данных
loadInitialData: ->
@appState.loading = true
@appState.error = null
Promise.all([
@loadSlides()
@loadFeaturedEvents()
@loadBlogPosts()
@loadCategories()
]).then =>
@appState.loading = false
.catch (error) =>
@appState.error = "Ошибка загрузки данных: "+error
@appState.loading = false
# Загрузка слайдов
loadSlides: ->
AppDB.getSlides(limit: 6).then (slides) =>
@appState.slides = slides
.catch (error) =>
debug.log "Ошибка загрузки слайдов: "+error
# Загрузка избранных мероприятий
loadFeaturedEvents: ->
AppDB.getUpcomingEvents(limit: 4).then (events) =>
@appState.featuredEvents = events
.catch (error) =>
debug.log "Ошибка загрузки мероприятий: "+error
# Загрузка блог постов
loadBlogPosts: ->
AppDB.getBlogPosts(limit: 6).then (posts) =>
@appState.blogPosts = posts
.catch (error) =>
debug.log "Ошибка загрузки блог постов: "+error
# Загрузка категорий
loadCategories: ->
AppDB.getCategories().then (categories) =>
@appState.categories = categories
.catch (error) =>
debug.log "Ошибка загрузки категорий: "+error
# Смена языка
changeLanguage: (language) ->
if language in @availableLanguages
AppDB.multilingual.setLanguage(language)
@currentLanguage = language
# Поиск по сайту
search: (query) ->
if query and query.length > 2
AppDB.searchContent(query).then (results) ->
EventBus.emit('search_results', results)
# Открытие модального окна
openModal: (component, props = {}) ->
@modalState.component = component
@modalState.props = props
@modalState.isVisible = true
# Закрытие модального окна
closeModal: ->
@modalState.isVisible = false
@modalState.component = null
@modalState.props = {}
render: (new Function '_ctx', '_cache', renderFns['app/temp.pug'])()
components:
'themetoggle': require 'app/shared/ThemeToggle'
'multilevelmenu': require 'app/shared/MultiLevelMenu'
'imageslider': require 'app/shared/ImageSlider'
'app-link': require 'app/shared/AppLink'
'language-switcher': require 'app/shared/LanguageSwitcher'
app.use(VueRouter.createRouter({
routes: routes
history: VueRouter.createWebHistory()
scrollBehavior: (to, from, savedPosition) ->
if savedPosition
return savedPosition
else
return { x: 0, y: 0 }
}))
# подключаем в body ОБЯЗАТЕЛЬНО!!!
app.mount('body')