content.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. var $ = document.querySelector.bind(document)
  2. var state = {
  3. theme,
  4. raw,
  5. content,
  6. html: '',
  7. markdown: '',
  8. toc: ''
  9. }
  10. chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
  11. if (req.message === 'reload') {
  12. location.reload(true)
  13. }
  14. else if (req.message === 'theme') {
  15. state.theme = req.theme
  16. m.redraw()
  17. }
  18. else if (req.message === 'raw') {
  19. state.raw = req.raw
  20. m.redraw()
  21. }
  22. })
  23. var oncreate = {
  24. markdown: () => {
  25. scroll()
  26. },
  27. html: () => {
  28. scroll()
  29. if (state.content.toc && !state.toc) {
  30. state.toc = toc()
  31. m.redraw()
  32. }
  33. setTimeout(() => Prism.highlightAll(), 20)
  34. }
  35. }
  36. function mount () {
  37. $('pre').style.display = 'none'
  38. var md = $('pre').innerText
  39. m.mount($('body'), {
  40. oninit: () => {
  41. ;((done) => {
  42. if (document.charset === 'UTF-8') {
  43. done()
  44. return
  45. }
  46. m.request({method: 'GET', url: location.href,
  47. deserialize: (body) => {
  48. done(body)
  49. return body
  50. }
  51. })
  52. })((data) => {
  53. state.markdown = data || md
  54. chrome.runtime.sendMessage({
  55. message: 'markdown',
  56. markdown: state.markdown
  57. }, (res) => {
  58. state.html = res.marked
  59. m.redraw()
  60. })
  61. })
  62. },
  63. view: () => {
  64. var dom = []
  65. if (state.raw) {
  66. dom.push(m('pre#markdown', {oncreate: oncreate.markdown}, state.markdown))
  67. $('body').classList.remove('_toc-left', '_toc-right')
  68. }
  69. else {
  70. if (state.theme) {
  71. dom.push(m('link#theme [rel="stylesheet"] [type="text/css"]', {
  72. href: chrome.runtime.getURL('/themes/' + state.theme + '.css')
  73. }))
  74. }
  75. if (state.html) {
  76. dom.push(m('#html', {oncreate: oncreate.html,
  77. class: /github(-dark)?/.test(state.theme) ? 'markdown-body' : 'markdown-theme'},
  78. m.trust(state.html)
  79. ))
  80. if (state.content.toc && state.toc) {
  81. dom.push(m.trust(state.toc))
  82. $('body').classList.add('_toc-left')
  83. }
  84. }
  85. }
  86. return (dom.length ? dom : m('div'))
  87. }
  88. })
  89. }
  90. function scroll () {
  91. if (state.content.scroll) {
  92. $('body').scrollTop = parseInt(localStorage.getItem('md-' + location.href))
  93. }
  94. else if (location.hash) {
  95. $('body').scrollTop = $(location.hash) && $(location.hash).offsetTop
  96. setTimeout(() => {
  97. $('body').scrollTop = $(location.hash) && $(location.hash).offsetTop
  98. }, 100)
  99. }
  100. }
  101. scroll.init = () => {
  102. if (state.content.scroll) {
  103. var timeout = null
  104. window.addEventListener('scroll', () => {
  105. clearTimeout(timeout)
  106. timeout = setTimeout(() => {
  107. localStorage.setItem('md-' + location.href, $('body').scrollTop)
  108. }, 100)
  109. })
  110. }
  111. setTimeout(scroll, 100)
  112. }
  113. if (document.readyState === 'complete') {
  114. mount()
  115. scroll.init()
  116. }
  117. else {
  118. window.addEventListener('DOMContentLoaded', mount)
  119. window.addEventListener('load', scroll.init)
  120. }
  121. var toc = ((link) => () => Array.from($('#html').childNodes)
  122. .filter((node) => /h[1-6]/i.test(node.tagName))
  123. .map((node) => ({
  124. id: node.getAttribute('id'),
  125. level: parseInt(node.tagName.replace('H', '')),
  126. title: node.innerText
  127. }))
  128. .reduce((html, header, index, headers) => {
  129. if (index) {
  130. var prev = headers[index - 1]
  131. }
  132. if (!index || prev.level === header.level) {
  133. html += link(header)
  134. }
  135. else if (prev.level > header.level) {
  136. html += '</div>' + link(header)
  137. }
  138. else if (prev.level < header.level) {
  139. html += '<div id="_ul">' + link(header)
  140. }
  141. return html
  142. }, '<div id="_toc"><div id="_ul">') + '</div></div>'
  143. )((header) => '<a href="#' + header.id + '">' + header.title + '</a>')