diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2017-11-19 08:23:51 +0900 |
---|---|---|
committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2017-11-26 11:40:12 +0900 |
commit | d33b37cdb9d2956f5f2d23ab4e71e35db137b16e (patch) | |
tree | 36e9bb6012c338259ed997d4ceda180e999beecc /src/settings | |
parent | 44459e39c3526673ac2ac7065c5659e4af5ea7d8 (diff) |
Use Preact for settings and show validation
Diffstat (limited to 'src/settings')
-rw-r--r-- | src/settings/components/index.jsx | 48 | ||||
-rw-r--r-- | src/settings/components/site.scss | 2 | ||||
-rw-r--r-- | src/settings/components/ui/input.jsx | 50 | ||||
-rw-r--r-- | src/settings/components/ui/input.scss | 17 |
4 files changed, 99 insertions, 18 deletions
diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index bb2045a..98d8fb2 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 Input from './ui/input'; import * as settingActions from 'settings/actions/setting'; import * as validator from 'shared/validators/setting'; @@ -10,6 +11,9 @@ class SettingsComponent extends Component { this.state = { settings: { json: '', + }, + errors: { + json: '', } }; this.context.store.subscribe(this.stateChanged.bind(this)); @@ -35,39 +39,47 @@ class SettingsComponent extends Component { <h1>Configure Vim-Vixen</h1> <form className='vimvixen-settings-form'> - <p>Load settings from:</p> - <input type='radio' id='setting-source-json' + <Input + type='radio' name='source' - value='json' - onChange={this.bindAndSave.bind(this)} - checked={this.state.settings.source === 'json'} /> - <label htmlFor='settings-source-json'>JSON</label> + label='Use plain JSON' + checked={this.state.settings.source === 'json'} + value='json' /> - <textarea name='json' spellCheck='false' - onInput={this.validate.bind(this)} + <Input + type='textarea' + name='json' + label='Plane JSON' + spellCheck='false' + error={this.state.errors.json} onChange={this.bindValue.bind(this)} onBlur={this.bindAndSave.bind(this)} - value={this.state.settings.json} /> + value={this.state.settings.json} + /> </form> </div> ); } - validate(e) { - try { - let settings = JSON.parse(e.target.value); + validate(target) { + if (target.name === 'json') { + let settings = JSON.parse(target.value); validator.validate(settings); - e.target.setCustomValidity(''); - } catch (err) { - e.target.setCustomValidity(err.message); } } bindValue(e) { - let nextSettings = Object.assign({}, this.state.settings); - nextSettings[e.target.name] = e.target.value; + let next = Object.assign({}, 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; - this.setState({ settings: nextSettings }); + this.setState(next); } bindAndSave(e) { diff --git a/src/settings/components/site.scss b/src/settings/components/site.scss index fae9c39..aac4319 100644 --- a/src/settings/components/site.scss +++ b/src/settings/components/site.scss @@ -1,4 +1,6 @@ .vimvixen-settings-form { + padding: 2px; + textarea[name=json] { font-family: monospace; width: 100%; diff --git a/src/settings/components/ui/input.jsx b/src/settings/components/ui/input.jsx new file mode 100644 index 0000000..9b6c229 --- /dev/null +++ b/src/settings/components/ui/input.jsx @@ -0,0 +1,50 @@ +import { h, Component } from 'preact'; +import './input.scss'; + +class Input extends Component { + + renderRadio(props) { + let inputClasses = 'form-field-input'; + if (props.error) { + inputClasses += ' input-error'; + } + return <div> + <label> + <input className={ inputClasses } type='radio' {...props} /> + { props.label } + </label> + </div>; + } + + renderTextArea(props) { + let inputClasses = 'form-field-input'; + if (props.error) { + inputClasses += ' input-error'; + } + return <div> + <label + className='form-field-label' + htmlFor={props.id} + >{ props.label }</label> + <textarea className={inputClasses} {...props} /> + + <p className='form-field-error'>{ this.props.error }</p> + </div>; + } + + render() { + let { type } = this.props; + + switch (this.props.type) { + case 'radio': + return this.renderRadio(this.props); + case 'textarea': + return this.renderTextArea(this.props); + default: + console.warn(`Unsupported input type ${type}`); + } + return null; + } +} + +export default Input; diff --git a/src/settings/components/ui/input.scss b/src/settings/components/ui/input.scss new file mode 100644 index 0000000..6187138 --- /dev/null +++ b/src/settings/components/ui/input.scss @@ -0,0 +1,17 @@ +.form-field-label { + font-weight: bold +} + +.form-field-error { + font-weight: bold; + color: red; + min-height: 1.5em; +} + +.form-field-input { + padding: 4px; +} + +.form-field-input.input-error { + box-shadow: 0 0 2px red; +} |