index.coffee 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. # Загрузка стилей компонента
  2. document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss" page="Page">'+stylFns['app/pages/Page/index.styl']+'</style>')
  3. # Подключение markdown парсера
  4. marked = require 'marked'
  5. module.exports =
  6. name: 'Page'
  7. render: (new Function '_ctx', '_cache', renderFns['app/pages/Page/index.pug'])()
  8. data: ->
  9. page: null
  10. loading: true
  11. error: null
  12. notFound: false
  13. pageSettings: {}
  14. computed:
  15. # Текущий язык из глобального состояния
  16. currentLanguage: ->
  17. return _.currentLanguage || 'ru'
  18. # Настройки сайта из глобального состояния
  19. siteSettings: ->
  20. return _.appState?.siteSettings || {}
  21. # Обработанный markdown контент
  22. processedContent: ->
  23. if not @page?.content
  24. return ''
  25. # Получаем контент для текущего языка
  26. content = @getMultilingualText(@page.content, '')
  27. return @processMarkdown(content)
  28. # Мета-данные для SEO
  29. pageMeta: ->
  30. if not @page
  31. return {}
  32. return {
  33. title: @getMultilingualText(@page.seo?.title, @getMultilingualText(@page.title, '')),
  34. description: @getMultilingualText(@page.seo?.description, @getMultilingualText(@page.excerpt, '')),
  35. keywords: @getMultilingualText(@page.seo?.keywords, []).join(', ')
  36. }
  37. beforeMount: ->
  38. @loadPageSettings()
  39. @loadPageData()
  40. watch:
  41. '$route.params.slug': ->
  42. @loadPageData()
  43. 'currentLanguage': ->
  44. @loadPageData()
  45. methods:
  46. # Загрузка настроек страниц
  47. loadPageSettings: ->
  48. @pageSettings = _.appState?.siteSettings?.pages || {
  49. urls: {
  50. about: '/about'
  51. contacts: '/contacts'
  52. privacy: '/privacy'
  53. terms: '/terms'
  54. }
  55. components: {
  56. about: 'AboutPage'
  57. contacts: 'ContactsPage'
  58. }
  59. strings: {
  60. not_found: ['Страница не найдена', 'Page not found', 'Саҳифа ёфт нашуд']
  61. back_to_home: ['Вернуться на главную', 'Back to home', 'Бозгашт ба саҳифаи асосӣ']
  62. loading: ['Загрузка...', 'Loading...', 'Бор шуда истодааст...']
  63. }
  64. }
  65. # Загрузка данных страницы
  66. loadPageData: ->
  67. @loading = true
  68. @error = null
  69. @notFound = false
  70. slug = @$route.params.slug
  71. if not slug
  72. @error = "Не указан slug страницы"
  73. @loading = false
  74. return
  75. @loadPageBySlug(slug).then (page) =>
  76. if page
  77. @.page = page
  78. @updatePageMeta()
  79. else
  80. @.notFound = true
  81. @loading = false
  82. .catch (error) =>
  83. @error = "Ошибка загрузки страницы: "+error
  84. @loading = false
  85. # Поиск страницы по slug
  86. loadPageBySlug: (slug) ->
  87. return new Promise (resolve, reject) =>
  88. try
  89. # Ищем в кэше глобального состояния
  90. cachedPages = _.appState?.pages || []
  91. cachedPage = cachedPages.find (page) =>
  92. slugs = @getMultilingualText(page.slug, [])
  93. return slugs.includes(slug)
  94. if cachedPage
  95. resolve(cachedPage)
  96. return
  97. # Если нет в кэше, загружаем из базы
  98. AppDB.db.query('pages/by_slug_multilingual', {
  99. key: ['borbad.s5l.ru', @currentLanguage, slug]
  100. include_docs: true
  101. }).then (result) =>
  102. if result.rows.length > 0
  103. page = AppDB.processMultilingualDocument(result.rows[0].doc)
  104. # Сохраняем в кэш
  105. if not _.appState.pages
  106. _.appState.pages = []
  107. _.appState.pages.push(page)
  108. resolve(page)
  109. else
  110. resolve(null)
  111. .catch (error) ->
  112. reject(error)
  113. catch error
  114. reject(error)
  115. # Обработка markdown с поддержкой кастомных классов
  116. processMarkdown: (content) ->
  117. if not content
  118. return ''
  119. # Обрабатываем кастомные теги для классов
  120. processedContent = content.replace(/\[class:([^\]]+)\]/g, '<div class="$1">')
  121. .replace(/\[\/class\]/g, '</div>')
  122. # Настройка marked
  123. marked.setOptions({
  124. breaks: true
  125. gfm: true
  126. sanitize: false # Разрешаем HTML для кастомных классов
  127. })
  128. return marked(processedContent)
  129. # Получение мультиязычного текста
  130. getMultilingualText: (textArray, fallback = '') ->
  131. return AppDB.multilingual.getText(textArray, fallback)
  132. # Получение локализованной строки из настроек
  133. getLocalizedString: (key, fallback = '') ->
  134. strings = @pageSettings.strings?[key] || []
  135. return @getMultilingualText(strings, fallback)
  136. # Обновление мета-данных страницы
  137. updatePageMeta: ->
  138. if @pageMeta.title
  139. document.title = @pageMeta.title + ' - Кохи Борбад'
  140. # Обновляем meta теги
  141. metaDescription = document.querySelector('meta[name="description"]')
  142. if not metaDescription
  143. metaDescription = document.createElement('meta')
  144. metaDescription.name = 'description'
  145. document.head.appendChild(metaDescription)
  146. metaDescription.content = @pageMeta.description
  147. metaKeywords = document.querySelector('meta[name="keywords"]')
  148. if not metaKeywords
  149. metaKeywords = document.createElement('meta')
  150. metaKeywords.name = 'keywords'
  151. document.head.appendChild(metaKeywords)
  152. metaKeywords.content = @pageMeta.keywords
  153. # Рендер компонента указанного в настройках страницы
  154. renderCustomComponent: ->
  155. if not @page?.settings?.component
  156. return null
  157. componentName = @page.settings.component
  158. try
  159. component = require('app/pages/' + componentName)
  160. return component
  161. catch error
  162. debug.log "Компонент "+componentName+" не найден: "+error
  163. return null
  164. # Обработка клика по внутренним ссылкам в контенте
  165. handleContentClick: (event) ->
  166. if event.target.tagName == 'A'
  167. href = event.target.getAttribute('href')
  168. if href and href.startsWith('/')
  169. event.preventDefault()
  170. _.$router.push(href)