aboutsummaryrefslogtreecommitdiff
path: root/src/settings
diff options
context:
space:
mode:
authorShin'ya Ueoka <ueokande@i-beam.org>2017-11-19 08:23:51 +0900
committerShin'ya Ueoka <ueokande@i-beam.org>2017-11-26 11:40:12 +0900
commitd33b37cdb9d2956f5f2d23ab4e71e35db137b16e (patch)
tree36e9bb6012c338259ed997d4ceda180e999beecc /src/settings
parent44459e39c3526673ac2ac7065c5659e4af5ea7d8 (diff)
Use Preact for settings and show validation
Diffstat (limited to 'src/settings')
-rw-r--r--src/settings/components/index.jsx48
-rw-r--r--src/settings/components/site.scss2
-rw-r--r--src/settings/components/ui/input.jsx50
-rw-r--r--src/settings/components/ui/input.scss17
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;
+}