entry_page.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. class app.views.EntryPage extends app.View
  2. @className: '_page'
  3. @errorClass: '_page-error'
  4. @events:
  5. click: 'onClick'
  6. @shortcuts:
  7. altC: 'onAltC'
  8. altO: 'onAltO'
  9. @routes:
  10. before: 'beforeRoute'
  11. init: ->
  12. @cacheMap = {}
  13. @cacheStack = []
  14. return
  15. deactivate: ->
  16. if super
  17. @empty()
  18. @entry = null
  19. return
  20. loading: ->
  21. @empty()
  22. @trigger 'loading'
  23. return
  24. render: (content = '', fromCache = false) ->
  25. return unless @activated
  26. @empty()
  27. @subview = new (@subViewClass()) @el, @entry
  28. $.batchUpdate @el, =>
  29. @subview.render(content, fromCache)
  30. @addCopyButtons() unless fromCache
  31. return
  32. if app.disabledDocs.findBy 'slug', @entry.doc.slug
  33. @hiddenView = new app.views.HiddenPage @el, @entry
  34. setFaviconForDoc(@entry.doc)
  35. @delay @polyfillMathML
  36. @trigger 'loaded'
  37. return
  38. addCopyButtons: ->
  39. unless @copyButton
  40. @copyButton = document.createElement('button')
  41. @copyButton.innerHTML = '<svg><use xlink:href="#icon-copy"/></svg>'
  42. @copyButton.type = 'button'
  43. @copyButton.className = '_pre-clip'
  44. @copyButton.title = 'Copy to clipboard'
  45. @copyButton.setAttribute 'aria-label', 'Copy to clipboard'
  46. el.appendChild @copyButton.cloneNode(true) for el in @findAllByTag('pre')
  47. return
  48. polyfillMathML: ->
  49. return unless window.supportsMathML is false and !@polyfilledMathML and @findByTag('math')
  50. @polyfilledMathML = true
  51. $.append document.head, """<link rel="stylesheet" href="#{app.config.mathml_stylesheet}">"""
  52. return
  53. LINKS =
  54. home: 'Homepage'
  55. code: 'Source code'
  56. prepareContent: (content) ->
  57. return content unless @entry.isIndex() and @entry.doc.links
  58. links = for link, url of @entry.doc.links
  59. """<a href="#{url}" class="_links-link">#{LINKS[link]}</a>"""
  60. """<p class="_links">#{links.join('')}</p>#{content}"""
  61. empty: ->
  62. @subview?.deactivate()
  63. @subview = null
  64. @hiddenView?.deactivate()
  65. @hiddenView = null
  66. @resetClass()
  67. super
  68. return
  69. subViewClass: ->
  70. app.views["#{$.classify(@entry.doc.type)}Page"] or app.views.BasePage
  71. getTitle: ->
  72. @entry.doc.fullName + if @entry.isIndex() then ' documentation' else " / #{@entry.name}"
  73. beforeRoute: =>
  74. @cache()
  75. @abort()
  76. return
  77. onRoute: (context) ->
  78. isSameFile = context.entry.filePath() is @entry?.filePath()
  79. @entry = context.entry
  80. @restore() or @load() unless isSameFile
  81. return
  82. load: ->
  83. @loading()
  84. @xhr = @entry.loadFile @onSuccess, @onError
  85. return
  86. abort: ->
  87. if @xhr
  88. @xhr.abort()
  89. @xhr = @entry = null
  90. return
  91. onSuccess: (response) =>
  92. return unless @activated
  93. @xhr = null
  94. @render @prepareContent(response)
  95. return
  96. onError: =>
  97. @xhr = null
  98. @render @tmpl('pageLoadError')
  99. @resetClass()
  100. @addClass @constructor.errorClass
  101. app.serviceWorker?.update()
  102. return
  103. cache: ->
  104. return if @xhr or not @entry or @cacheMap[path = @entry.filePath()]
  105. @cacheMap[path] = @el.innerHTML
  106. @cacheStack.push(path)
  107. while @cacheStack.length > app.config.history_cache_size
  108. delete @cacheMap[@cacheStack.shift()]
  109. return
  110. restore: ->
  111. if @cacheMap[path = @entry.filePath()]
  112. @render @cacheMap[path], true
  113. true
  114. onClick: (event) =>
  115. target = $.eventTarget(event)
  116. if target.hasAttribute 'data-retry'
  117. $.stopEvent(event)
  118. @load()
  119. else if target.classList.contains '_pre-clip'
  120. $.stopEvent(event)
  121. target.classList.add if $.copyToClipboard(target.parentNode.textContent) then '_pre-clip-success' else '_pre-clip-error'
  122. setTimeout (-> target.className = '_pre-clip'), 2000
  123. return
  124. onAltC: =>
  125. return unless link = @find('._attribution:last-child ._attribution-link')
  126. console.log(link.href + location.hash)
  127. navigator.clipboard.writeText(link.href + location.hash)
  128. return
  129. onAltO: =>
  130. return unless link = @find('._attribution:last-child ._attribution-link')
  131. @delay -> $.popup(link.href + location.hash)
  132. return