index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. var Popup = () => {
  2. var state = {
  3. compiler: '',
  4. options: {},
  5. content: {},
  6. theme: '',
  7. themes: {},
  8. _themes: [
  9. 'github',
  10. 'github-dark',
  11. // 'air',
  12. 'almond',
  13. 'awsm',
  14. 'axist',
  15. 'bamboo',
  16. 'bullframe',
  17. 'holiday',
  18. 'kacit',
  19. 'latex',
  20. 'marx',
  21. 'mini',
  22. 'modest',
  23. 'new',
  24. 'no-class',
  25. 'pico',
  26. 'retro',
  27. 'sakura',
  28. 'sakura-vader',
  29. 'semantic',
  30. 'simple',
  31. // 'splendor',
  32. 'style-sans',
  33. 'style-serif',
  34. 'stylize',
  35. 'superstylin',
  36. 'tacit',
  37. 'vanilla',
  38. 'water',
  39. 'water-dark',
  40. 'writ',
  41. ],
  42. _width: [
  43. 'auto',
  44. 'full',
  45. 'wide',
  46. 'large',
  47. 'medium',
  48. 'small',
  49. 'tiny',
  50. ],
  51. raw: false,
  52. tab: '',
  53. tabs: ['theme', 'compiler', 'content'],
  54. compilers: [],
  55. description: {
  56. themes: {},
  57. compiler: {},
  58. content: {
  59. autoreload: 'Auto reload on file change',
  60. emoji: 'Convert emoji :shortnames: into EmojiOne images',
  61. toc: 'Generate Table of Contents',
  62. mathjax: 'Render MathJax formulas',
  63. mermaid: 'Mermaid diagrams',
  64. syntax: 'Syntax highlighting for fenced code blocks',
  65. }
  66. },
  67. settings: {}
  68. }
  69. var events = {
  70. tab: (e) => {
  71. state.tab = e.target.hash.replace('#tab-', '')
  72. localStorage.setItem('tab', state.tab)
  73. return false
  74. },
  75. compiler: {
  76. name: (e) => {
  77. state.compiler = state.compilers[e.target.selectedIndex]
  78. chrome.runtime.sendMessage({
  79. message: 'popup.compiler.name',
  80. compiler: state.compiler,
  81. }, () => {
  82. chrome.runtime.sendMessage({message: 'popup'}, init)
  83. })
  84. },
  85. options: (e) => {
  86. state.options[e.target.name] = !state.options[e.target.name]
  87. chrome.runtime.sendMessage({
  88. message: 'popup.compiler.options',
  89. compiler: state.compiler,
  90. options: state.options,
  91. })
  92. }
  93. },
  94. content: (e) => {
  95. state.content[e.target.name] = !state.content[e.target.name]
  96. chrome.runtime.sendMessage({
  97. message: 'popup.content',
  98. content: state.content,
  99. })
  100. },
  101. themes: (e) => {
  102. state.themes.width = state._width[e.target.selectedIndex]
  103. chrome.runtime.sendMessage({
  104. message: 'popup.themes',
  105. themes: state.themes,
  106. })
  107. },
  108. theme: (e) => {
  109. state.theme = state._themes[e.target.selectedIndex]
  110. chrome.runtime.sendMessage({
  111. message: 'popup.theme',
  112. theme: state.theme
  113. })
  114. },
  115. raw: () => {
  116. state.raw = !state.raw
  117. chrome.runtime.sendMessage({
  118. message: 'popup.raw',
  119. raw: state.raw
  120. })
  121. },
  122. defaults: () => {
  123. chrome.runtime.sendMessage({
  124. message: 'popup.defaults'
  125. }, () => {
  126. chrome.runtime.sendMessage({message: 'popup'}, init)
  127. localStorage.removeItem('tab')
  128. state._tabs.activeTabIndex = 0
  129. })
  130. },
  131. advanced: () => {
  132. chrome.runtime.sendMessage({message: 'popup.advanced'})
  133. }
  134. }
  135. var init = (res) => {
  136. state.compiler = res.compiler
  137. state.options = res.options
  138. state.content = res.content
  139. state.theme = res.theme
  140. state.themes = res.themes
  141. state.raw = res.raw
  142. state.tab = localStorage.getItem('tab') || 'theme'
  143. state.compilers = res.compilers
  144. state.description.compiler = res.description
  145. state.settings = res.settings
  146. document.querySelector('body').classList.add(state.settings.theme)
  147. m.redraw()
  148. }
  149. chrome.runtime.sendMessage({message: 'popup'}, init)
  150. var oncreate = {
  151. ripple: (vnode) => {
  152. mdc.ripple.MDCRipple.attachTo(vnode.dom)
  153. },
  154. tabs: (vnode) => {
  155. state._tabs = mdc.tabs.MDCTabBar.attachTo(vnode.dom)
  156. setTimeout(() => {
  157. state._tabs.activeTabIndex = state.tabs.indexOf(state.tab)
  158. }, 250)
  159. }
  160. }
  161. var onupdate = (tab, key) => (vnode) => {
  162. var value = tab === 'compiler' ? state.options[key]
  163. : tab === 'content' ? state.content[key]
  164. : null
  165. if (vnode.dom.classList.contains('is-checked') !== value) {
  166. vnode.dom.classList.toggle('is-checked')
  167. }
  168. }
  169. var render = () =>
  170. m('#popup',
  171. // raw
  172. m('button.mdc-button mdc-button--raised m-button', {
  173. oncreate: oncreate.ripple,
  174. onclick: events.raw
  175. },
  176. (state.raw ? 'Html' : 'Markdown')
  177. ),
  178. // defaults
  179. m('button.mdc-button mdc-button--raised m-button', {
  180. oncreate: oncreate.ripple,
  181. onclick: events.defaults
  182. },
  183. 'Defaults'
  184. ),
  185. // tabs
  186. m('nav.mdc-tab-bar m-tabs', {
  187. oncreate: oncreate.tabs,
  188. onclick: events.tab
  189. },
  190. state.tabs.map((tab) =>
  191. m('a.mdc-tab', {
  192. href: '#tab-' + tab,
  193. },
  194. tab
  195. )),
  196. m('span.mdc-tab-bar__indicator')
  197. ),
  198. m('.m-panels',
  199. // theme
  200. m('.m-panel', {
  201. class: state.tab === 'theme' ? 'is-active' : ''
  202. },
  203. m('select.mdc-elevation--z2 m-select', {
  204. onchange: events.theme
  205. },
  206. state._themes.map((theme) =>
  207. m('option', {selected: state.theme === theme}, theme)
  208. )
  209. ),
  210. m('select.mdc-elevation--z2 m-select', {
  211. onchange: events.themes
  212. },
  213. state._width.map((width) =>
  214. m('option', {
  215. selected: state.themes.width === width,
  216. }, width)
  217. )
  218. ),
  219. ),
  220. // compiler
  221. m('.m-panel', {
  222. class: state.tab === 'compiler' ? 'is-active' : ''
  223. },
  224. m('select.mdc-elevation--z2 m-select', {
  225. onchange: events.compiler.name
  226. },
  227. state.compilers.map((name) =>
  228. m('option', {selected: state.compiler === name}, name)
  229. )
  230. ),
  231. m('.scroll', {
  232. class: Object.keys(state.options)
  233. .filter((key) => typeof state.options[key] === 'boolean')
  234. .length > 8
  235. ? 'max' : ''
  236. },
  237. Object.keys(state.options)
  238. .filter((key) => typeof state.options[key] === 'boolean')
  239. .map((key) =>
  240. m('label.mdc-switch m-switch', {
  241. onupdate: onupdate('compiler', key),
  242. title: state.description.compiler[key]
  243. },
  244. m('input.mdc-switch__native-control', {
  245. type: 'checkbox',
  246. name: key,
  247. checked: state.options[key],
  248. onchange: events.compiler.options
  249. }),
  250. m('.mdc-switch__background', m('.mdc-switch__knob')),
  251. m('span.mdc-switch-label', key)
  252. )
  253. )
  254. )
  255. ),
  256. // content
  257. m('.m-panel', {
  258. class: state.tab === 'content' ? 'is-active' : ''
  259. },
  260. m('.scroll', Object.keys(state.content).map((key) =>
  261. m('label.mdc-switch m-switch', {
  262. onupdate: onupdate('content', key),
  263. title: state.description.content[key]
  264. },
  265. m('input.mdc-switch__native-control', {
  266. type: 'checkbox',
  267. name: key,
  268. checked: state.content[key],
  269. onchange: events.content
  270. }),
  271. m('.mdc-switch__background', m('.mdc-switch__knob')),
  272. m('span.mdc-switch-label', key)
  273. ))
  274. )
  275. )
  276. ),
  277. // advanced options
  278. m('button.mdc-button mdc-button--raised m-button', {
  279. oncreate: oncreate.ripple,
  280. onclick: events.advanced
  281. },
  282. 'Advanced Options'
  283. )
  284. )
  285. var options = () =>
  286. m('.row m-settings hidden',
  287. m('.col-xxl-4.col-xl-4.col-lg-6.col-md-6.col-sm-12',
  288. m('h3', 'Theme'),
  289. m('.bs-callout m-theme',
  290. m('.row',
  291. m('.col-xxl-6.col-xl-6.col-lg-6.col-md-6.col-sm-12',
  292. m('span.m-label',
  293. 'Content Theme'
  294. )
  295. ),
  296. m('.col-xxl-6.col-xl-6.col-lg-6.col-md-6.col-sm-12',
  297. m('select.mdc-elevation--z2 m-select', {
  298. onchange: events.theme
  299. },
  300. state._themes.map((theme) =>
  301. m('option', {selected: state.theme === theme}, theme)
  302. )
  303. )
  304. ),
  305. ),
  306. m('.row',
  307. m('.col-xxl-6.col-xl-6.col-lg-6.col-md-6.col-sm-12',
  308. m('span.m-label',
  309. 'Content Width'
  310. )
  311. ),
  312. m('.col-xxl-6.col-xl-6.col-lg-6.col-md-6.col-sm-12',
  313. m('select.mdc-elevation--z2 m-select', {
  314. onchange: events.themes
  315. },
  316. state._width.map((width) =>
  317. m('option', {
  318. selected: state.themes.width === width,
  319. }, width)
  320. )
  321. )
  322. ),
  323. ),
  324. settings.render()
  325. ),
  326. ),
  327. m('.col-xxl-4.col-xl-4.col-lg-6.col-md-6.col-sm-12',
  328. m('h3', 'Compiler'),
  329. m('.bs-callout m-compiler',
  330. m('select.mdc-elevation--z2 m-select', {
  331. onchange: events.compiler.name
  332. },
  333. state.compilers.map((name) =>
  334. m('option', {selected: state.compiler === name}, name)
  335. )
  336. ),
  337. m('.scroll', {
  338. class: Object.keys(state.options)
  339. .filter((key) => typeof state.options[key] === 'boolean')
  340. .length > 8
  341. ? 'max' : ''
  342. },
  343. Object.keys(state.options)
  344. .filter((key) => typeof state.options[key] === 'boolean')
  345. .map((key) =>
  346. m('label.mdc-switch m-switch', {
  347. onupdate: onupdate('compiler', key),
  348. title: state.description.compiler[key]
  349. },
  350. m('input.mdc-switch__native-control', {
  351. type: 'checkbox',
  352. name: key,
  353. checked: state.options[key],
  354. onchange: events.compiler.options
  355. }),
  356. m('.mdc-switch__background', m('.mdc-switch__knob')),
  357. m('span.mdc-switch-label', key)
  358. )
  359. )
  360. )
  361. ),
  362. ),
  363. m('.col-xxl-4.col-xl-4.col-lg-6.col-md-6.col-sm-12',
  364. m('h3', 'Content'),
  365. m('.bs-callout m-content',
  366. m('.scroll', Object.keys(state.content).map((key) =>
  367. m('label.mdc-switch m-switch', {
  368. onupdate: onupdate('content', key),
  369. title: state.description.content[key]
  370. },
  371. m('input.mdc-switch__native-control', {
  372. type: 'checkbox',
  373. name: key,
  374. checked: state.content[key],
  375. onchange: events.content
  376. }),
  377. m('.mdc-switch__background', m('.mdc-switch__knob')),
  378. m('span.mdc-switch-label', key)
  379. ))
  380. )
  381. ),
  382. ),
  383. )
  384. return {state, render, options}
  385. }
  386. if (document.querySelector('.is-popup')) {
  387. var popup = Popup()
  388. m.mount(document.querySelector('body'), {
  389. view: (vnode) => popup.render()
  390. })
  391. }
  392. else {
  393. var settings = Settings()
  394. }