content.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. class app.views.Content extends app.View
  2. @el: '._content'
  3. @loadingClass: '_content-loading'
  4. @events:
  5. click: 'onClick'
  6. @shortcuts:
  7. altUp: 'scrollStepUp'
  8. altDown: 'scrollStepDown'
  9. pageUp: 'scrollPageUp'
  10. pageDown: 'scrollPageDown'
  11. pageTop: 'scrollToTop'
  12. pageBottom: 'scrollToBottom'
  13. altF: 'onAltF'
  14. @routes:
  15. before: 'beforeRoute'
  16. after: 'afterRoute'
  17. init: ->
  18. @scrollEl = if app.isMobile()
  19. (document.scrollingElement || document.body)
  20. else
  21. @el
  22. @scrollMap = {}
  23. @scrollStack = []
  24. @rootPage = new app.views.RootPage
  25. @staticPage = new app.views.StaticPage
  26. @settingsPage = new app.views.SettingsPage
  27. @offlinePage = new app.views.OfflinePage
  28. @typePage = new app.views.TypePage
  29. @entryPage = new app.views.EntryPage
  30. @entryPage
  31. .on 'loading', @onEntryLoading
  32. .on 'loaded', @onEntryLoaded
  33. app
  34. .on 'ready', @onReady
  35. .on 'bootError', @onBootError
  36. return
  37. show: (view) ->
  38. @hideLoading()
  39. unless view is @view
  40. @view?.deactivate()
  41. @html @view = view
  42. @view.activate()
  43. return
  44. showLoading: ->
  45. @addClass @constructor.loadingClass
  46. return
  47. isLoading: ->
  48. @el.classList.contains @constructor.loadingClass
  49. hideLoading: ->
  50. @removeClass @constructor.loadingClass
  51. return
  52. scrollTo: (value) ->
  53. @scrollEl.scrollTop = value or 0
  54. return
  55. smoothScrollTo: (value) ->
  56. if app.settings.get('fastScroll')
  57. @scrollTo value
  58. else
  59. $.smoothScroll @scrollEl, value or 0
  60. return
  61. scrollBy: (n) ->
  62. @smoothScrollTo @scrollEl.scrollTop + n
  63. return
  64. scrollToTop: =>
  65. @smoothScrollTo 0
  66. return
  67. scrollToBottom: =>
  68. @smoothScrollTo @scrollEl.scrollHeight
  69. return
  70. scrollStepUp: =>
  71. @scrollBy -80
  72. return
  73. scrollStepDown: =>
  74. @scrollBy 80
  75. return
  76. scrollPageUp: =>
  77. @scrollBy 40 - @scrollEl.clientHeight
  78. return
  79. scrollPageDown: =>
  80. @scrollBy @scrollEl.clientHeight - 40
  81. return
  82. scrollToTarget: ->
  83. if @routeCtx.hash and el = @findTargetByHash @routeCtx.hash
  84. $.scrollToWithImageLock el, @scrollEl, 'top',
  85. margin: if @scrollEl is @el then 0 else $.offset(@el).top
  86. $.highlight el, className: '_highlight'
  87. else
  88. @scrollTo @scrollMap[@routeCtx.state.id]
  89. return
  90. onReady: =>
  91. @hideLoading()
  92. return
  93. onBootError: =>
  94. @hideLoading()
  95. @html @tmpl('bootError')
  96. return
  97. onEntryLoading: =>
  98. @showLoading()
  99. if @scrollToTargetTimeout
  100. clearTimeout @scrollToTargetTimeout
  101. @scrollToTargetTimeout = null
  102. return
  103. onEntryLoaded: =>
  104. @hideLoading()
  105. if @scrollToTargetTimeout
  106. clearTimeout @scrollToTargetTimeout
  107. @scrollToTargetTimeout = null
  108. @scrollToTarget()
  109. return
  110. beforeRoute: (context) =>
  111. @cacheScrollPosition()
  112. @routeCtx = context
  113. @scrollToTargetTimeout = @delay @scrollToTarget
  114. return
  115. cacheScrollPosition: ->
  116. return if not @routeCtx or @routeCtx.hash
  117. return if @routeCtx.path is '/'
  118. unless @scrollMap[@routeCtx.state.id]?
  119. @scrollStack.push @routeCtx.state.id
  120. while @scrollStack.length > app.config.history_cache_size
  121. delete @scrollMap[@scrollStack.shift()]
  122. @scrollMap[@routeCtx.state.id] = @scrollEl.scrollTop
  123. return
  124. afterRoute: (route, context) =>
  125. if route != 'entry' and route != 'type'
  126. resetFavicon()
  127. switch route
  128. when 'root'
  129. @show @rootPage
  130. when 'entry'
  131. @show @entryPage
  132. when 'type'
  133. @show @typePage
  134. when 'settings'
  135. @show @settingsPage
  136. when 'offline'
  137. @show @offlinePage
  138. else
  139. @show @staticPage
  140. @view.onRoute(context)
  141. app.document.setTitle @view.getTitle?()
  142. return
  143. onClick: (event) =>
  144. link = $.closestLink $.eventTarget(event), @el
  145. if link and @isExternalUrl link.getAttribute('href')
  146. $.stopEvent(event)
  147. $.popup(link)
  148. return
  149. onAltF: (event) =>
  150. unless document.activeElement and $.hasChild @el, document.activeElement
  151. @find('a:not(:empty)')?.focus()
  152. $.stopEvent(event)
  153. findTargetByHash: (hash) ->
  154. el = try $.id decodeURIComponent(hash) catch
  155. el or= try $.id(hash) catch
  156. el
  157. isExternalUrl: (url) ->
  158. url?[0..5] in ['http:/', 'https:']