From 6669f6b6ef2a3268dfeca87dbccc2ac8ef2fa30d Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Mon, 9 Oct 2017 13:42:16 +0900
Subject: use react in settings

---
 src/settings/components/index.jsx | 78 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 src/settings/components/index.jsx

(limited to 'src/settings/components/index.jsx')

diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx
new file mode 100644
index 0000000..e57b09d
--- /dev/null
+++ b/src/settings/components/index.jsx
@@ -0,0 +1,78 @@
+import './site.scss';
+import React from 'react';
+import PropTypes from 'prop-types';
+import * as settingActions from 'settings/actions/setting';
+import { validate } from 'shared/validators/setting';
+
+class SettingsComponent extends React.Component {
+  constructor(props, context) {
+    super(props, context);
+
+    this.state = {
+      settings: {
+        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 });
+  }
+
+  render() {
+    return (
+      <div>
+        <h1>Configure Vim-Vixen</h1>
+
+        <form id='vimvixen-settings-form' className='vimvixen-settings-form'
+          onSubmit={this.saveSettings.bind(this)}>
+          <label htmlFor='load-from-json'>Load from JSON:</label>
+          <textarea name='plain-json' spellCheck='false'
+            onInput={this.onPlainJsonChanged.bind(this)}
+            onChange={this.bindValue.bind(this)}
+            value={this.state.settings.json} />
+          <button type='submit'>Save</button>
+        </form>
+      </div>
+    );
+  }
+
+  saveSettings(e) {
+    let settings = {
+      json: e.target.elements['plain-json'].value,
+    };
+    this.context.store.dispatch(settingActions.save(settings));
+    e.preventDefault();
+  }
+
+  onPlainJsonChanged(e) {
+    try {
+      let settings = JSON.parse(e.target.value);
+      validate(settings);
+      e.target.setCustomValidity('');
+    } catch (err) {
+      e.target.setCustomValidity(err.message);
+    }
+  }
+
+  bindValue(e) {
+    let next = Object.assign({}, this.state, {
+      settings: {
+        'json': e.target.value,
+      }
+    });
+    this.setState(next);
+  }
+}
+
+SettingsComponent.contextTypes = {
+  store: PropTypes.any,
+};
+
+export default SettingsComponent;
-- 
cgit v1.2.3


From 805d1395fc869235f079438b5b4884a521c0230e Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Mon, 9 Oct 2017 17:03:52 +0900
Subject: save settings on the fly

---
 src/settings/actions/setting.js   |  6 ++--
 src/settings/components/index.jsx | 61 ++++++++++++++++++++++++---------------
 src/settings/components/site.scss |  2 +-
 src/settings/reducers/setting.js  |  2 ++
 src/shared/default-settings.js    |  1 +
 5 files changed, 45 insertions(+), 27 deletions(-)

(limited to 'src/settings/components/index.jsx')

diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js
index 3525f0a..c1b27c8 100644
--- a/src/settings/actions/setting.js
+++ b/src/settings/actions/setting.js
@@ -3,8 +3,7 @@ import messages from 'shared/messages';
 import DefaultSettings from 'shared/default-settings';
 
 const load = () => {
-  return browser.storage.local.get('settings').then((value) => {
-    let settings = value.settings;
+  return browser.storage.local.get('settings').then(({ settings }) => {
     if (settings) {
       return set(settings);
     }
@@ -18,6 +17,8 @@ const save = (settings) => {
   }).then(() => {
     return browser.runtime.sendMessage({
       type: messages.SETTINGS_RELOAD
+    }).then(() => {
+      return set(settings);
     });
   });
 };
@@ -25,6 +26,7 @@ const save = (settings) => {
 const set = (settings) => {
   return {
     type: actions.SETTING_SET_SETTINGS,
+    source: settings.source,
     json: settings.json,
     value: JSON.parse(settings.json),
   };
diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx
index e57b09d..4418942 100644
--- a/src/settings/components/index.jsx
+++ b/src/settings/components/index.jsx
@@ -2,7 +2,7 @@ import './site.scss';
 import React from 'react';
 import PropTypes from 'prop-types';
 import * as settingActions from 'settings/actions/setting';
-import { validate } from 'shared/validators/setting';
+import * as validator from 'shared/validators/setting';
 
 class SettingsComponent extends React.Component {
   constructor(props, context) {
@@ -22,39 +22,42 @@ class SettingsComponent extends React.Component {
 
   stateChanged() {
     let settings = this.context.store.getState();
-    this.setState({ settings });
+    this.setState({
+      settings: {
+        source: settings.source,
+        json: settings.json,
+      }
+    });
   }
 
   render() {
     return (
       <div>
         <h1>Configure Vim-Vixen</h1>
+        <form className='vimvixen-settings-form'>
 
-        <form id='vimvixen-settings-form' className='vimvixen-settings-form'
-          onSubmit={this.saveSettings.bind(this)}>
-          <label htmlFor='load-from-json'>Load from JSON:</label>
-          <textarea name='plain-json' spellCheck='false'
-            onInput={this.onPlainJsonChanged.bind(this)}
+          <p>Load settings from:</p>
+          <input type='radio' id='setting-source-json'
+            name='source'
+            value='json'
+            onChange={this.bindAndSave.bind(this)}
+            checked={this.state.settings.source === 'json'} />
+          <label htmlFor='settings-source-json'>JSON</label>
+
+          <textarea name='json' spellCheck='false'
+            onInput={this.validate.bind(this)}
             onChange={this.bindValue.bind(this)}
+            onBlur={this.bindAndSave.bind(this)}
             value={this.state.settings.json} />
-          <button type='submit'>Save</button>
         </form>
       </div>
     );
   }
 
-  saveSettings(e) {
-    let settings = {
-      json: e.target.elements['plain-json'].value,
-    };
-    this.context.store.dispatch(settingActions.save(settings));
-    e.preventDefault();
-  }
-
-  onPlainJsonChanged(e) {
+  validate(e) {
     try {
       let settings = JSON.parse(e.target.value);
-      validate(settings);
+      validator.validate(settings);
       e.target.setCustomValidity('');
     } catch (err) {
       e.target.setCustomValidity(err.message);
@@ -62,12 +65,22 @@ class SettingsComponent extends React.Component {
   }
 
   bindValue(e) {
-    let next = Object.assign({}, this.state, {
-      settings: {
-        'json': e.target.value,
-      }
-    });
-    this.setState(next);
+    let nextSettings = Object.assign({}, this.state.settings);
+    nextSettings[e.target.name] = e.target.value;
+
+    this.setState({ settings: nextSettings });
+  }
+
+  bindAndSave(e) {
+    this.bindValue(e);
+
+    try {
+      let json = this.state.settings.json;
+      validator.validate(JSON.parse(json));
+      this.context.store.dispatch(settingActions.save(this.state.settings));
+    } catch (err) {
+      // error already shown
+    }
   }
 }
 
diff --git a/src/settings/components/site.scss b/src/settings/components/site.scss
index 5707c8a..fae9c39 100644
--- a/src/settings/components/site.scss
+++ b/src/settings/components/site.scss
@@ -1,5 +1,5 @@
 .vimvixen-settings-form {
-  textarea[name=plain-json] {
+  textarea[name=json] {
     font-family: monospace;
     width: 100%;
     min-height: 64ex;
diff --git a/src/settings/reducers/setting.js b/src/settings/reducers/setting.js
index 7f32f72..a61c09f 100644
--- a/src/settings/reducers/setting.js
+++ b/src/settings/reducers/setting.js
@@ -1,6 +1,7 @@
 import actions from 'settings/actions';
 
 const defaultState = {
+  source: '',
   json: '',
   value: {}
 };
@@ -9,6 +10,7 @@ export default function reducer(state = defaultState, action = {}) {
   switch (action.type) {
   case actions.SETTING_SET_SETTINGS:
     return {
+      source: action.source,
       json: action.json,
       value: action.value,
     };
diff --git a/src/shared/default-settings.js b/src/shared/default-settings.js
index 24ac536..f287b7a 100644
--- a/src/shared/default-settings.js
+++ b/src/shared/default-settings.js
@@ -1,4 +1,5 @@
 export default {
+  source: 'json',
   json: `{
   "keymaps": {
     "0": { "type": "scroll.home" },
-- 
cgit v1.2.3

