index.coffee 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. # Загрузка стилей компонента
  2. document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss" page="AppLink">'+stylFns['app/shared/AppLink/index.styl']+'</style>')
  3. module.exports =
  4. name: 'AppLink'
  5. render: (new Function '_ctx', '_cache', renderFns['app/shared/AppLink/index.pug'])()
  6. props:
  7. to:
  8. type: [String, Object]
  9. required: true
  10. href:
  11. type: String
  12. default: ''
  13. target:
  14. type: String
  15. default: '_self'
  16. rel:
  17. type: String
  18. default: ''
  19. class:
  20. type: [String, Object, Array]
  21. default: ''
  22. activeClass:
  23. type: String
  24. default: 'app-link--active'
  25. exact:
  26. type: Boolean
  27. default: false
  28. computed:
  29. # Определяем тип ссылки: внутренняя (router) или внешняя
  30. isExternalLink: ->
  31. if typeof @to is 'string'
  32. return @isExternalUrl(@to) or @to.startsWith('http') or @to.startsWith('//') or @to.startsWith('mailto:') or @to.startsWith('tel:')
  33. return false
  34. # Определяем является ли ссылка маршрутом Vue Router
  35. isRouterLink: ->
  36. if typeof @to is 'object'
  37. return true
  38. if typeof @to is 'string' and not @isExternalLink
  39. return @to.startsWith('/') and not @to.startsWith('//')
  40. return false
  41. # Нормализованный URL для внешних ссылок
  42. normalizedHref: ->
  43. if @href
  44. return @href
  45. if typeof @to is 'string' and @isExternalLink
  46. return @to
  47. return ''
  48. # Нормализованный to для router-link
  49. normalizedTo: ->
  50. if typeof @to is 'object'
  51. return @to
  52. if typeof @to is 'string' and not @isExternalLink
  53. return @to
  54. return ''
  55. # Классы для компонента
  56. linkClasses: ->
  57. baseClasses = 'app-link transition-colors duration-200'
  58. if typeof @class is 'string'
  59. return baseClasses + ' ' + @class
  60. else if Array.isArray(@class)
  61. return [baseClasses, ...@class]
  62. else if typeof @class is 'object'
  63. return Object.assign({}, {[baseClasses]: true}, @class)
  64. else
  65. return baseClasses
  66. methods:
  67. # Проверка является ли URL внешним
  68. isExternalUrl: (url) ->
  69. if not url or typeof url isnt 'string'
  70. return false
  71. # Проверяем различные признаки внешних ссылок
  72. externalPatterns = [
  73. /^https?:\/\//i
  74. /^\/\//i
  75. /^mailto:/i
  76. /^tel:/i
  77. /^ftp:/i
  78. /^#/i # якорные ссылки считаем внешними для простоты
  79. ]
  80. for pattern in externalPatterns
  81. if pattern.test(url)
  82. return true
  83. return false
  84. # Обработчик клика для внешних ссылок
  85. handleExternalClick: (event) ->
  86. # Если target="_blank", добавляем noopener noreferrer для безопасности
  87. if @target is '_blank' and not @rel
  88. @$el.rel = 'noopener noreferrer'
  89. # Можно добавить аналитику или другие обработчики здесь
  90. EventBus.emit('external_link_clicked', {
  91. url: @normalizedHref
  92. target: @target
  93. })
  94. # Обработчик клика для внутренних ссылок
  95. handleInternalClick: (event) ->
  96. # Можно добавить аналитику или другие обработчики здесь
  97. EventBus.emit('internal_link_clicked', {
  98. to: @normalizedTo
  99. route: @$route
  100. })