diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-05-02 17:25:56 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-02 17:25:56 +0900 |
commit | 5df0537bcf65a341e79852b1b30379c73318529c (patch) | |
tree | aee5efe52412855f620cb514a13a2c14373f27b7 /src/settings | |
parent | 685f2b7b69218b06b5bb676069e35f79c5048c9b (diff) | |
parent | 75abd90ecb8201ad845b266f96220d8adfe19b2d (diff) |
Merge pull request #749 from ueokande/qa-0.28
QA 0.28
Diffstat (limited to 'src/settings')
-rw-r--r-- | src/settings/actions/index.ts | 24 | ||||
-rw-r--r-- | src/settings/actions/setting.ts | 39 | ||||
-rw-r--r-- | src/settings/components/form/BlacklistForm.tsx | 71 | ||||
-rw-r--r-- | src/settings/components/form/KeymapsForm.tsx | 54 | ||||
-rw-r--r-- | src/settings/components/form/PartialBlacklistForm.tsx | 100 | ||||
-rw-r--r-- | src/settings/components/form/PropertiesForm.tsx | 66 | ||||
-rw-r--r-- | src/settings/components/form/SearchForm.tsx | 112 | ||||
-rw-r--r-- | src/settings/components/index.tsx | 222 | ||||
-rw-r--r-- | src/settings/components/ui/AddButton.tsx | 15 | ||||
-rw-r--r-- | src/settings/components/ui/DeleteButton.tsx | 15 | ||||
-rw-r--r-- | src/settings/components/ui/Input.tsx | 89 | ||||
-rw-r--r-- | src/settings/index.tsx | 23 | ||||
-rw-r--r-- | src/settings/keymaps.ts | 137 | ||||
-rw-r--r-- | src/settings/reducers/setting.ts | 64 | ||||
-rw-r--r-- | src/settings/storage.ts | 16 |
15 files changed, 579 insertions, 468 deletions
diff --git a/src/settings/actions/index.ts b/src/settings/actions/index.ts index dfa41c4..6b06ef8 100644 --- a/src/settings/actions/index.ts +++ b/src/settings/actions/index.ts @@ -1,12 +1,14 @@ import { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; // Settings -export const SETTING_SET_SETTINGS = 'setting.set.settings'; -export const SETTING_SHOW_ERROR = 'setting.show.error'; -export const SETTING_SWITCH_TO_FORM = 'setting.switch.to.form'; -export const SETTING_SWITCH_TO_JSON = 'setting.switch.to.json'; +export const SETTING_SET_SETTINGS = "setting.set.settings"; +export const SETTING_SHOW_ERROR = "setting.show.error"; +export const SETTING_SWITCH_TO_FORM = "setting.switch.to.form"; +export const SETTING_SWITCH_TO_JSON = "setting.switch.to.json"; interface SettingSetSettingsAcion { type: typeof SETTING_SET_SETTINGS; @@ -23,14 +25,16 @@ interface SettingShowErrorAction { interface SettingSwitchToFormAction { type: typeof SETTING_SWITCH_TO_FORM; - form: FormSettings, + form: FormSettings; } interface SettingSwitchToJsonAction { type: typeof SETTING_SWITCH_TO_JSON; - json: JSONTextSettings, + json: JSONTextSettings; } export type SettingAction = - SettingSetSettingsAcion | SettingShowErrorAction | - SettingSwitchToFormAction | SettingSwitchToJsonAction; + | SettingSetSettingsAcion + | SettingShowErrorAction + | SettingSwitchToFormAction + | SettingSwitchToJsonAction; diff --git a/src/settings/actions/setting.ts b/src/settings/actions/setting.ts index 93ca5f8..e880ae4 100644 --- a/src/settings/actions/setting.ts +++ b/src/settings/actions/setting.ts @@ -1,15 +1,17 @@ -import * as actions from './index'; -import * as storages from '../storage'; +import * as actions from "./index"; +import * as storages from "../storage"; import SettingData, { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; -const load = async(): Promise<actions.SettingAction> => { +const load = async (): Promise<actions.SettingAction> => { const data = await storages.load(); return set(data); }; -const save = async(data: SettingData): Promise<actions.SettingAction> => { +const save = async (data: SettingData): Promise<actions.SettingAction> => { try { if (data.getSource() === SettingSource.JSON) { // toSettings exercise validation @@ -26,7 +28,6 @@ const save = async(data: SettingData): Promise<actions.SettingAction> => { return set(data); }; - const switchToForm = (json: JSONTextSettings): actions.SettingAction => { try { // toSettings exercise validation @@ -55,18 +56,18 @@ const switchToJson = (form: FormSettings): actions.SettingAction => { const set = (data: SettingData): actions.SettingAction => { const source = data.getSource(); switch (source) { - case SettingSource.JSON: - return { - type: actions.SETTING_SET_SETTINGS, - source: source, - json: data.getJSON(), - }; - case SettingSource.Form: - return { - type: actions.SETTING_SET_SETTINGS, - source: source, - form: data.getForm(), - }; + case SettingSource.JSON: + return { + type: actions.SETTING_SET_SETTINGS, + source: source, + json: data.getJSON(), + }; + case SettingSource.Form: + return { + type: actions.SETTING_SET_SETTINGS, + source: source, + form: data.getForm(), + }; } throw new Error(`unknown source: ${source}`); }; diff --git a/src/settings/components/form/BlacklistForm.tsx b/src/settings/components/form/BlacklistForm.tsx index 51c32f4..859cb9f 100644 --- a/src/settings/components/form/BlacklistForm.tsx +++ b/src/settings/components/form/BlacklistForm.tsx @@ -1,8 +1,8 @@ -import './BlacklistForm.scss'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import React from 'react'; -import Blacklist, { BlacklistItem } from '../../../shared/settings/Blacklist'; +import "./BlacklistForm.scss"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import React from "react"; +import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; interface Props { value: Blacklist; @@ -18,45 +18,56 @@ class BlacklistForm extends React.Component<Props> { }; render() { - return <div className='form-blacklist-form'> - { - this.props.value.items.map((item, index) => { + return ( + <div className="form-blacklist-form"> + {this.props.value.items.map((item, index) => { if (item.partial) { return null; } - return <div key={index} className='form-blacklist-form-row'> - <input data-index={index} type='text' name='url' - className='column-url' value={item.pattern} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + return ( + <div key={index} className="form-blacklist-form-row"> + <input + data-index={index} + type="text" + name="url" + className="column-url" + value={item.pattern} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + </div> + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } bindValue(e: any) { const name = e.target.name; - const index = e.target.getAttribute('data-index'); + const index = e.target.getAttribute("data-index"); const items = this.props.value.items; - if (name === 'url') { + if (name === "url") { items[index] = new BlacklistItem(e.target.value, false, []); - } else if (name === 'add') { - items.push(new BlacklistItem('', false, [])); - } else if (name === 'delete') { + } else if (name === "add") { + items.push(new BlacklistItem("", false, [])); + } else if (name === "delete") { items.splice(index, 1); } this.props.onChange(new Blacklist(items)); - if (name === 'delete') { + if (name === "delete") { this.props.onBlur(); } } diff --git a/src/settings/components/form/KeymapsForm.tsx b/src/settings/components/form/KeymapsForm.tsx index dc74de3..b9af0df 100644 --- a/src/settings/components/form/KeymapsForm.tsx +++ b/src/settings/components/form/KeymapsForm.tsx @@ -1,8 +1,8 @@ -import './KeymapsForm.scss'; -import React from 'react'; -import Input from '../ui/Input'; -import keymaps from '../../keymaps'; -import { FormKeymaps } from '../../../shared/SettingData'; +import "./KeymapsForm.scss"; +import React from "react"; +import Input from "../ui/Input"; +import keymaps from "../../keymaps"; +import { FormKeymaps } from "../../../shared/SettingData"; interface Props { value: FormKeymaps; @@ -19,25 +19,31 @@ class KeymapsForm extends React.Component<Props> { render() { const values = this.props.value.toJSON(); - return <div className='form-keymaps-form'> - { - keymaps.fields.map((group, index) => { - return <div key={index} className='form-keymaps-form-field-group'> - { - group.map(([name, label]) => { - const value = values[name] || ''; - return <Input - type='text' id={name} name={name} key={name} - label={label} value={value} - onValueChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - />; - }) - } - </div>; - }) - } - </div>; + return ( + <div className="form-keymaps-form"> + {keymaps.fields.map((group, index) => { + return ( + <div key={index} className="form-keymaps-form-field-group"> + {group.map(([name, label]) => { + const value = values[name] || ""; + return ( + <Input + type="text" + id={name} + name={name} + key={name} + label={label} + value={value} + onValueChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + ); + })} + </div> + ); + })} + </div> + ); } bindValue(name: string, value: string) { diff --git a/src/settings/components/form/PartialBlacklistForm.tsx b/src/settings/components/form/PartialBlacklistForm.tsx index 1807e28..95beee8 100644 --- a/src/settings/components/form/PartialBlacklistForm.tsx +++ b/src/settings/components/form/PartialBlacklistForm.tsx @@ -1,8 +1,8 @@ -import './PartialBlacklistForm.scss'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import React from 'react'; -import Blacklist, { BlacklistItem } from '../../../shared/settings/Blacklist'; +import "./PartialBlacklistForm.scss"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import React from "react"; +import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; interface Props { value: Blacklist; @@ -18,59 +18,77 @@ class PartialBlacklistForm extends React.Component<Props> { }; render() { - return <div className='form-partial-blacklist-form'> - <div className='form-partial-blacklist-form-header'> - <div className='column-url'>URL</div> - <div className='column-keys'>Keys</div> - </div> - { - this.props.value.items.map((item, index) => { + return ( + <div className="form-partial-blacklist-form"> + <div className="form-partial-blacklist-form-header"> + <div className="column-url">URL</div> + <div className="column-keys">Keys</div> + </div> + {this.props.value.items.map((item, index) => { if (!item.partial) { return null; } - return <div key={index} className='form-partial-blacklist-form-row'> - <input data-index={index} type='text' name='url' - className='column-url' value={item.pattern} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <input data-index={index} type='text' name='keys' - className='column-keys' value={item.keys.join(',')} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + return ( + <div key={index} className="form-partial-blacklist-form-row"> + <input + data-index={index} + type="text" + name="url" + className="column-url" + value={item.pattern} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <input + data-index={index} + type="text" + name="keys" + className="column-keys" + value={item.keys.join(",")} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + </div> + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } bindValue(e: any) { const name = e.target.name; - const index = e.target.getAttribute('data-index'); + const index = e.target.getAttribute("data-index"); const items = this.props.value.items; - if (name === 'url') { + if (name === "url") { const current = items[index]; items[index] = new BlacklistItem(e.target.value, true, current.keys); - } else if (name === 'keys') { + } else if (name === "keys") { const current = items[index]; items[index] = new BlacklistItem( - current.pattern, true, e.target.value.split(',')); - } else if (name === 'add') { - items.push(new BlacklistItem('', true, [])); - } else if (name === 'delete') { + current.pattern, + true, + e.target.value.split(",") + ); + } else if (name === "add") { + items.push(new BlacklistItem("", true, [])); + } else if (name === "delete") { items.splice(index, 1); } this.props.onChange(new Blacklist(items)); - if (name === 'delete') { + if (name === "delete") { this.props.onBlur(); } } diff --git a/src/settings/components/form/PropertiesForm.tsx b/src/settings/components/form/PropertiesForm.tsx index e648971..aebd9b1 100644 --- a/src/settings/components/form/PropertiesForm.tsx +++ b/src/settings/components/form/PropertiesForm.tsx @@ -1,9 +1,9 @@ -import './PropertiesForm.scss'; -import React from 'react'; +import "./PropertiesForm.scss"; +import React from "react"; interface Props { - types: {[key: string]: string}; - value: {[key: string]: any}; + types: { [key: string]: string }; + value: { [key: string]: any }; onChange: (value: any) => void; onBlur: () => void; } @@ -20,18 +20,18 @@ class PropertiesForm extends React.Component<Props> { const types = this.props.types; const values = this.props.value; - return <div className='form-properties-form'> - { - Object.keys(types).map((name) => { + return ( + <div className="form-properties-form"> + {Object.keys(types).map((name) => { const type = types[name]; - let inputType = ''; + let inputType = ""; let onChange = this.bindValue.bind(this); - if (type === 'string') { - inputType = 'text'; - } else if (type === 'number') { - inputType = 'number'; - } else if (type === 'boolean') { - inputType = 'checkbox'; + if (type === "string") { + inputType = "text"; + } else if (type === "number") { + inputType = "number"; + } else if (type === "boolean") { + inputType = "checkbox"; // Settings are saved onBlur, but checkbox does not fire it onChange = (e) => { @@ -41,29 +41,33 @@ class PropertiesForm extends React.Component<Props> { } else { return null; } - return <div key={name} className='form-properties-form-row'> - <label> - <span className='column-name'>{name}</span> - <input type={inputType} name={name} - className='column-input' - value={values[name] ? values[name] : ''} - onChange={onChange} - onBlur={this.props.onBlur} - checked={values[name]} - /> - </label> - </div>; - }) - } - </div>; + return ( + <div key={name} className="form-properties-form-row"> + <label> + <span className="column-name">{name}</span> + <input + type={inputType} + name={name} + className="column-input" + value={values[name] ? values[name] : ""} + onChange={onChange} + onBlur={this.props.onBlur} + checked={values[name]} + /> + </label> + </div> + ); + })} + </div> + ); } bindValue(e: React.ChangeEvent<HTMLInputElement>) { const name = e.target.name; const next = { ...this.props.value }; - if (e.target.type.toLowerCase() === 'checkbox') { + if (e.target.type.toLowerCase() === "checkbox") { next[name] = e.target.checked; - } else if (e.target.type.toLowerCase() === 'number') { + } else if (e.target.type.toLowerCase() === "number") { next[name] = Number(e.target.value); } else { next[name] = e.target.value; diff --git a/src/settings/components/form/SearchForm.tsx b/src/settings/components/form/SearchForm.tsx index 5dc786b..a4d923d 100644 --- a/src/settings/components/form/SearchForm.tsx +++ b/src/settings/components/form/SearchForm.tsx @@ -1,8 +1,8 @@ -import './SearchForm.scss'; -import React from 'react'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import { FormSearch } from '../../../shared/SettingData'; +import "./SearchForm.scss"; +import React from "react"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import { FormSearch } from "../../../shared/SettingData"; interface Props { value: FormSearch; @@ -12,68 +12,88 @@ interface Props { class SearchForm extends React.Component<Props> { public static defaultProps: Props = { - value: FormSearch.fromJSON({ default: '', engines: []}), + value: FormSearch.fromJSON({ default: "", engines: [] }), onChange: () => {}, onBlur: () => {}, }; render() { const value = this.props.value.toJSON(); - return <div className='form-search-form'> - <div className='form-search-form-header'> - <div className='column-name'>Name</div> - <div className='column-url'>URL</div> - <div className='column-option'>Default</div> - </div> - { - value.engines.map((engine, index) => { - return <div key={index} className='form-search-form-row'> - <input data-index={index} type='text' name='name' - className='column-name' value={engine[0]} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <input data-index={index} type='text' name='url' - placeholder='http://example.com/?q={}' - className='column-url' value={engine[1]} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <div className='column-option'> - <input data-index={index} type='radio' name='default' - checked={value.default === engine[0]} - onChange={this.bindValue.bind(this)} /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} /> + return ( + <div className="form-search-form"> + <div className="form-search-form-header"> + <div className="column-name">Name</div> + <div className="column-url">URL</div> + <div className="column-option">Default</div> + </div> + {value.engines.map((engine, index) => { + return ( + <div key={index} className="form-search-form-row"> + <input + data-index={index} + type="text" + name="name" + className="column-name" + value={engine[0]} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <input + data-index={index} + type="text" + name="url" + placeholder="http://example.com/?q={}" + className="column-url" + value={engine[1]} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <div className="column-option"> + <input + data-index={index} + type="radio" + name="default" + checked={value.default === engine[0]} + onChange={this.bindValue.bind(this)} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + /> + </div> </div> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } // eslint-disable-next-line max-statements bindValue(e: any) { const value = this.props.value.toJSON(); const name = e.target.name; - const index = Number(e.target.getAttribute('data-index')); + const index = Number(e.target.getAttribute("data-index")); const next: typeof value = { default: value.default, engines: value.engines.slice(), }; - if (name === 'name') { + if (name === "name") { next.engines[index][0] = e.target.value; next.default = value.engines[index][0]; - } else if (name === 'url') { + } else if (name === "url") { next.engines[index][1] = e.target.value; - } else if (name === 'default') { + } else if (name === "default") { next.default = value.engines[index][0]; - } else if (name === 'add') { - next.engines.push(['', '']); - } else if (name === 'delete' && value.engines.length > 1) { + } else if (name === "add") { + next.engines.push(["", ""]); + } else if (name === "delete" && value.engines.length > 1) { next.engines.splice(index, 1); if (value.engines[index][0] === value.default) { const nextIndex = Math.min(index, next.engines.length - 1); @@ -82,7 +102,7 @@ class SearchForm extends React.Component<Props> { } this.props.onChange(FormSearch.fromJSON(next)); - if (name === 'delete' || name === 'default') { + if (name === "delete" || name === "default") { this.props.onBlur(); } } diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index f4f0326..5793a8f 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -1,32 +1,36 @@ -import './site.scss'; -import React from 'react'; -import { connect } from 'react-redux'; -import Input from './ui/Input'; -import SearchForm from './form/SearchForm'; -import KeymapsForm from './form/KeymapsForm'; -import BlacklistForm from './form/BlacklistForm'; -import PropertiesForm from './form/PropertiesForm'; -import PartialBlacklistForm from './form/PartialBlacklistForm'; -import * as settingActions from '../../settings/actions/setting'; +import "./site.scss"; +import React from "react"; +import { connect } from "react-redux"; +import Input from "./ui/Input"; +import SearchForm from "./form/SearchForm"; +import KeymapsForm from "./form/KeymapsForm"; +import BlacklistForm from "./form/BlacklistForm"; +import PropertiesForm from "./form/PropertiesForm"; +import PartialBlacklistForm from "./form/PartialBlacklistForm"; +import * as settingActions from "../../settings/actions/setting"; import SettingData, { - FormKeymaps, FormSearch, FormSettings, JSONTextSettings, -} from '../../shared/SettingData'; -import { State as AppState } from '../reducers/setting'; -import Properties from '../../shared/settings/Properties'; -import Blacklist from '../../shared/settings/Blacklist'; + FormKeymaps, + FormSearch, + FormSettings, + JSONTextSettings, +} from "../../shared/SettingData"; +import { State as AppState } from "../reducers/setting"; +import Properties from "../../shared/settings/Properties"; +import Blacklist from "../../shared/settings/Blacklist"; const DO_YOU_WANT_TO_CONTINUE = - 'Some settings in JSON can be lost when migrating. ' + - 'Do you want to continue?'; + "Some settings in JSON can be lost when migrating. " + + "Do you want to continue?"; type StateProps = ReturnType<typeof mapStateToProps>; interface DispatchProps { - dispatch: (action: any) => void, + dispatch: (action: any) => void; } -type Props = StateProps & DispatchProps & { - // FIXME - store: any; -}; +type Props = StateProps & + DispatchProps & { + // FIXME + store: any; + }; class SettingsComponent extends React.Component<Props> { componentDidMount() { @@ -34,97 +38,103 @@ class SettingsComponent extends React.Component<Props> { } renderFormFields(form: FormSettings) { - return <div> - <fieldset> - <legend>Keybindings</legend> - <KeymapsForm - value={form.keymaps} - onChange={this.bindKeymapsForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Search Engines</legend> - <SearchForm - value={form.search} - onChange={this.bindSearchForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Blacklist</legend> - <BlacklistForm - value={form.blacklist} - onChange={this.bindBlacklistForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Partial blacklist</legend> - <PartialBlacklistForm - value={form.blacklist} - onChange={this.bindBlacklistForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Properties</legend> - <PropertiesForm - types={Properties.types()} - value={form.properties.toJSON()} - onChange={this.bindPropertiesForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - </div>; + return ( + <div> + <fieldset> + <legend>Keybindings</legend> + <KeymapsForm + value={form.keymaps} + onChange={this.bindKeymapsForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Search Engines</legend> + <SearchForm + value={form.search} + onChange={this.bindSearchForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Blacklist</legend> + <BlacklistForm + value={form.blacklist} + onChange={this.bindBlacklistForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Partial blacklist</legend> + <PartialBlacklistForm + value={form.blacklist} + onChange={this.bindBlacklistForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Properties</legend> + <PropertiesForm + types={Properties.types()} + value={form.properties.toJSON()} + onChange={this.bindPropertiesForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + </div> + ); } renderJsonFields(json: JSONTextSettings, error: string) { - return <div> - <Input - type='textarea' - name='json' - label='Plain JSON' - spellCheck={false} - error={error} - onValueChange={this.bindJson.bind(this)} - onBlur={this.save.bind(this)} - value={json.toJSONText()} - /> - </div>; + return ( + <div> + <Input + type="textarea" + name="json" + label="Plain JSON" + spellCheck={false} + error={error} + onValueChange={this.bindJson.bind(this)} + onBlur={this.save.bind(this)} + value={json.toJSONText()} + /> + </div> + ); } render() { let fields = null; const disabled = this.props.error.length > 0; - if (this.props.source === 'form') { + if (this.props.source === "form") { fields = this.renderFormFields(this.props.form!!); - } else if (this.props.source === 'json') { + } else if (this.props.source === "json") { fields = this.renderJsonFields(this.props.json!!, this.props.error); } return ( <div> <h1>Configure Vim-Vixen</h1> - <form className='vimvixen-settings-form'> + <form className="vimvixen-settings-form"> <Input - type='radio' - id='setting-source-form' - name='source' - label='Use form' - checked={this.props.source === 'form'} - value='form' + type="radio" + id="setting-source-form" + name="source" + label="Use form" + checked={this.props.source === "form"} + value="form" onValueChange={this.bindSource.bind(this)} - disabled={disabled} /> + disabled={disabled} + /> <Input - type='radio' - name='source' - label='Use plain JSON' - checked={this.props.source === 'json'} - value='json' + type="radio" + name="source" + label="Use plain JSON" + checked={this.props.source === "json"} + value="json" onValueChange={this.bindSource.bind(this)} - disabled={disabled} /> - { fields } + disabled={disabled} + /> + {fields} </form> </div> ); @@ -142,7 +152,8 @@ class SettingsComponent extends React.Component<Props> { const data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithSearch( - FormSearch.fromJSON(value)), + FormSearch.fromJSON(value) + ), }); this.props.dispatch(settingActions.set(data)); } @@ -159,7 +170,8 @@ class SettingsComponent extends React.Component<Props> { const data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithProperties( - Properties.fromJSON(value)) + Properties.fromJSON(value) + ), }); this.props.dispatch(settingActions.set(data)); } @@ -174,27 +186,29 @@ class SettingsComponent extends React.Component<Props> { bindSource(_name: string, value: string) { const from = this.props.source; - if (from === 'form' && value === 'json') { - this.props.dispatch(settingActions.switchToJson( - this.props.form as FormSettings)); + if (from === "form" && value === "json") { + this.props.dispatch( + settingActions.switchToJson(this.props.form as FormSettings) + ); this.save(); - } else if (from === 'json' && value === 'form') { + } else if (from === "json" && value === "form") { const b = window.confirm(DO_YOU_WANT_TO_CONTINUE); if (!b) { this.forceUpdate(); return; } this.props.dispatch( - settingActions.switchToForm(this.props.json as JSONTextSettings)); + settingActions.switchToForm(this.props.json as JSONTextSettings) + ); this.save(); } } save() { const { source, json, form } = this.props.store.getState(); - this.props.dispatch(settingActions.save( - new SettingData({ source, json, form }), - )); + this.props.dispatch( + settingActions.save(new SettingData({ source, json, form })) + ); } } diff --git a/src/settings/components/ui/AddButton.tsx b/src/settings/components/ui/AddButton.tsx index bb76d08..c15a732 100644 --- a/src/settings/components/ui/AddButton.tsx +++ b/src/settings/components/ui/AddButton.tsx @@ -1,13 +1,18 @@ -import './AddButton.scss'; -import React from 'react'; +import "./AddButton.scss"; +import React from "react"; type Props = React.AllHTMLAttributes<HTMLInputElement>; class AddButton extends React.Component<Props> { render() { - return <input - className='ui-add-button' type='button' value='✚' - {...this.props} />; + return ( + <input + className="ui-add-button" + type="button" + value="✚" + {...this.props} + /> + ); } } diff --git a/src/settings/components/ui/DeleteButton.tsx b/src/settings/components/ui/DeleteButton.tsx index e666426..df8976e 100644 --- a/src/settings/components/ui/DeleteButton.tsx +++ b/src/settings/components/ui/DeleteButton.tsx @@ -1,13 +1,18 @@ -import './DeleteButton.scss'; -import React from 'react'; +import "./DeleteButton.scss"; +import React from "react"; type Props = React.AllHTMLAttributes<HTMLInputElement>; class DeleteButton extends React.Component<Props> { render() { - return <input - className='ui-delete-button' type='button' value='✖' - {...this.props} />; + return ( + <input + className="ui-delete-button" + type="button" + value="✖" + {...this.props} + /> + ); } } diff --git a/src/settings/components/ui/Input.tsx b/src/settings/components/ui/Input.tsx index 69c14b3..6819ddb 100644 --- a/src/settings/components/ui/Input.tsx +++ b/src/settings/components/ui/Input.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import './Input.scss'; +import React from "react"; +import "./Input.scss"; interface Props extends React.AllHTMLAttributes<HTMLElement> { name: string; @@ -13,66 +13,75 @@ interface Props extends React.AllHTMLAttributes<HTMLElement> { class Input extends React.Component<Props> { renderText(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label htmlFor={props.id}>{ props.label }</label> - <input - type='text' className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - </div>; + return ( + <div className="settings-ui-input"> + <label htmlFor={props.id}>{props.label}</label> + <input + type="text" + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + </div> + ); } renderRadio(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label> - <input - type='radio' className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - { props.label } - </label> - </div>; + return ( + <div className="settings-ui-input"> + <label> + <input + type="radio" + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + {props.label} + </label> + </div> + ); } renderTextArea(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label - htmlFor={props.id} - >{ props.label }</label> - <textarea - className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - <p className='settings-ui-input-error'>{ this.props.error }</p> - </div>; + return ( + <div className="settings-ui-input"> + <label htmlFor={props.id}>{props.label}</label> + <textarea + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + <p className="settings-ui-input-error">{this.props.error}</p> + </div> + ); } render() { const { type } = this.props; switch (this.props.type) { - case 'text': - return this.renderText(this.props); - case 'radio': - return this.renderRadio(this.props); - case 'textarea': - return this.renderTextArea(this.props); - default: - console.warn(`Unsupported input type ${type}`); + case "text": + return this.renderText(this.props); + case "radio": + return this.renderRadio(this.props); + case "textarea": + return this.renderTextArea(this.props); + default: + console.warn(`Unsupported input type ${type}`); } return null; } - bindOnChange(e: React.ChangeEvent<HTMLInputElement|HTMLTextAreaElement>) { + bindOnChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) { if (this.props.onValueChange) { this.props.onValueChange(e.target.name, e.target.value); } diff --git a/src/settings/index.tsx b/src/settings/index.tsx index cde4488..0d3364b 100644 --- a/src/settings/index.tsx +++ b/src/settings/index.tsx @@ -1,18 +1,15 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import SettingsComponent from './components'; -import reducer from './reducers/setting'; -import { Provider } from 'react-redux'; -import promise from 'redux-promise'; -import { createStore, applyMiddleware } from 'redux'; +import React from "react"; +import ReactDOM from "react-dom"; +import SettingsComponent from "./components"; +import reducer from "./reducers/setting"; +import { Provider } from "react-redux"; +import promise from "redux-promise"; +import { createStore, applyMiddleware } from "redux"; -const store = createStore( - reducer, - applyMiddleware(promise), -); +const store = createStore(reducer, applyMiddleware(promise)); -document.addEventListener('DOMContentLoaded', () => { - const wrapper = document.getElementById('vimvixen-settings'); +document.addEventListener("DOMContentLoaded", () => { + const wrapper = document.getElementById("vimvixen-settings"); ReactDOM.render( <Provider store={store}> <SettingsComponent store={store} /> diff --git a/src/settings/keymaps.ts b/src/settings/keymaps.ts index 24ba1a5..25c7a51 100644 --- a/src/settings/keymaps.ts +++ b/src/settings/keymaps.ts @@ -2,70 +2,79 @@ const fields = [ [ - ['scroll.vertically?{"count":1}', 'Scroll down'], - ['scroll.vertically?{"count":-1}', 'Scroll up'], - ['scroll.horizonally?{"count":-1}', 'Scroll left'], - ['scroll.horizonally?{"count":1}', 'Scroll right'], - ['scroll.home', 'Scroll to leftmost'], - ['scroll.end', 'Scroll to rightmost'], - ['scroll.top', 'Scroll to top'], - ['scroll.bottom', 'Scroll to bottom'], - ['scroll.pages?{"count":-0.5}', 'Scroll up by half of screen'], - ['scroll.pages?{"count":0.5}', 'Scroll down by half of screen'], - ['scroll.pages?{"count":-1}', 'Scroll up by a screen'], - ['scroll.pages?{"count":1}', 'Scroll down by a screen'], - ], [ - ['mark.set.prefix', 'Set mark at current position'], - ['mark.jump.prefix', 'Jump to the mark'], - ], [ - ['tabs.close?{"select":"right"}', 'Close a tab'], - ['tabs.close.right', 'Close all tabs to the right'], - ['tabs.reopen', 'Reopen closed tab'], - ['tabs.next', 'Select next tab'], - ['tabs.prev', 'Select prev tab'], - ['tabs.first', 'Select first tab'], - ['tabs.last', 'Select last tab'], - ['tabs.reload?{"cache":false}', 'Reload current tab'], - ['tabs.reload?{"cache":true}', 'Reload with no caches'], - ['tabs.pin.toggle', 'Toggle pinned state'], - ['tabs.duplicate', 'Duplicate a tab'], - ], [ - ['follow.start?{"newTab":false,"background":false}', 'Follow a link'], - ['follow.start?{"newTab":true,"background":false}', 'Follow a link in new tab'], - ['navigate.history.prev', 'Go back in histories'], - ['navigate.history.next', 'Go forward in histories'], - ['navigate.link.next', 'Open next link'], - ['navigate.link.prev', 'Open previous link'], - ['navigate.parent', 'Go to parent directory'], - ['navigate.root', 'Go to root directory'], - ['page.source', 'Open page source'], - ['page.home?{"newTab":false}', 'Open start page to current tab'], - ['page.home?{"newTab":true}', 'Open start page in new tab'], - ['focus.input', 'Focus input'], - ], [ - ['find.start', 'Start find mode'], - ['find.next', 'Find next word'], - ['find.prev', 'Find previous word'], - ], [ - ['command.show', 'Open console'], - ['command.show.open?{"alter":false}', 'Open URL'], - ['command.show.open?{"alter":true}', 'Alter URL'], - ['command.show.tabopen?{"alter":false}', 'Open URL in new tab'], - ['command.show.tabopen?{"alter":true}', 'Alter URL in new tab'], - ['command.show.winopen?{"alter":false}', 'Open URL in new window'], - ['command.show.winopen?{"alter":true}', 'Alter URL in new window'], - ['command.show.buffer', 'Open buffer command'], - ['command.show.addbookmark?{"alter":true}', 'Open addbookmark command'], - ], [ - ['addon.toggle.enabled', 'Enable or disable'], - ['urls.yank', 'Copy current URL'], - ['urls.paste?{"newTab":false}', 'Open clipboard\'s URL in current tab'], - ['urls.paste?{"newTab":true}', 'Open clipboard\'s URL in new tab'], - ['zoom.in', 'Zoom-in'], - ['zoom.out', 'Zoom-out'], - ['zoom.neutral', 'Reset zoom level'], - ['repeat.last', 'Repeat last change'], - ] + ['scroll.vertically?{"count":1}', "Scroll down"], + ['scroll.vertically?{"count":-1}', "Scroll up"], + ['scroll.horizonally?{"count":-1}', "Scroll left"], + ['scroll.horizonally?{"count":1}', "Scroll right"], + ["scroll.home", "Scroll to leftmost"], + ["scroll.end", "Scroll to rightmost"], + ["scroll.top", "Scroll to top"], + ["scroll.bottom", "Scroll to bottom"], + ['scroll.pages?{"count":-0.5}', "Scroll up by half of screen"], + ['scroll.pages?{"count":0.5}', "Scroll down by half of screen"], + ['scroll.pages?{"count":-1}', "Scroll up by a screen"], + ['scroll.pages?{"count":1}', "Scroll down by a screen"], + ], + [ + ["mark.set.prefix", "Set mark at current position"], + ["mark.jump.prefix", "Jump to the mark"], + ], + [ + ['tabs.close?{"select":"right"}', "Close a tab"], + ["tabs.close.right", "Close all tabs to the right"], + ["tabs.reopen", "Reopen closed tab"], + ["tabs.next", "Select next tab"], + ["tabs.prev", "Select prev tab"], + ["tabs.first", "Select first tab"], + ["tabs.last", "Select last tab"], + ['tabs.reload?{"cache":false}', "Reload current tab"], + ['tabs.reload?{"cache":true}', "Reload with no caches"], + ["tabs.pin.toggle", "Toggle pinned state"], + ["tabs.duplicate", "Duplicate a tab"], + ], + [ + ['follow.start?{"newTab":false,"background":false}', "Follow a link"], + [ + 'follow.start?{"newTab":true,"background":false}', + "Follow a link in new tab", + ], + ["navigate.history.prev", "Go back in histories"], + ["navigate.history.next", "Go forward in histories"], + ["navigate.link.next", "Open next link"], + ["navigate.link.prev", "Open previous link"], + ["navigate.parent", "Go to parent directory"], + ["navigate.root", "Go to root directory"], + ["page.source", "Open page source"], + ['page.home?{"newTab":false}', "Open start page to current tab"], + ['page.home?{"newTab":true}', "Open start page in new tab"], + ["focus.input", "Focus input"], + ], + [ + ["find.start", "Start find mode"], + ["find.next", "Find next word"], + ["find.prev", "Find previous word"], + ], + [ + ["command.show", "Open console"], + ['command.show.open?{"alter":false}', "Open URL"], + ['command.show.open?{"alter":true}', "Alter URL"], + ['command.show.tabopen?{"alter":false}', "Open URL in new tab"], + ['command.show.tabopen?{"alter":true}', "Alter URL in new tab"], + ['command.show.winopen?{"alter":false}', "Open URL in new window"], + ['command.show.winopen?{"alter":true}', "Alter URL in new window"], + ["command.show.buffer", "Open buffer command"], + ['command.show.addbookmark?{"alter":true}', "Open addbookmark command"], + ], + [ + ["addon.toggle.enabled", "Enable or disable"], + ["urls.yank", "Copy current URL"], + ['urls.paste?{"newTab":false}', "Open clipboard's URL in current tab"], + ['urls.paste?{"newTab":true}', "Open clipboard's URL in new tab"], + ["zoom.in", "Zoom-in"], + ["zoom.out", "Zoom-out"], + ["zoom.neutral", "Reset zoom level"], + ["repeat.last", "Repeat last change"], + ], ]; export default { diff --git a/src/settings/reducers/setting.ts b/src/settings/reducers/setting.ts index 804853f..31544bb 100644 --- a/src/settings/reducers/setting.ts +++ b/src/settings/reducers/setting.ts @@ -1,8 +1,10 @@ -import * as actions from '../actions'; +import * as actions from "../actions"; import { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; -import { DefaultSetting } from '../../shared/settings/Settings'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; +import { DefaultSetting } from "../../shared/settings/Settings"; export interface State { source: SettingSource; @@ -13,37 +15,41 @@ export interface State { const defaultState: State = { source: SettingSource.JSON, - json: JSONTextSettings.fromText(''), + json: JSONTextSettings.fromText(""), form: FormSettings.fromSettings(DefaultSetting), - error: '', + error: "", }; export default function reducer( state = defaultState, - action: actions.SettingAction, + action: actions.SettingAction ): State { switch (action.type) { - case actions.SETTING_SET_SETTINGS: - return { ...state, - source: action.source, - json: action.json, - form: action.form, - error: '', }; - case actions.SETTING_SHOW_ERROR: - return { ...state, - error: action.error, - json: action.json, }; - case actions.SETTING_SWITCH_TO_FORM: - return { ...state, - error: '', - source: SettingSource.Form, - form: action.form, }; - case actions.SETTING_SWITCH_TO_JSON: - return { ...state, - error: '', - source: SettingSource.JSON, - json: action.json, }; - default: - return state; + case actions.SETTING_SET_SETTINGS: + return { + ...state, + source: action.source, + json: action.json, + form: action.form, + error: "", + }; + case actions.SETTING_SHOW_ERROR: + return { ...state, error: action.error, json: action.json }; + case actions.SETTING_SWITCH_TO_FORM: + return { + ...state, + error: "", + source: SettingSource.Form, + form: action.form, + }; + case actions.SETTING_SWITCH_TO_JSON: + return { + ...state, + error: "", + source: SettingSource.JSON, + json: action.json, + }; + default: + return state; } } diff --git a/src/settings/storage.ts b/src/settings/storage.ts index 55cca96..da67ecc 100644 --- a/src/settings/storage.ts +++ b/src/settings/storage.ts @@ -1,22 +1,24 @@ -import SettingData, { DefaultSettingData } from '../shared/SettingData'; +import SettingData, { DefaultSettingData } from "../shared/SettingData"; -const loadSettingData = async(): Promise<SettingData> => { - const { settings: syncSettings } = await browser.storage.sync.get('settings'); +const loadSettingData = async (): Promise<SettingData> => { + const { settings: syncSettings } = await browser.storage.sync.get("settings"); if (syncSettings) { return SettingData.fromJSON(syncSettings as any); } - const { settings: localSettings } = await browser.storage.local.get('settings'); + const { settings: localSettings } = await browser.storage.local.get( + "settings" + ); if (localSettings) { return SettingData.fromJSON(localSettings as any); } - return DefaultSettingData + return DefaultSettingData; }; -export const load = async(): Promise<SettingData> => { +export const load = async (): Promise<SettingData> => { try { return loadSettingData(); } catch (e) { - console.error('unable to load settings', e); + console.error("unable to load settings", e); return DefaultSettingData; } }; |