123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- var Origins = () => {
- var defaults = {
- // storage
- origins: {},
- match: '',
- // UI
- host: '',
- timeout: null,
- file: true,
- // chrome
- permissions: {},
- }
- var state = Object.assign({}, defaults)
- chrome.extension.isAllowedFileSchemeAccess((isAllowedAccess) => {
- state.file = /Firefox/.test(navigator.userAgent)
- ? true // ff: `Allow access to file URLs` option isn't available
- : isAllowedAccess
- m.redraw()
- })
- chrome.runtime.sendMessage({message: 'options.origins'}, (res) => {
- Object.assign(state, {file: state.file}, res)
- chrome.permissions.getAll(({origins}) => {
- state.permissions = origins.reduce((all, origin) =>
- (all[origin.replace(/(.*)\/\*$/, '$1')] = true, all), {})
- m.redraw()
- })
- })
- var events = {
- file: () => {
- chrome.tabs.create({url: `chrome://extensions/?id=${chrome.runtime.id}`})
- },
- host: (e) => {
- state.scheme = e.target.value.replace(/(.*):\/\/.*/i, '$1')
- state.domain = e.target.value.replace(/.*:\/\/([^/]+).*/i, '$1')
- state.host = e.target.value
- },
- add: (all) => () => {
- if (!all && !state.host && !['https', 'http', '*'].includes(state.scheme)) {
- return
- }
- var origin = all ? '*://*' : `${state.scheme}://${state.domain}`
- if (/Firefox/.test(navigator.userAgent) && /:\d{2,4}/.test(origin)) {
- origin = origin.replace(/(:\d{2,4})/, '')
- }
- chrome.permissions.request({origins: [`${origin}/*`]}, (granted) => {
- if (granted) {
- chrome.runtime.sendMessage({message: 'origin.add', origin})
- state.origins[origin] = {
- header: true,
- path: true,
- match: state.match,
- }
- state.host = ''
- state.permissions[origin] = true
- m.redraw()
- }
- })
- },
- remove: (origin) => () => {
- chrome.permissions.remove({origins: [`${origin}/*`]}, (removed) => {
- if (removed) {
- chrome.runtime.sendMessage({message: 'origin.remove', origin})
- delete state.origins[origin]
- delete state.permissions[origin]
- m.redraw()
- }
- })
- },
- refresh: (origin) => () => {
- chrome.permissions.request({origins: [`${origin}/*`]}, (granted) => {
- if (granted) {
- state.permissions[origin] = true
- m.redraw()
- }
- })
- },
- header: (origin) => () => {
- state.origins[origin].header = !state.origins[origin].header
- var {header, path, match} = state.origins[origin]
- chrome.runtime.sendMessage({
- message: 'origin.update',
- origin,
- options: {header, path, match},
- })
- },
- path: (origin) => () => {
- state.origins[origin].path = !state.origins[origin].path
- var {header, path, match} = state.origins[origin]
- chrome.runtime.sendMessage({
- message: 'origin.update',
- origin,
- options: {header, path, match},
- })
- },
- match: (origin) => (e) => {
- state.origins[origin].match = e.target.value
- clearTimeout(state.timeout)
- state.timeout = setTimeout(() => {
- var {header, path, match} = state.origins[origin]
- chrome.runtime.sendMessage({
- message: 'origin.update',
- origin,
- options: {header, path, match},
- })
- }, 750)
- },
- }
- var oncreate = {
- ripple: (vnode) => {
- mdc.ripple.MDCRipple.attachTo(vnode.dom)
- },
- textfield: (vnode) => {
- mdc.textfield.MDCTextField.attachTo(vnode.dom)
- }
- }
- var onupdate = {
- header: (origin) => (vnode) => {
- if (vnode.dom.classList.contains('is-checked') !== state.origins[origin].header) {
- vnode.dom.classList.toggle('is-checked')
- }
- },
- path: (origin) => (vnode) => {
- if (vnode.dom.classList.contains('is-checked') !== state.origins[origin].path) {
- vnode.dom.classList.toggle('is-checked')
- }
- }
- }
- var render = () =>
- m('.m-origins',
- // file access
- m('.row',
- m('.col-xxl-10.col-xl-10.col-lg-9.col-md-8.col-sm-12',
- m('h3', 'File Access'),
- ),
- m('.col-xxl-2.col-xl-2.col-lg-3.col-md-4.col-sm-12',
- // file access is disabled
- (!state.file || null) &&
- m('button.mdc-button mdc-button--raised m-button m-btn-file', {
- oncreate: oncreate.ripple,
- onclick: events.file
- },
- 'Allow Access'
- )
- ),
- ),
- ...Object.keys(state.origins)
- .filter((origin) => origin === 'file://' && state.file)
- .map(callout),
- // site access
- m('.row',
- m('.col-xxl-10.col-xl-10.col-lg-10.col-md-9.col-sm-8',
- m('h3', 'Site Access'),
- ),
- (!Object.keys(state.origins).includes('*://*') || null) &&
- m('.col-xxl-2.col-xl-2.col-lg-2.col-md-3.col-sm-4',
- m('button.mdc-button mdc-button--raised m-button m-btn-all', {
- oncreate: oncreate.ripple,
- onclick: events.add(true)
- },
- 'Allow All'
- ),
- ),
- ),
- // add origin
- m('.bs-callout m-box-add',
- m('.row',
- m('.col-xxl-11.col-xl-11.col-lg-10.col-md-10.col-sm-12',
- m('.mdc-text-field m-textfield', {
- oncreate: oncreate.textfield,
- },
- m('input.mdc-text-field__input', {
- type: 'text',
- value: state.host,
- onchange: events.host,
- placeholder: 'Copy/paste URL address here'
- }),
- m('.mdc-line-ripple')
- ),
- ),
- m('.col-xxl-1.col-xl-1.col-lg-2.col-md-2.col-sm-12',
- m('button.mdc-button mdc-button--raised m-button m-btn-add', {
- oncreate: oncreate.ripple,
- onclick: events.add()
- },
- 'Add'
- ),
- )
- )
- ),
- // allowed origins
- ...Object.keys(state.origins)
- .filter((origin) => origin !== 'file://')
- .sort((a, b) => a < b ? 1 : a > b ? -1 : 0)
- .map(callout)
- )
- var callout = (origin) =>
- m('.bs-callout', {class: !state.permissions[origin] ? 'm-box-refresh' : undefined},
- // origin
- m('.row',
- m('.col-xxl-8.col-xl-8.col-lg-8.col-md-7.col-sm-12 m-overflow', m('span.m-origin', origin)),
- m('.col-xxl-4.col-xl-4.col-lg-4.col-md-5.col-sm-12',
- // remove
- (origin !== 'file://' || null) &&
- m('button.mdc-button mdc-button--raised m-button m-btn-remove', {
- oncreate: oncreate.ripple,
- onclick: events.remove(origin)
- },
- 'Remove'
- ),
- // refresh
- (!state.permissions[origin] || null) &&
- m('button.mdc-button mdc-button--raised m-button m-btn-refresh', {
- oncreate: oncreate.ripple,
- onclick: events.refresh(origin)
- },
- 'Refresh'
- )
- )
- ),
- // header detection
- m('.row',
- m('.col-sm-12',
- m('.overflow',
- m('label.mdc-switch m-switch', {
- onupdate: onupdate.header,
- title: 'Toggle Header Detection'
- },
- m('input.mdc-switch__native-control', {
- type: 'checkbox',
- checked: state.origins[origin].header,
- onchange: events.header(origin)
- }),
- m('.mdc-switch__background', m('.mdc-switch__knob')),
- m('span.mdc-switch-label',
- 'Content Type Detection: ',
- m('span', 'text/markdown'),
- ', ',
- m('span', 'text/x-markdown'),
- ', ',
- m('span', 'text/plain'),
- )
- ),
- )
- )
- ),
- // path matching regexp
- m('.row',
- m('.col-sm-12',
- m('.overflow',
- m('label.mdc-switch m-switch', {
- onupdate: onupdate.path,
- title: 'Toggle Path Detection'
- },
- m('input.mdc-switch__native-control', {
- type: 'checkbox',
- checked: state.origins[origin].path,
- onchange: events.path(origin)
- }),
- m('.mdc-switch__background', m('.mdc-switch__knob')),
- m('span.mdc-switch-label',
- 'Path Matching RegExp: '
- )
- ),
- m('.mdc-text-field m-textfield', {
- oncreate: oncreate.textfield
- },
- m('input.mdc-text-field__input', {
- type: 'text',
- onkeyup: events.match(origin),
- value: state.origins[origin].match,
- }),
- m('.mdc-line-ripple')
- )
- )
- )
- )
- )
- return {state, render}
- }
|