From 2641183a5b244a9640d8fb7e92ba95dc15dadc58 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sat, 25 Nov 2017 12:31:24 +0900
Subject: keymaps form

---
 src/settings/components/form/keymaps-form.jsx | 95 +++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)
 create mode 100644 src/settings/components/form/keymaps-form.jsx

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
new file mode 100644
index 0000000..a112979
--- /dev/null
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -0,0 +1,95 @@
+import './keymaps-form.scss';
+import { h, Component } from 'preact';
+import Input from '../ui/input';
+
+const KeyMapFields = [
+  [
+    ['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 leftmost'],
+    ['scroll.end', 'Scroll last'],
+    ['scroll.pages?{count:-0.5}', 'Scroll up by half of screen'],
+    ['scroll.pages?{count:0.5}', 'Scroll up by half of screen'],
+    ['scroll.pages?{count:-1}', 'Scroll up by a screen'],
+    ['scroll.pages?{count:1}', 'Scroll up by a screen'],
+  ], [
+    ['tabs.close', 'Close a tab'],
+    ['tabs.reopen', 'Reopen closed tab'],
+    ['tabs.next?{count:1}', 'Select next Tab'],
+    ['tabs.prev?{count:1}', 'Select prev Tab'],
+    ['tabs.first', 'Select first tab'],
+    ['tabs.last', 'Select last tab'],
+    ['tabs.reload?{cache:true}', 'Reload current tab'],
+    ['tabs.pin.toggle', 'Toggle pinned state'],
+    ['tabs.duplicate', 'Dupplicate a tab'],
+  ], [
+    ['follow.start?{newTab:false}', 'Follow a link'],
+    ['follow.start?{newTab:true}', 'Follow a link in new tab'],
+    ['navigate.histories.prev', 'Go back in histories'],
+    ['navigate.histories.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'],
+  ], [
+    ['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'],
+  ], [
+    ['addon.toggle.enabled', 'Enable or disable'],
+    ['urls.yank', 'Copy current URL'],
+    ['zoom.in', 'Zoom-in'],
+    ['zoom.out', 'Zoom-out'],
+    ['zoom.neutral', 'Reset zoom level'],
+  ]
+];
+
+class KeymapsForm extends Component {
+
+  render() {
+    return <div className='keymap-fields'>
+      {
+        KeyMapFields.map((group, index) => {
+          return <div key={index} className='form-keymaps-form'>
+            {
+              group.map((field) => {
+                let name = field[0];
+                let label = field[1];
+                let value = this.props.value[name];
+                return <Input
+                  type='text' id={name} name={name} key={name}
+                  label={label} value={value}
+                  onChange={this.bindValue.bind(this)}
+                />;
+              })
+            }
+          </div>;
+        })
+      }
+    </div>;
+  }
+
+  bindValue(e) {
+    if (!this.props.onChange) {
+      return;
+    }
+
+    let next = Object.assign({}, this.props.value);
+    next[e.target.name] = e.target.value;
+
+    this.props.onChange(next);
+  }
+}
+
+export default KeymapsForm;
-- 
cgit v1.2.3


From f27d21908a2b402e3274288d4411a48160f38e4c Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sat, 25 Nov 2017 18:03:15 +0900
Subject: load settiongs from form

---
 src/settings/actions/setting.js               |  12 ++-
 src/settings/components/form/keymaps-form.jsx |  38 ++++----
 src/shared/default-settings.js                | 131 --------------------------
 src/shared/settings/default.js                | 131 ++++++++++++++++++++++++++
 src/shared/settings/values.js                 |  35 +++++++
 5 files changed, 195 insertions(+), 152 deletions(-)
 delete mode 100644 src/shared/default-settings.js
 create mode 100644 src/shared/settings/default.js
 create mode 100644 src/shared/settings/values.js

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js
index fa158a3..1d4ef34 100644
--- a/src/settings/actions/setting.js
+++ b/src/settings/actions/setting.js
@@ -1,6 +1,7 @@
 import actions from 'settings/actions';
 import messages from 'shared/messages';
-import DefaultSettings from 'shared/default-settings';
+import DefaultSettings from 'shared/settings/default';
+import * as settingsValues from 'shared/settings/values';
 
 const load = () => {
   return browser.storage.local.get('settings').then(({ settings }) => {
@@ -24,12 +25,19 @@ const save = (settings) => {
 };
 
 const set = (settings) => {
+  let value = JSON.parse(DefaultSettings.json);
+  if (settings.source === 'json') {
+    value = settingsValues.fromJson(settings.json);
+  } else if (settings.source === 'form') {
+    value = settingsValues.fromForm(settings.form);
+  }
+
   return {
     type: actions.SETTING_SET_SETTINGS,
     source: settings.source,
     json: settings.json,
     form: settings.form,
-    value: JSON.parse(settings.json),
+    value,
   };
 };
 
diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index a112979..a827e4e 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -4,29 +4,29 @@ import Input from '../ui/input';
 
 const KeyMapFields = [
   [
-    ['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.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 leftmost'],
     ['scroll.end', 'Scroll last'],
-    ['scroll.pages?{count:-0.5}', 'Scroll up by half of screen'],
-    ['scroll.pages?{count:0.5}', 'Scroll up by half of screen'],
-    ['scroll.pages?{count:-1}', 'Scroll up by a screen'],
-    ['scroll.pages?{count:1}', 'Scroll up by a screen'],
+    ['scroll.pages?{"count":-0.5}', 'Scroll up by half of screen'],
+    ['scroll.pages?{"count":0.5}', 'Scroll up by half of screen'],
+    ['scroll.pages?{"count":-1}', 'Scroll up by a screen'],
+    ['scroll.pages?{"count":1}', 'Scroll up by a screen'],
   ], [
     ['tabs.close', 'Close a tab'],
     ['tabs.reopen', 'Reopen closed tab'],
-    ['tabs.next?{count:1}', 'Select next Tab'],
-    ['tabs.prev?{count:1}', 'Select prev Tab'],
+    ['tabs.next?{"count":1}', 'Select next Tab'],
+    ['tabs.prev?{"count":1}', 'Select prev Tab'],
     ['tabs.first', 'Select first tab'],
     ['tabs.last', 'Select last tab'],
-    ['tabs.reload?{cache:true}', 'Reload current tab'],
+    ['tabs.reload?{"cache":true}', 'Reload current tab'],
     ['tabs.pin.toggle', 'Toggle pinned state'],
     ['tabs.duplicate', 'Dupplicate a tab'],
   ], [
-    ['follow.start?{newTab:false}', 'Follow a link'],
-    ['follow.start?{newTab:true}', 'Follow a link in new tab'],
+    ['follow.start?{"newTab":false}', 'Follow a link'],
+    ['follow.start?{"newTab":true}', 'Follow a link in new tab'],
     ['navigate.histories.prev', 'Go back in histories'],
     ['navigate.histories.next', 'Go forward in histories'],
     ['navigate.link.next', 'Open next link'],
@@ -39,12 +39,12 @@ const KeyMapFields = [
     ['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.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'],
   ], [
     ['addon.toggle.enabled', 'Enable or disable'],
diff --git a/src/shared/default-settings.js b/src/shared/default-settings.js
deleted file mode 100644
index 218390b..0000000
--- a/src/shared/default-settings.js
+++ /dev/null
@@ -1,131 +0,0 @@
-export default {
-  source: 'json',
-  json: `{
-  "keymaps": {
-    "0": { "type": "scroll.home" },
-    ":": { "type": "command.show" },
-    "o": { "type": "command.show.open", "alter": false },
-    "O": { "type": "command.show.open", "alter": true },
-    "t": { "type": "command.show.tabopen", "alter": false },
-    "T": { "type": "command.show.tabopen", "alter": true },
-    "w": { "type": "command.show.winopen", "alter": false },
-    "W": { "type": "command.show.winopen", "alter": true },
-    "b": { "type": "command.show.buffer" },
-    "k": { "type": "scroll.vertically", "count": -1 },
-    "j": { "type": "scroll.vertically", "count": 1 },
-    "h": { "type": "scroll.horizonally", "count": -1 },
-    "l": { "type": "scroll.horizonally", "count": 1 },
-    "<C-Y>": { "type": "scroll.vertically", "count": -1 },
-    "<C-E>": { "type": "scroll.vertically", "count": 1 },
-    "<C-U>": { "type": "scroll.pages", "count": -0.5 },
-    "<C-D>": { "type": "scroll.pages", "count": 0.5 },
-    "<C-B>": { "type": "scroll.pages", "count": -1 },
-    "<C-F>": { "type": "scroll.pages", "count": 1 },
-    "gg": { "type": "scroll.top" },
-    "G": { "type": "scroll.bottom" },
-    "$": { "type": "scroll.end" },
-    "d": { "type": "tabs.close" },
-    "u": { "type": "tabs.reopen" },
-    "K": { "type": "tabs.prev", "count": 1 },
-    "J": { "type": "tabs.next", "count": 1 },
-    "g0": { "type": "tabs.first" },
-    "g$": { "type": "tabs.last" },
-    "r": { "type": "tabs.reload", "cache": false },
-    "R": { "type": "tabs.reload", "cache": true },
-    "zp": { "type": "tabs.pin.toggle" },
-    "zd": { "type": "tabs.duplicate" },
-    "zi": { "type": "zoom.in" },
-    "zo": { "type": "zoom.out" },
-    "zz": { "type": "zoom.neutral" },
-    "f": { "type": "follow.start", "newTab": false },
-    "F": { "type": "follow.start", "newTab": true },
-    "H": { "type": "navigate.history.prev" },
-    "L": { "type": "navigate.history.next" },
-    "[[": { "type": "navigate.link.prev" },
-    "]]": { "type": "navigate.link.next" },
-    "gu": { "type": "navigate.parent" },
-    "gU": { "type": "navigate.root" },
-    "y": { "type": "urls.yank" },
-    "/": { "type": "find.start" },
-    "n": { "type": "find.next" },
-    "N": { "type": "find.prev" },
-    "<S-Esc>": { "type": "addon.toggle.enabled" }
-  },
-  "search": {
-    "default": "google",
-    "engines": {
-      "google": "https://google.com/search?q={}",
-      "yahoo": "https://search.yahoo.com/search?p={}",
-      "bing": "https://www.bing.com/search?q={}",
-      "duckduckgo": "https://duckduckgo.com/?q={}",
-      "twitter": "https://twitter.com/search?q={}",
-      "wikipedia": "https://en.wikipedia.org/w/index.php?search={}"
-    }
-  }
-}`,
-
-  'form': {
-    'keymaps': {
-      'scroll.vertically?{count:-1}': 'j',
-      'scroll.vertically?{count:1}': 'k',
-      'scroll.horizonally?{count:-1}': 'h',
-      'scroll.horizonally?{count:1}': 'l',
-      'scroll.home': '0',
-      'scroll.end': '$',
-      'scroll.pages?{count:-0.5}': '<C-U>',
-      'scroll.pages?{count:0.5}': '<C-D>',
-      'scroll.pages?{count:-1}': '<C-B>',
-      'scroll.pages?{count:1}': '<C-F>',
-
-      'tabs.close': 'd',
-      'tabs.reopen': 'u',
-      'tabs.next?{count:1}': 'J',
-      'tabs.prev?{count:1}': 'K',
-      'tabs.first': 'g0',
-      'tabs.last': 'g$',
-      'tabs.reload?{cache:true}': 'r',
-      'tabs.pin.toggle': 'zp',
-      'tabs.duplicate': 'zd',
-
-      'follow.start?{newTab:false}': 'f',
-      'follow.start?{newTab:true}': 'F',
-      'navigate.histories.prev': 'H',
-      'navigate.histories.next': 'L',
-      'navigate.link.next': ']]',
-      'navigate.link.prev': '[[',
-      'navigate.parent': 'gu',
-      'navigate.root': 'gU',
-
-      'find.start': '/',
-      'find.next': 'n',
-      'find.prev': 'N',
-
-      'command.show': ':',
-      'command.show.open?{alter:false}': 'o',
-      'command.show.open?{alter:true}': 'O',
-      'command.show.tabopen?{alter:false}': 't',
-      'command.show.tabopen?{alter:true}': 'T',
-      'command.show.winopen?{alter:false}': 'w',
-      'command.show.winopen?{alter:true}': 'W',
-      'command.show.buffer': 'b',
-
-      'addon.toggle.enabled': '<S-Esc>',
-      'urls.yank': 'y',
-      'zoom.in': 'zi',
-      'zoom.out': 'zo',
-      'zoom.neutral': 'zz',
-    },
-    'search': {
-      'default': 'google',
-      'engines': [
-        ['google', 'https,//google.com/search?q={}'],
-        ['yahoo', 'https,//search.yahoo.com/search?p={}'],
-        ['bing', 'https,//www.bing.com/search?q={}'],
-        ['duckduckgo', 'https,//duckduckgo.com/?q={}'],
-        ['twitter', 'https,//twitter.com/search?q={}'],
-        ['wikipedia', 'https,//en.wikipedia.org/w/index.php?search={}'],
-      ]
-    },
-    'blacklist': [],
-  }
-};
diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js
new file mode 100644
index 0000000..fc259b8
--- /dev/null
+++ b/src/shared/settings/default.js
@@ -0,0 +1,131 @@
+export default {
+  source: 'json',
+  json: `{
+  "keymaps": {
+    "0": { "type": "scroll.home" },
+    ":": { "type": "command.show" },
+    "o": { "type": "command.show.open", "alter": false },
+    "O": { "type": "command.show.open", "alter": true },
+    "t": { "type": "command.show.tabopen", "alter": false },
+    "T": { "type": "command.show.tabopen", "alter": true },
+    "w": { "type": "command.show.winopen", "alter": false },
+    "W": { "type": "command.show.winopen", "alter": true },
+    "b": { "type": "command.show.buffer" },
+    "k": { "type": "scroll.vertically", "count": -1 },
+    "j": { "type": "scroll.vertically", "count": 1 },
+    "h": { "type": "scroll.horizonally", "count": -1 },
+    "l": { "type": "scroll.horizonally", "count": 1 },
+    "<C-Y>": { "type": "scroll.vertically", "count": -1 },
+    "<C-E>": { "type": "scroll.vertically", "count": 1 },
+    "<C-U>": { "type": "scroll.pages", "count": -0.5 },
+    "<C-D>": { "type": "scroll.pages", "count": 0.5 },
+    "<C-B>": { "type": "scroll.pages", "count": -1 },
+    "<C-F>": { "type": "scroll.pages", "count": 1 },
+    "gg": { "type": "scroll.top" },
+    "G": { "type": "scroll.bottom" },
+    "$": { "type": "scroll.end" },
+    "d": { "type": "tabs.close" },
+    "u": { "type": "tabs.reopen" },
+    "K": { "type": "tabs.prev", "count": 1 },
+    "J": { "type": "tabs.next", "count": 1 },
+    "g0": { "type": "tabs.first" },
+    "g$": { "type": "tabs.last" },
+    "r": { "type": "tabs.reload", "cache": false },
+    "R": { "type": "tabs.reload", "cache": true },
+    "zp": { "type": "tabs.pin.toggle" },
+    "zd": { "type": "tabs.duplicate" },
+    "zi": { "type": "zoom.in" },
+    "zo": { "type": "zoom.out" },
+    "zz": { "type": "zoom.neutral" },
+    "f": { "type": "follow.start", "newTab": false },
+    "F": { "type": "follow.start", "newTab": true },
+    "H": { "type": "navigate.history.prev" },
+    "L": { "type": "navigate.history.next" },
+    "[[": { "type": "navigate.link.prev" },
+    "]]": { "type": "navigate.link.next" },
+    "gu": { "type": "navigate.parent" },
+    "gU": { "type": "navigate.root" },
+    "y": { "type": "urls.yank" },
+    "/": { "type": "find.start" },
+    "n": { "type": "find.next" },
+    "N": { "type": "find.prev" },
+    "<S-Esc>": { "type": "addon.toggle.enabled" }
+  },
+  "search": {
+    "default": "google",
+    "engines": {
+      "google": "https://google.com/search?q={}",
+      "yahoo": "https://search.yahoo.com/search?p={}",
+      "bing": "https://www.bing.com/search?q={}",
+      "duckduckgo": "https://duckduckgo.com/?q={}",
+      "twitter": "https://twitter.com/search?q={}",
+      "wikipedia": "https://en.wikipedia.org/w/index.php?search={}"
+    }
+  }
+}`,
+
+  'form': {
+    'keymaps': {
+      'scroll.vertically?{"count":1}': 'j',
+      'scroll.vertically?{"count":-1}': 'k',
+      'scroll.horizonally?{"count":-1}': 'h',
+      'scroll.horizonally?{"count":1}': 'l',
+      'scroll.home': '0',
+      'scroll.end': '$',
+      'scroll.pages?{"count":-0.5}': '<C-U>',
+      'scroll.pages?{"count":0.5}': '<C-D>',
+      'scroll.pages?{"count":-1}': '<C-B>',
+      'scroll.pages?{"count":1}': '<C-F>',
+
+      'tabs.close': 'd',
+      'tabs.reopen': 'u',
+      'tabs.next?{"count":1}': 'J',
+      'tabs.prev?{"count":1}': 'K',
+      'tabs.first': 'g0',
+      'tabs.last': 'g$',
+      'tabs.reload?{"cache":true}': 'r',
+      'tabs.pin.toggle': 'zp',
+      'tabs.duplicate': 'zd',
+
+      'follow.start?{"newTab":false}': 'f',
+      'follow.start?{"newTab":true}': 'F',
+      'navigate.histories.prev': 'H',
+      'navigate.histories.next': 'L',
+      'navigate.link.next': ']]',
+      'navigate.link.prev': '[[',
+      'navigate.parent': 'gu',
+      'navigate.root': 'gU',
+
+      'find.start': '/',
+      'find.next': 'n',
+      'find.prev': 'N',
+
+      'command.show': ':',
+      'command.show.open?{"alter":false}': 'o',
+      'command.show.open?{"alter":true}': 'O',
+      'command.show.tabopen?{"alter":false}': 't',
+      'command.show.tabopen?{"alter":true}': 'T',
+      'command.show.winopen?{"alter":false}': 'w',
+      'command.show.winopen?{"alter":true}': 'W',
+      'command.show.buffer': 'b',
+
+      'addon.toggle.enabled': '<S-Esc>',
+      'urls.yank': 'y',
+      'zoom.in': 'zi',
+      'zoom.out': 'zo',
+      'zoom.neutral': 'zz',
+    },
+    'search': {
+      'default': 'google',
+      'engines': [
+        ['google', 'https,//google.com/search?q={}'],
+        ['yahoo', 'https,//search.yahoo.com/search?p={}'],
+        ['bing', 'https,//www.bing.com/search?q={}'],
+        ['duckduckgo', 'https,//duckduckgo.com/?q={}'],
+        ['twitter', 'https,//twitter.com/search?q={}'],
+        ['wikipedia', 'https,//en.wikipedia.org/w/index.php?search={}'],
+      ]
+    },
+    'blacklist': [],
+  }
+};
diff --git a/src/shared/settings/values.js b/src/shared/settings/values.js
new file mode 100644
index 0000000..d86cfdc
--- /dev/null
+++ b/src/shared/settings/values.js
@@ -0,0 +1,35 @@
+const operationFromName = (name) => {
+  let [type, argStr] = name.split('?');
+  let args = {};
+  if (argStr) {
+    args = JSON.parse(argStr);
+  }
+  return Object.assign({ type }, args);
+};
+
+const fromJson = (json) => {
+  return JSON.parse(json);
+};
+
+const fromForm = (form) => {
+  let keymaps = {};
+  for (let name of Object.keys(form.keymaps)) {
+    let keys = form.keymaps[name];
+    keymaps[keys] = operationFromName(name);
+  }
+
+  let engines = {};
+  for (let { name, url } of form.search.engines) {
+    engines[name] = url;
+  }
+  let search = {
+    default: form.search.default,
+    engines,
+  };
+
+  let blacklist = form.blacklist;
+
+  return { keymaps, search, blacklist };
+};
+
+export { fromJson, fromForm };
-- 
cgit v1.2.3


From 2c46e9d448142c84b802ef8e0e1af53524dc4759 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sat, 25 Nov 2017 22:58:10 +0900
Subject: fix keymap form

---
 src/settings/components/form/keymaps-form.jsx | 4 ++--
 src/shared/settings/default.js                | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index a827e4e..8e93c3f 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -27,8 +27,8 @@ const KeyMapFields = [
   ], [
     ['follow.start?{"newTab":false}', 'Follow a link'],
     ['follow.start?{"newTab":true}', 'Follow a link in new tab'],
-    ['navigate.histories.prev', 'Go back in histories'],
-    ['navigate.histories.next', 'Go forward in histories'],
+    ['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'],
diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js
index fc259b8..69238e3 100644
--- a/src/shared/settings/default.js
+++ b/src/shared/settings/default.js
@@ -89,8 +89,8 @@ export default {
 
       'follow.start?{"newTab":false}': 'f',
       'follow.start?{"newTab":true}': 'F',
-      'navigate.histories.prev': 'H',
-      'navigate.histories.next': 'L',
+      'navigate.history.prev': 'H',
+      'navigate.history.next': 'L',
       'navigate.link.next': ']]',
       'navigate.link.prev': '[[',
       'navigate.parent': 'gu',
-- 
cgit v1.2.3


From 705c47bc6379a8d1fea4f775a6af98c97d4eab81 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sun, 26 Nov 2017 12:34:49 +0900
Subject: add KeymapsForm test

---
 src/settings/components/form/keymaps-form.jsx      |  6 ++-
 .../settings/components/form/keymaps-form.test.jsx | 53 ++++++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletion(-)
 create mode 100644 test/settings/components/form/keymaps-form.test.jsx

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index 8e93c3f..f64320c 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -58,6 +58,10 @@ const KeyMapFields = [
 class KeymapsForm extends Component {
 
   render() {
+    let values = this.props.value;
+    if (!values) {
+      values = {};
+    }
     return <div className='keymap-fields'>
       {
         KeyMapFields.map((group, index) => {
@@ -66,7 +70,7 @@ class KeymapsForm extends Component {
               group.map((field) => {
                 let name = field[0];
                 let label = field[1];
-                let value = this.props.value[name];
+                let value = values[name];
                 return <Input
                   type='text' id={name} name={name} key={name}
                   label={label} value={value}
diff --git a/test/settings/components/form/keymaps-form.test.jsx b/test/settings/components/form/keymaps-form.test.jsx
new file mode 100644
index 0000000..e9f9359
--- /dev/null
+++ b/test/settings/components/form/keymaps-form.test.jsx
@@ -0,0 +1,53 @@
+import { expect } from 'chai';
+import { h, render } from 'preact';
+import KeymapsForm from 'settings/components/form/keymaps-form'
+
+describe("settings/form/KeymapsForm", () => {
+  beforeEach(() => {
+    document.body.innerHTML = '';
+  });
+
+  describe('render', () => {
+    it('renders KeymapsForm', () => {
+      render(<KeymapsForm value={{
+        'scroll.vertically?{"count":1}': 'j',
+        'scroll.vertically?{"count":-1}': 'k',
+      }} />, document.body);
+
+      let inputj = document.getElementById('scroll.vertically?{"count":1}');
+      let inputk = document.getElementById('scroll.vertically?{"count":-1}');
+
+      expect(inputj.value).to.equal('j');
+      expect(inputk.value).to.equal('k');
+    });
+
+    it('renders blank value', () => {
+      render(<KeymapsForm />, document.body);
+
+      let inputj = document.getElementById('scroll.vertically?{"count":1}');
+      let inputk = document.getElementById('scroll.vertically?{"count":-1}');
+
+      expect(inputj.value).to.be.empty;
+      expect(inputk.value).to.be.empty;
+    });
+  });
+
+  describe('onChange event', () => {
+    it('invokes onChange event on edit', (done) => {
+      render(<KeymapsForm
+        value={{
+          'scroll.vertically?{"count":1}': 'j',
+          'scroll.vertically?{"count":-1}': 'k',
+        }}
+        onChange={value => {
+          expect(value['scroll.vertically?{"count":1}']).to.equal('jjj');
+
+          done();
+        }} />, document.body);
+
+      let input = document.getElementById('scroll.vertically?{"count":1}');
+      input.value = 'jjj';
+      input.dispatchEvent(new Event('change'))
+    });
+  });
+});
-- 
cgit v1.2.3


From 8c79b2c5e7e3b25ce5eb0fa94e856b5b9b1f77f1 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sun, 26 Nov 2017 21:06:39 +0900
Subject: fix keymap field

---
 src/settings/components/form/keymaps-form.jsx  | 4 ++--
 src/settings/components/form/keymaps-form.scss | 8 +++++---
 2 files changed, 7 insertions(+), 5 deletions(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index f64320c..8ec0456 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -62,10 +62,10 @@ class KeymapsForm extends Component {
     if (!values) {
       values = {};
     }
-    return <div className='keymap-fields'>
+    return <div className='form-keymaps-form'>
       {
         KeyMapFields.map((group, index) => {
-          return <div key={index} className='form-keymaps-form'>
+          return <div key={index} className='form-keymaps-form-field-group'>
             {
               group.map((field) => {
                 let name = field[0];
diff --git a/src/settings/components/form/keymaps-form.scss b/src/settings/components/form/keymaps-form.scss
index 3a83910..1a4e5cd 100644
--- a/src/settings/components/form/keymaps-form.scss
+++ b/src/settings/components/form/keymaps-form.scss
@@ -1,9 +1,11 @@
 .form-keymaps-form {
   column-count: 3;
-  .keymap-fields-group {
+
+  &-field-group {
     margin-top: 24px;
   }
-  .keymap-fields-group:first-of-type {
-    margin-top: 0;
+
+  &-field-group:first-of-type {
+    margin-top: 24px;
   }
 }
-- 
cgit v1.2.3


From 6b7fad3e494ddca1133fd9e9e6c7ebe7479b7f03 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sun, 26 Nov 2017 21:54:27 +0900
Subject: fix form key bindings

---
 src/settings/components/form/keymaps-form.jsx | 6 ++++--
 src/shared/settings/default.js                | 2 ++
 2 files changed, 6 insertions(+), 2 deletions(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index 8ec0456..ac24689 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -8,8 +8,10 @@ const KeyMapFields = [
     ['scroll.vertically?{"count":-1}', 'Scroll up'],
     ['scroll.horizonally?{"count":-1}', 'Scroll left'],
     ['scroll.horizonally?{"count":1}', 'Scroll right'],
-    ['scroll.home', 'Scroll leftmost'],
-    ['scroll.end', 'Scroll last'],
+    ['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 up by half of screen'],
     ['scroll.pages?{"count":-1}', 'Scroll up by a screen'],
diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js
index 71465c9..527725a 100644
--- a/src/shared/settings/default.js
+++ b/src/shared/settings/default.js
@@ -70,6 +70,8 @@ export default {
       'scroll.horizonally?{"count":1}': 'l',
       'scroll.home': '0',
       'scroll.end': '$',
+      'scroll.top': 'gg',
+      'scroll.bottom': 'G',
       'scroll.pages?{"count":-0.5}': '<C-U>',
       'scroll.pages?{"count":0.5}': '<C-D>',
       'scroll.pages?{"count":-1}': '<C-B>',
-- 
cgit v1.2.3


From 6821372fc71779b458eed52f614d5a15571129d0 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sun, 26 Nov 2017 21:59:29 +0900
Subject: fix form key bindings

---
 src/settings/components/form/keymaps-form.jsx | 3 ++-
 src/shared/settings/default.js                | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index ac24689..f99318f 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -23,7 +23,8 @@ const KeyMapFields = [
     ['tabs.prev?{"count":1}', 'Select prev Tab'],
     ['tabs.first', 'Select first tab'],
     ['tabs.last', 'Select last tab'],
-    ['tabs.reload?{"cache":true}', 'Reload current tab'],
+    ['tabs.reload?{"cache":false}', 'Reload current tab'],
+    ['tabs.reload?{"cache":true}', 'Reload with no caches'],
     ['tabs.pin.toggle', 'Toggle pinned state'],
     ['tabs.duplicate', 'Dupplicate a tab'],
   ], [
diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js
index 527725a..14ed548 100644
--- a/src/shared/settings/default.js
+++ b/src/shared/settings/default.js
@@ -83,7 +83,8 @@ export default {
       'tabs.prev?{"count":1}': 'K',
       'tabs.first': 'g0',
       'tabs.last': 'g$',
-      'tabs.reload?{"cache":true}': 'r',
+      'tabs.reload?{"cache":false}': 'r',
+      'tabs.reload?{"cache":true}': 'R',
       'tabs.pin.toggle': 'zp',
       'tabs.duplicate': 'zd',
 
-- 
cgit v1.2.3


From e1060f9bb218202d13a4382584f220d47173194c Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Tue, 28 Nov 2017 20:45:22 +0900
Subject: remove default form settings

---
 src/settings/components/form/keymaps-form.jsx |  4 ++
 src/settings/components/index.jsx             | 15 +++++-
 src/shared/settings/default.js                | 68 ---------------------------
 src/shared/settings/values.js                 | 14 +++---
 test/shared/settings/values.test.js           |  4 +-
 5 files changed, 27 insertions(+), 78 deletions(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index f99318f..f3b6abe 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -58,6 +58,8 @@ const KeyMapFields = [
   ]
 ];
 
+const AllowdOps = [].concat(...KeyMapFields.map(group => group.map(e => e[0])));
+
 class KeymapsForm extends Component {
 
   render() {
@@ -99,4 +101,6 @@ class KeymapsForm extends Component {
   }
 }
 
+KeymapsForm.AllowdOps = AllowdOps;
+
 export default KeymapsForm;
diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx
index 3961982..38f7db8 100644
--- a/src/settings/components/index.jsx
+++ b/src/settings/components/index.jsx
@@ -123,6 +123,18 @@ class SettingsComponent extends Component {
     }
   }
 
+  validateValue(e) {
+    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;
+  }
+
   bindForm(name, value) {
     let next = Object.assign({}, this.state, {
       settings: Object.assign({}, this.state.settings, {
@@ -164,7 +176,8 @@ class SettingsComponent extends Component {
         return;
       }
       next.settings.form =
-        settingsValues.formFromJson(this.state.settings.json);
+        settingsValues.formFromJson(
+          this.state.settings.json, KeymapsForm.AllowdOps);
     }
     next.settings.source = to;
 
diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js
index 14ed548..d187565 100644
--- a/src/shared/settings/default.js
+++ b/src/shared/settings/default.js
@@ -61,72 +61,4 @@ export default {
     }
   }
 }`,
-
-  'form': {
-    'keymaps': {
-      'scroll.vertically?{"count":1}': 'j',
-      'scroll.vertically?{"count":-1}': 'k',
-      'scroll.horizonally?{"count":-1}': 'h',
-      'scroll.horizonally?{"count":1}': 'l',
-      'scroll.home': '0',
-      'scroll.end': '$',
-      'scroll.top': 'gg',
-      'scroll.bottom': 'G',
-      'scroll.pages?{"count":-0.5}': '<C-U>',
-      'scroll.pages?{"count":0.5}': '<C-D>',
-      'scroll.pages?{"count":-1}': '<C-B>',
-      'scroll.pages?{"count":1}': '<C-F>',
-
-      'tabs.close': 'd',
-      'tabs.reopen': 'u',
-      'tabs.next?{"count":1}': 'J',
-      'tabs.prev?{"count":1}': 'K',
-      'tabs.first': 'g0',
-      'tabs.last': 'g$',
-      'tabs.reload?{"cache":false}': 'r',
-      'tabs.reload?{"cache":true}': 'R',
-      'tabs.pin.toggle': 'zp',
-      'tabs.duplicate': 'zd',
-
-      'follow.start?{"newTab":false}': 'f',
-      'follow.start?{"newTab":true}': 'F',
-      'navigate.history.prev': 'H',
-      'navigate.history.next': 'L',
-      'navigate.link.next': ']]',
-      'navigate.link.prev': '[[',
-      'navigate.parent': 'gu',
-      'navigate.root': 'gU',
-
-      'find.start': '/',
-      'find.next': 'n',
-      'find.prev': 'N',
-
-      'command.show': ':',
-      'command.show.open?{"alter":false}': 'o',
-      'command.show.open?{"alter":true}': 'O',
-      'command.show.tabopen?{"alter":false}': 't',
-      'command.show.tabopen?{"alter":true}': 'T',
-      'command.show.winopen?{"alter":false}': 'w',
-      'command.show.winopen?{"alter":true}': 'W',
-      'command.show.buffer': 'b',
-
-      'addon.toggle.enabled': '<S-Esc>',
-      'urls.yank': 'y',
-      'zoom.in': 'zi',
-      'zoom.out': 'zo',
-      'zoom.neutral': 'zz',
-    },
-    'search': {
-      'default': 'google',
-      'engines': [
-        ['google', 'https,//google.com/search?q={}'],
-        ['yahoo', 'https,//search.yahoo.com/search?p={}'],
-        ['bing', 'https,//www.bing.com/search?q={}'],
-        ['duckduckgo', 'https,//duckduckgo.com/?q={}'],
-        ['twitter', 'https,//twitter.com/search?q={}'],
-        ['wikipedia', 'https,//en.wikipedia.org/w/index.php?search={}'],
-      ]
-    },
-    'blacklist': [],
-  }
 };
diff --git a/src/shared/settings/values.js b/src/shared/settings/values.js
index 4482fbb..4e55fa0 100644
--- a/src/shared/settings/values.js
+++ b/src/shared/settings/values.js
@@ -1,5 +1,3 @@
-import DefaultSettings from './default';
-
 const operationFromFormName = (name) => {
   let [type, argStr] = name.split('?');
   let args = {};
@@ -55,16 +53,16 @@ const jsonFromValue = (value) => {
   return JSON.stringify(value, undefined, 2);
 };
 
-const formFromValue = (value) => {
-
+const formFromValue = (value, allowedOps) => {
   let keymaps = undefined;
+
   if (value.keymaps) {
-    let allowedOps = new Set(Object.keys(DefaultSettings.form.keymaps));
+    let allowedSet = new Set(allowedOps);
 
     keymaps = {};
     for (let keys of Object.keys(value.keymaps)) {
       let op = operationToFormName(value.keymaps[keys]);
-      if (allowedOps.has(op)) {
+      if (allowedSet.has(op)) {
         keymaps[op] = keys;
       }
     }
@@ -89,9 +87,9 @@ const jsonFromForm = (form) => {
   return jsonFromValue(valueFromForm(form));
 };
 
-const formFromJson = (json) => {
+const formFromJson = (json, allowedOps) => {
   let value = valueFromJson(json);
-  return formFromValue(value);
+  return formFromValue(value, allowedOps);
 };
 
 export {
diff --git a/test/shared/settings/values.test.js b/test/shared/settings/values.test.js
index 2c222b6..2632cd7 100644
--- a/test/shared/settings/values.test.js
+++ b/test/shared/settings/values.test.js
@@ -98,9 +98,11 @@ describe("settings values", () => {
         search: { default: 'google', engines: { google: 'https://google.com/search?q={}' }},
         blacklist: [ '*.slack.com']
       };
-      let form = values.formFromValue(value);
+      let allowed = ['scroll.vertically?{"count":1}', 'scroll.home' ];
+      let form = values.formFromValue(value, allowed);
 
       expect(form.keymaps).to.have.property('scroll.vertically?{"count":1}', 'j');
+      expect(form.keymaps).to.not.have.property('scroll.vertically?{"count":100}');
       expect(form.keymaps).to.have.property('scroll.home', '0');
       expect(Object.keys(form.keymaps)).to.have.lengthOf(2);
       expect(form.search).to.have.property('default', 'google');
-- 
cgit v1.2.3


From 2e67d9a667385acf2780fde417e8490a5dc5eb92 Mon Sep 17 00:00:00 2001
From: l4 <l4.foss@gmail.com>
Date: Thu, 28 Dec 2017 13:58:53 +0700
Subject: fix scroll settings typos

---
 src/settings/components/form/keymaps-form.jsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index f3b6abe..c399570 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -13,9 +13,9 @@ const KeyMapFields = [
     ['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 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 up by a screen'],
+    ['scroll.pages?{"count":1}', 'Scroll down by a screen'],
   ], [
     ['tabs.close', 'Close a tab'],
     ['tabs.reopen', 'Reopen closed tab'],
-- 
cgit v1.2.3


From 54a7662cd1e7372910e9ce81aae1a904f3b26c82 Mon Sep 17 00:00:00 2001
From: usk <usk@>
Date: Wed, 3 Jan 2018 07:19:25 +0900
Subject: open clipboard's URL in current/new tab

---
 QA.md                                         |  2 ++
 README.md                                     |  2 ++
 manifest.json                                 |  3 ++-
 src/content/actions/operation.js              |  2 ++
 src/content/urls.js                           | 26 +++++++++++++++++++++++++-
 src/settings/components/form/keymaps-form.jsx |  2 ++
 src/shared/operations.js                      |  3 ++-
 src/shared/settings/default.js                |  2 ++
 8 files changed, 39 insertions(+), 3 deletions(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/QA.md b/QA.md
index 1a0839e..1c06861 100644
--- a/QA.md
+++ b/QA.md
@@ -46,6 +46,8 @@ The behaviors of the console are tested in [Console section](#consoles).
 - [ ] <kbd>z</kbd><kbd>i</kbd>, <kbd>z</kbd><kbd>o</kbd>: zoom-in and zoom-out
 - [ ] <kbd>z</kbd><kbd>z</kbd>: set zoom level as default
 - [ ] <kbd>y</kbd>: yank current URL and show a message
+- [ ] <kbd>p</kbd>: open clipbord's URL in current tab
+- [ ] <kbd>P</kbd>: open clipbord's URL in new tab
 - [ ] Toggle enabled/disabled of plugin bu <kbd>Shift</kbd>+<kbd>Esc</kbd>
 
 ### Following links
diff --git a/README.md b/README.md
index fdc48d4..a249ada 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,8 @@ The default mappings are as follows:
 - <kbd>z</kbd><kbd>i</kbd>, <kbd>z</kbd><kbd>o</kbd>: zoom-in/zoom-out
 - <kbd>z</kbd><kbd>z</kbd>: Set default zoom level
 - <kbd>y</kbd>: copy URL in current tab
+- <kbd>p</kbd>: open clipbord's URL in current tab
+- <kbd>P</kbd>: open clipbord's URL in new tab
 - <kbd>Shift</kbd>+<kbd>Esc</kbd>: enable or disable the add-on in current tab.
 
 ### Console commands
diff --git a/manifest.json b/manifest.json
index 78479c2..02d8589 100644
--- a/manifest.json
+++ b/manifest.json
@@ -30,7 +30,8 @@
     "history",
     "sessions",
     "storage",
-    "tabs"
+    "tabs",
+    "clipboardRead"
   ],
   "web_accessible_resources": [
     "build/console.html",
diff --git a/src/content/actions/operation.js b/src/content/actions/operation.js
index 767f14b..0a5cd97 100644
--- a/src/content/actions/operation.js
+++ b/src/content/actions/operation.js
@@ -60,6 +60,8 @@ const exec = (operation) => {
       type: messages.CONSOLE_SHOW_INFO,
       text: 'Current url yanked',
     });
+  case operations.URLS_PASTE:
+    return urls.paste(window, operation.newTab ? operation.newTab : false);
   default:
     browser.runtime.sendMessage({
       type: messages.BACKGROUND_OPERATION,
diff --git a/src/content/urls.js b/src/content/urls.js
index 8f8a1ac..9b7b284 100644
--- a/src/content/urls.js
+++ b/src/content/urls.js
@@ -1,3 +1,5 @@
+import messages from 'shared/messages';
+
 const yank = (win) => {
   let input = win.document.createElement('input');
   win.document.body.append(input);
@@ -12,4 +14,26 @@ const yank = (win) => {
   input.remove();
 };
 
-export { yank };
+const paste = (win, newTab) => {
+  let textarea = win.document.createElement('textarea');
+  win.document.body.append(textarea);
+
+  textarea.style.position = 'fixed';
+  textarea.style.top = '-100px';
+  textarea.contentEditable = 'true';
+  textarea.focus();
+
+  if (win.document.execCommand('paste')) {
+    if (/^(https?|ftp):\/\//.test(textarea.textContent)) {
+      browser.runtime.sendMessage({
+        type: messages.OPEN_URL,
+        url: textarea.textContent,
+        newTab: newTab ? newTab : false,
+      });
+    }
+  }
+
+  textarea.remove();
+};
+
+export { yank, paste };
diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index c399570..eb77e52 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -52,6 +52,8 @@ const KeyMapFields = [
   ], [
     ['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'],
diff --git a/src/shared/operations.js b/src/shared/operations.js
index 4c221ba..7334369 100644
--- a/src/shared/operations.js
+++ b/src/shared/operations.js
@@ -49,8 +49,9 @@ export default {
   ZOOM_OUT: 'zoom.out',
   ZOOM_NEUTRAL: 'zoom.neutral',
 
-  // Url yank
+  // Url yank/paste
   URLS_YANK: 'urls.yank',
+  URLS_PASTE: 'urls.paste',
 
   // Find
   FIND_START: 'find.start',
diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js
index d187565..6b71717 100644
--- a/src/shared/settings/default.js
+++ b/src/shared/settings/default.js
@@ -44,6 +44,8 @@ export default {
     "gu": { "type": "navigate.parent" },
     "gU": { "type": "navigate.root" },
     "y": { "type": "urls.yank" },
+    "p": { "type": "urls.paste", "newTab": false },
+    "P": { "type": "urls.paste", "newTab": true },
     "/": { "type": "find.start" },
     "n": { "type": "find.next" },
     "N": { "type": "find.prev" },
-- 
cgit v1.2.3


From e3fdf742e7dc3fa3518746d185418a2e63ca2118 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Sat, 13 Jan 2018 22:42:39 +0900
Subject: add focus input key map

---
 src/settings/components/form/keymaps-form.jsx | 1 +
 src/shared/settings/default.js                | 1 +
 2 files changed, 2 insertions(+)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index eb77e52..e25107c 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -36,6 +36,7 @@ const KeyMapFields = [
     ['navigate.link.prev', 'Open previous link'],
     ['navigate.parent', 'Go to parent directory'],
     ['navigate.root', 'Go to root directory'],
+    ['focus.input', 'Focus input'],
   ], [
     ['find.start', 'Start find mode'],
     ['find.next', 'Find next word'],
diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js
index 0c3f0d9..4ad81c4 100644
--- a/src/shared/settings/default.js
+++ b/src/shared/settings/default.js
@@ -43,6 +43,7 @@ export default {
     "]]": { "type": "navigate.link.next" },
     "gu": { "type": "navigate.parent" },
     "gU": { "type": "navigate.root" },
+    "gi": { "type": "focus.input" },
     "y": { "type": "urls.yank" },
     "p": { "type": "urls.paste", "newTab": false },
     "P": { "type": "urls.paste", "newTab": true },
-- 
cgit v1.2.3


From f55f0bfd98c9d6f3c41c8601e48ac9c73c5c0d38 Mon Sep 17 00:00:00 2001
From: Ben Boeckel <mathstuf@gmail.com>
Date: Mon, 15 Jan 2018 15:18:56 -0500
Subject: keymaps-form: fix a typo

---
 src/settings/components/form/keymaps-form.jsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/settings/components/form/keymaps-form.jsx')

diff --git a/src/settings/components/form/keymaps-form.jsx b/src/settings/components/form/keymaps-form.jsx
index eb77e52..4e08616 100644
--- a/src/settings/components/form/keymaps-form.jsx
+++ b/src/settings/components/form/keymaps-form.jsx
@@ -26,7 +26,7 @@ const KeyMapFields = [
     ['tabs.reload?{"cache":false}', 'Reload current tab'],
     ['tabs.reload?{"cache":true}', 'Reload with no caches'],
     ['tabs.pin.toggle', 'Toggle pinned state'],
-    ['tabs.duplicate', 'Dupplicate a tab'],
+    ['tabs.duplicate', 'Duplicate a tab'],
   ], [
     ['follow.start?{"newTab":false}', 'Follow a link'],
     ['follow.start?{"newTab":true}', 'Follow a link in new tab'],
-- 
cgit v1.2.3

