background.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // chrome.storage.sync.clear()
  2. // chrome.permissions.getAll((p) => chrome.permissions.remove({origins: p.origins}))
  3. var match = '\\.(?:markdown|mdown|mkdn|md|mkd|mdwn|mdtxt|mdtext|text)(?:#.*)?$'
  4. var defaults = {
  5. theme: 'github',
  6. compiler: 'marked',
  7. content: {
  8. emoji: false,
  9. scroll: true,
  10. toc: false
  11. },
  12. raw: false,
  13. header: true,
  14. match,
  15. origins: {
  16. 'file://': match
  17. }
  18. }
  19. Object.keys(md).forEach((compiler) => {
  20. defaults[compiler] = md[compiler].defaults
  21. })
  22. var state
  23. function set (options) {
  24. chrome.storage.sync.set(options)
  25. Object.assign(state, options)
  26. }
  27. chrome.storage.sync.get((res) => {
  28. var options = !Object.keys(res).length ? defaults : res
  29. // v2.2 -> v2.3
  30. if (!options.match || !options.origins) {
  31. options.match = match
  32. options.origins = {
  33. 'file://': match
  34. }
  35. }
  36. // v2.3 -> v2.4
  37. else if (!options.origins['file://']) {
  38. options.origins['file://'] = match
  39. }
  40. // v2.4 -> v2.5
  41. if (!options.compiler) {
  42. options.compiler = options.options
  43. }
  44. if (!options.content) {
  45. options.content = defaults.content
  46. }
  47. // v2.7 -> v2.8
  48. if (!options.marked) {
  49. options.compiler = 'marked'
  50. options.marked = md.marked.defaults
  51. }
  52. // v2.8 -> v2.9
  53. if (!options.remark) {
  54. options.remark = md.remark.defaults
  55. }
  56. // v2.9 -> v3.0
  57. if (options.content.emoji === undefined) {
  58. options.content.emoji = false
  59. }
  60. // v3.0 -> v3.1
  61. if (options.header === undefined) {
  62. options.header = true
  63. }
  64. Object.keys(md).forEach((compiler) => {
  65. if (!options[compiler]) {
  66. options[compiler] = md[compiler].defaults
  67. }
  68. })
  69. chrome.storage.sync.set(options)
  70. state = JSON.parse(JSON.stringify(options))
  71. })
  72. function inject (id) {
  73. chrome.tabs.executeScript(id, {
  74. code: [
  75. 'document.querySelector("pre").style.visibility = "hidden"',
  76. 'var theme = "' + state.theme + '"',
  77. 'var raw = ' + state.raw,
  78. 'var content = ' + JSON.stringify(state.content),
  79. 'var compiler = "' + state.compiler + '"'
  80. ].join(';'), runAt: 'document_start'})
  81. chrome.tabs.insertCSS(id, {file: 'css/content.css', runAt: 'document_start'})
  82. chrome.tabs.insertCSS(id, {file: 'vendor/prism.css', runAt: 'document_start'})
  83. chrome.tabs.executeScript(id, {file: 'vendor/mithril.min.js', runAt: 'document_start'})
  84. chrome.tabs.executeScript(id, {file: 'vendor/prism.js', runAt: 'document_start'})
  85. chrome.tabs.executeScript(id, {file: 'content/emoji.js', runAt: 'document_start'})
  86. chrome.tabs.executeScript(id, {file: 'content/content.js', runAt: 'document_start'})
  87. }
  88. chrome.tabs.onUpdated.addListener((id, info, tab) => {
  89. if (info.status === 'loading') {
  90. chrome.tabs.executeScript(id, {
  91. code: 'JSON.stringify({' +
  92. 'location: window.location,' +
  93. 'contentType: document.contentType,' +
  94. 'loaded: !!window.state' +
  95. '})',
  96. runAt: 'document_start'
  97. }, (res) => {
  98. if (chrome.runtime.lastError) {
  99. // Origin not allowed
  100. return
  101. }
  102. try {
  103. var win = JSON.parse(res)
  104. }
  105. catch (err) {
  106. // JSON parse error
  107. return
  108. }
  109. if (win.loaded) {
  110. return
  111. }
  112. if (state.header && /text\/(?:x-)?markdown/i.test(win.contentType)) {
  113. inject(id)
  114. }
  115. else {
  116. var path =
  117. state.origins[win.location.origin] ||
  118. state.origins['*://' + win.location.host] ||
  119. state.origins['*://*']
  120. if (new RegExp(path).test(win.location.href)) {
  121. inject(id)
  122. }
  123. }
  124. })
  125. }
  126. })
  127. chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
  128. if (req.message === 'markdown') {
  129. md[state.compiler].compile(req.markdown, sendResponse)
  130. }
  131. else if (req.message === 'settings') {
  132. sendResponse(Object.assign({}, state, {
  133. options: state[state.compiler],
  134. description: md[state.compiler].description,
  135. compilers: Object.keys(md)
  136. }))
  137. }
  138. else if (req.message === 'compiler.name') {
  139. set({compiler: req.compiler})
  140. sendResponse()
  141. notifyContent({message: 'reload'})
  142. }
  143. else if (req.message === 'compiler.options') {
  144. set({[req.compiler]: req.options})
  145. notifyContent({message: 'reload'})
  146. }
  147. else if (req.message === 'content') {
  148. set({content: req.content})
  149. notifyContent({message: 'reload'})
  150. }
  151. else if (req.message === 'defaults') {
  152. set(defaults)
  153. sendResponse()
  154. notifyContent({message: 'reload'})
  155. }
  156. else if (req.message === 'theme') {
  157. set({theme: req.theme})
  158. notifyContent({message: 'theme', theme: req.theme})
  159. }
  160. else if (req.message === 'raw') {
  161. set({raw: req.raw})
  162. notifyContent({message: 'raw', raw: req.raw})
  163. }
  164. else if (req.message === 'advanced') {
  165. chrome.management.getSelf((extension) => {
  166. chrome.tabs.create({url: extension.optionsUrl})
  167. })
  168. }
  169. else if (req.message === 'origins') {
  170. sendResponse({origins: state.origins, header: state.header})
  171. }
  172. else if (req.message === 'header') {
  173. set({header: req.header})
  174. }
  175. else if (req.message === 'add') {
  176. state.origins[req.origin] = match
  177. set({origins: state.origins})
  178. sendResponse()
  179. }
  180. else if (req.message === 'remove') {
  181. delete state.origins[req.origin]
  182. set({origins: state.origins})
  183. sendResponse()
  184. }
  185. else if (req.message === 'update') {
  186. state.origins[req.origin] = req.match
  187. set({origins: state.origins})
  188. }
  189. return true
  190. })
  191. function notifyContent (req, res) {
  192. chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
  193. chrome.tabs.sendMessage(tabs[0].id, req, res)
  194. })
  195. }