options.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. var defaults = {
  2. // storage
  3. origins: {},
  4. header: false,
  5. // static
  6. protocols: ['https', 'http', '*'],
  7. // UI
  8. protocol: 'https',
  9. origin: '',
  10. timeout: null,
  11. file: true,
  12. }
  13. var state = Object.assign({}, defaults)
  14. var events = {
  15. file: () => {
  16. chrome.tabs.create({url: 'chrome://extensions/?id=' + chrome.runtime.id})
  17. },
  18. header: (e) => {
  19. state.header = !state.header
  20. chrome.runtime.sendMessage({
  21. message: 'options.header',
  22. header: state.header,
  23. })
  24. },
  25. origin: {
  26. protocol: (e) => {
  27. state.protocol = state.protocols[e.target.selectedIndex]
  28. },
  29. name: (e) => {
  30. state.origin = e.target.value
  31. },
  32. add: () => {
  33. var domain = state.origin.replace(/.*:\/\/([^/]+).*/i, '$1')
  34. if (!domain) {
  35. return
  36. }
  37. var origin = state.protocol + '://' + domain
  38. chrome.permissions.request({origins: [origin + '/*']}, (granted) => {
  39. if (granted) {
  40. chrome.runtime.sendMessage({message: 'origin.add', origin}, init)
  41. }
  42. })
  43. },
  44. all: () => {
  45. var origin = '*://*'
  46. chrome.permissions.request({origins: [origin + '/*']}, (granted) => {
  47. if (granted) {
  48. chrome.runtime.sendMessage({message: 'origin.add', origin}, init)
  49. }
  50. })
  51. },
  52. remove: (origin) => () => {
  53. chrome.permissions.remove({origins: [origin + '/*']}, (removed) => {
  54. if (removed) {
  55. chrome.runtime.sendMessage({message: 'origin.remove', origin}, init)
  56. }
  57. })
  58. },
  59. update: (origin) => (e) => {
  60. state.origins[origin] = e.target.value
  61. clearTimeout(state.timeout)
  62. state.timeout = setTimeout(() => {
  63. chrome.runtime.sendMessage({
  64. message: 'origin.update', origin, match: e.target.value
  65. })
  66. }, 750)
  67. },
  68. refresh: (origin) => () => {
  69. chrome.permissions.request({origins: [origin + '/*']})
  70. },
  71. },
  72. }
  73. chrome.extension.isAllowedFileSchemeAccess((isAllowedAccess) => {
  74. state.file = /Firefox/.test(navigator.userAgent)
  75. ? true // Allow access to file URLs option isn't working on FF
  76. : isAllowedAccess
  77. m.redraw()
  78. })
  79. var init = () => {
  80. chrome.runtime.sendMessage({message: 'options'}, (res) => {
  81. state = Object.assign({}, defaults, {file: state.file}, res)
  82. m.redraw()
  83. })
  84. }
  85. init()
  86. var oncreate = {
  87. ripple: (vnode) => {
  88. mdc.ripple.MDCRipple.attachTo(vnode.dom)
  89. }
  90. }
  91. var onupdate = {
  92. switch: (vnode) => {
  93. if (vnode.dom.classList.contains('is-checked') !== state.header) {
  94. vnode.dom.classList.toggle('is-checked')
  95. }
  96. }
  97. }
  98. m.mount(document.querySelector('main'), {
  99. view: () =>
  100. m('#options',
  101. // file access is disabled
  102. (!state.file || null) &&
  103. m('.bs-callout m-file',
  104. m('h4.mdc-typography--headline', 'Access to file:// URLs is Disabled'),
  105. m('img.mdc-elevation--z2', {src: '/images/file-urls.png'}),
  106. m('button.mdc-button mdc-button--raised m-button', {
  107. oncreate: oncreate.ripple,
  108. onclick: events.file
  109. },
  110. 'Enable Access to file:// URLs'
  111. )
  112. ),
  113. // allowed origins
  114. m('.bs-callout m-origins',
  115. m('h4.mdc-typography--headline', 'Allowed Origins'),
  116. // add origin
  117. m('select.mdc-elevation--z2 m-select', {
  118. onchange: events.origin.protocol
  119. },
  120. state.protocols.map((protocol) =>
  121. m('option', {
  122. value: protocol,
  123. selected: protocol === state.protocol
  124. },
  125. protocol + '://'
  126. )
  127. )),
  128. m('.mdc-textfield m-textfield',
  129. m('input.mdc-textfield__input', {
  130. type: 'text',
  131. value: state.origin,
  132. onchange: events.origin.name,
  133. placeholder: 'raw.githubusercontent.com'
  134. })
  135. ),
  136. m('button.mdc-button mdc-button--raised m-button', {
  137. oncreate: oncreate.ripple,
  138. onclick: events.origin.add
  139. },
  140. 'Add'
  141. ),
  142. m('button.mdc-button mdc-button--raised m-button', {
  143. oncreate: oncreate.ripple,
  144. onclick: events.origin.all
  145. },
  146. 'Allow All'
  147. ),
  148. // header detection
  149. (!/Firefox/.test(navigator.userAgent) || null) &&
  150. m('label.mdc-switch m-switch', {
  151. onupdate: onupdate.switch,
  152. title: 'Toggle header detection'
  153. },
  154. m('input.mdc-switch__native-control', {
  155. type: 'checkbox',
  156. checked: state.header,
  157. onchange: events.header
  158. }),
  159. m('.mdc-switch__background', m('.mdc-switch__knob')),
  160. m('span.mdc-switch-label',
  161. 'Detect ',
  162. m('code', 'text/markdown'),
  163. ' and ',
  164. m('code', 'text/x-markdown'),
  165. ' content type'
  166. )
  167. ),
  168. m('ul.mdc-elevation--z2 m-list',
  169. Object.keys(state.origins).sort().map((origin) =>
  170. m('li',
  171. m('span', origin.replace(/^(\*|file|http(s)?).*/, '$1')),
  172. m('span', origin.replace(/^(\*|file|http(s)?):\/\//, '')),
  173. m('.mdc-textfield m-textfield', {
  174. oncreate: oncreate.textfield
  175. },
  176. m('input.mdc-textfield__input', {
  177. type: 'text',
  178. onkeyup: events.origin.update(origin),
  179. value: state.origins[origin],
  180. })
  181. ),
  182. (origin !== 'file://' || null) &&
  183. m('span',
  184. m('button.mdc-button', {
  185. oncreate: oncreate.ripple,
  186. onclick: events.origin.refresh(origin),
  187. title: 'Refresh'
  188. },
  189. m('i.material-icons icon-refresh')
  190. ),
  191. m('button.mdc-button', {
  192. oncreate: oncreate.ripple,
  193. onclick: events.origin.remove(origin),
  194. title: 'Remove'
  195. },
  196. m('i.material-icons icon-remove')
  197. )
  198. )
  199. )
  200. )
  201. )
  202. ),
  203. )
  204. })