index.js 11 KB

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