diff options
-rw-r--r-- | src/settings/actions/index.js | 3 | ||||
-rw-r--r-- | src/settings/actions/setting.js | 51 | ||||
-rw-r--r-- | src/settings/components/index.jsx | 168 | ||||
-rw-r--r-- | src/settings/reducers/setting.js | 23 | ||||
-rw-r--r-- | test/settings/reducers/setting.test.js | 42 |
5 files changed, 144 insertions, 143 deletions
diff --git a/src/settings/actions/index.js b/src/settings/actions/index.js index 8c212c2..016f2a5 100644 --- a/src/settings/actions/index.js +++ b/src/settings/actions/index.js @@ -1,4 +1,7 @@ export default { // Settings SETTING_SET_SETTINGS: 'setting.set.settings', + SETTING_SHOW_ERROR: 'setting.show.error', + SETTING_SWITCH_TO_FORM: 'setting.switch.to.form', + SETTING_SWITCH_TO_JSON: 'setting.switch.to.json', }; diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js index 1219ba5..3bb24be 100644 --- a/src/settings/actions/setting.js +++ b/src/settings/actions/setting.js @@ -1,8 +1,9 @@ import actions from 'settings/actions'; import messages from 'shared/messages'; -import DefaultSettings from 'shared/settings/default'; -import * as settingsStorage from 'shared/settings/storage'; +import * as validator from 'shared/settings/validator'; +import KeymapsForm from '../components/form/keymaps-form'; import * as settingsValues from 'shared/settings/values'; +import * as settingsStorage from 'shared/settings/storage'; const load = async() => { let settings = await settingsStorage.loadRaw(); @@ -10,6 +11,18 @@ const load = async() => { }; const save = async(settings) => { + try { + if (settings.source === 'json') { + let value = JSON.parse(settings.json); + validator.validate(value); + } + } catch (e) { + return { + type: actions.SETTING_SHOW_ERROR, + error: e.toString(), + json: settings.json, + }; + } await settingsStorage.save(settings); await browser.runtime.sendMessage({ type: messages.SETTINGS_RELOAD @@ -17,21 +30,39 @@ const save = async(settings) => { return set(settings); }; -const set = (settings) => { - let value = JSON.parse(DefaultSettings.json); - if (settings.source === 'json') { - value = settingsValues.valueFromJson(settings.json); - } else if (settings.source === 'form') { - value = settingsValues.valueFromForm(settings.form); +const switchToForm = (json) => { + try { + validator.validate(JSON.parse(json)); + // AllowdOps filters operations, this is dirty dependency + let form = settingsValues.formFromJson(json, KeymapsForm.AllowdOps); + return { + type: actions.SETTING_SWITCH_TO_FORM, + form, + }; + } catch (e) { + return { + type: actions.SETTING_SHOW_ERROR, + error: e.toString(), + json, + }; } +}; +const switchToJson = (form) => { + let json = settingsValues.jsonFromForm(form); + return { + type: actions.SETTING_SWITCH_TO_JSON, + json, + }; +}; + +const set = (settings) => { return { type: actions.SETTING_SET_SETTINGS, source: settings.source, json: settings.json, form: settings.form, - value, }; }; -export { load, save }; +export { load, save, switchToForm, switchToJson }; diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index c479986..66dc940 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -1,5 +1,6 @@ import './site.scss'; import { h, Component } from 'preact'; +import { connect } from 'preact-redux'; import Input from './ui/input'; import SearchForm from './form/search-form'; import KeymapsForm from './form/keymaps-form'; @@ -7,63 +8,36 @@ import BlacklistForm from './form/blacklist-form'; import PropertiesForm from './form/properties-form'; import * as properties from 'shared/settings/properties'; import * as settingActions from 'settings/actions/setting'; -import * as validator from 'shared/settings/validator'; -import * as settingsValues from 'shared/settings/values'; const DO_YOU_WANT_TO_CONTINUE = 'Some settings in JSON can be lost when migrating. ' + 'Do you want to continue?'; class SettingsComponent extends Component { - constructor(props, context) { - super(props, context); - - this.state = { - settings: { - json: '', - }, - errors: { - json: '', - } - }; - this.context.store.subscribe(this.stateChanged.bind(this)); - } - componentDidMount() { - this.context.store.dispatch(settingActions.load()); - } - - stateChanged() { - let settings = this.context.store.getState(); - this.setState({ - settings: { - source: settings.source, - json: settings.json, - form: settings.form, - } - }); + this.props.dispatch(settingActions.load()); } - renderFormFields() { + renderFormFields(form) { return <div> <fieldset> <legend>Keybindings</legend> <KeymapsForm - value={this.state.settings.form.keymaps} + value={form.keymaps} onChange={value => this.bindForm('keymaps', value)} /> </fieldset> <fieldset> <legend>Search Engines</legend> <SearchForm - value={this.state.settings.form.search} + value={form.search} onChange={value => this.bindForm('search', value)} /> </fieldset> <fieldset> <legend>Blacklist</legend> <BlacklistForm - value={this.state.settings.form.blacklist} + value={form.blacklist} onChange={value => this.bindForm('blacklist', value)} /> </fieldset> @@ -71,33 +45,33 @@ class SettingsComponent extends Component { <legend>Properties</legend> <PropertiesForm types={properties.types} - value={this.state.settings.form.properties} + value={form.properties} onChange={value => this.bindForm('properties', value)} /> </fieldset> </div>; } - renderJsonFields() { + renderJsonFields(json, error) { return <div> <Input type='textarea' name='json' label='Plain JSON' spellCheck='false' - error={this.state.errors.json} - onChange={this.bindValue.bind(this)} - value={this.state.settings.json} + error={error} + onChange={this.bindJson.bind(this)} + value={json} /> </div>; } render() { let fields = null; - if (this.state.settings.source === 'form') { - fields = this.renderFormFields(); - } else if (this.state.settings.source === 'json') { - fields = this.renderJsonFields(); + if (this.props.source === 'form') { + fields = this.renderFormFields(this.props.form); + } else if (this.props.source === 'json') { + fields = this.renderJsonFields(this.props.json, this.props.error); } return ( <div> @@ -108,7 +82,7 @@ class SettingsComponent extends Component { id='setting-source-form' name='source' label='Use form' - checked={this.state.settings.source === 'form'} + checked={this.props.source === 'form'} value='form' onChange={this.bindSource.bind(this)} /> @@ -116,7 +90,7 @@ class SettingsComponent extends Component { type='radio' name='source' label='Use plain JSON' - checked={this.state.settings.source === 'json'} + checked={this.props.source === 'json'} value='json' onChange={this.bindSource.bind(this)} /> @@ -126,98 +100,44 @@ class SettingsComponent extends Component { ); } - validate(target) { - if (target.name === 'json') { - let settings = JSON.parse(target.value); - validator.validate(settings); - } - } - - validateValue(e) { - let next = { ...this.state }; - - next.errors.json = ''; - try { - this.validate(e.target); - } catch (err) { - next.errors.json = err.message; - } - next.settings[e.target.name] = e.target.value; - } - bindForm(name, value) { - let next = { ...this.state, - settings: { ...this.state.settings, - form: { ...this.state.settings.form }}}; - next.settings.form[name] = value; - this.setState(next); - this.context.store.dispatch(settingActions.save(next.settings)); - } - - bindValue(e) { - let next = { ...this.state }; - let error = false; - - next.errors.json = ''; - try { - this.validate(e.target); - } catch (err) { - next.errors.json = err.message; - error = true; - } - next.settings[e.target.name] = e.target.value; - - this.setState(this.state); - if (!error) { - this.context.store.dispatch(settingActions.save(next.settings)); - } - } - - migrateToForm() { - let b = window.confirm(DO_YOU_WANT_TO_CONTINUE); - if (!b) { - this.setState(this.state); - return; - } - try { - validator.validate(JSON.parse(this.state.settings.json)); - } catch (err) { - this.setState(this.state); - return; - } - - let form = settingsValues.formFromJson( - this.state.settings.json, KeymapsForm.AllowdOps); - let next = { ...this.state }; - next.settings.form = form; - next.settings.source = 'form'; - next.errors.json = ''; - - this.setState(next); - this.context.store.dispatch(settingActions.save(next.settings)); + let settings = { + source: this.props.source, + json: this.props.json, + form: { ...this.props.form }, + }; + settings.form[name] = value; + this.props.dispatch(settingActions.save(settings)); } - migrateToJson() { - let json = settingsValues.jsonFromForm(this.state.settings.form); - let next = { ...this.state }; - next.settings.json = json; - next.settings.source = 'json'; - next.errors.json = ''; - - this.setState(next); - this.context.store.dispatch(settingActions.save(next.settings)); + bindJson(e) { + let settings = { + source: this.props.source, + json: e.target.value, + form: this.props.form, + }; + this.props.dispatch(settingActions.save(settings)); } bindSource(e) { - let from = this.state.settings.source; + let from = this.props.source; let to = e.target.value; if (from === 'form' && to === 'json') { - this.migrateToJson(); + this.props.dispatch(settingActions.switchToJson(this.props.form)); } else if (from === 'json' && to === 'form') { - this.migrateToForm(); + let b = window.confirm(DO_YOU_WANT_TO_CONTINUE); + if (!b) { + return; + } + this.props.dispatch(settingActions.switchToForm(this.props.json)); } + + let settings = this.context.store.getState(); + this.props.dispatch(settingActions.save(settings)); } } -export default SettingsComponent; +const mapStateToProps = state => state; + +export default connect(mapStateToProps)(SettingsComponent); diff --git a/src/settings/reducers/setting.js b/src/settings/reducers/setting.js index 70c6183..8e4a415 100644 --- a/src/settings/reducers/setting.js +++ b/src/settings/reducers/setting.js @@ -4,20 +4,33 @@ const defaultState = { source: '', json: '', form: null, - value: {} + error: '', }; export default function reducer(state = defaultState, action = {}) { switch (action.type) { case actions.SETTING_SET_SETTINGS: - return { + return { ...state, source: action.source, json: action.json, form: action.form, - value: action.value, - }; + errors: '', + error: '', }; + case actions.SETTING_SHOW_ERROR: + return { ...state, + error: action.text, + json: action.json, }; + case actions.SETTING_SWITCH_TO_FORM: + return { ...state, + error: '', + source: 'form', + form: action.form, }; + case actions.SETTING_SWITCH_TO_JSON: + return { ...state, + error: '', + source: 'json', + json: action.json, }; default: return state; } } - diff --git a/test/settings/reducers/setting.test.js b/test/settings/reducers/setting.test.js index b9579cf..d800394 100644 --- a/test/settings/reducers/setting.test.js +++ b/test/settings/reducers/setting.test.js @@ -1,21 +1,55 @@ import actions from 'settings/actions'; import settingReducer from 'settings/reducers/setting'; -describe("setting reducer", () => { +describe("settings setting reducer", () => { it('return the initial state', () => { let state = settingReducer(undefined, {}); expect(state).to.have.deep.property('json', ''); - expect(state).to.have.deep.property('value', {}); + expect(state).to.have.deep.property('form', null); + expect(state).to.have.deep.property('error', ''); }); it('return next state for SETTING_SET_SETTINGS', () => { let action = { type: actions.SETTING_SET_SETTINGS, + source: 'json', json: '{ "key": "value" }', - value: { key: 123 }, + form: {}, }; let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('source', 'json'); expect(state).to.have.deep.property('json', '{ "key": "value" }'); - expect(state).to.have.deep.property('value', { key: 123 }); + expect(state).to.have.deep.property('form', {}); + }); + + it('return next state for SETTING_SHOW_ERROR', () => { + let action = { + type: actions.SETTING_SHOW_ERROR, + text: 'bad value', + json: '{}', + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('error', 'bad value'); + expect(state).to.have.deep.property('json', '{}'); + }); + + it('return next state for SETTING_SWITCH_TO_FORM', () => { + let action = { + type: actions.SETTING_SWITCH_TO_FORM, + form: {}, + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('form', {}); + expect(state).to.have.deep.property('source', 'form'); + }); + + it('return next state for SETTING_SWITCH_TO_JSON', () => { + let action = { + type: actions.SETTING_SWITCH_TO_JSON, + json: '{}', + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('json', '{}'); + expect(state).to.have.deep.property('source', 'json'); }); }); |