From f27d21908a2b402e3274288d4411a48160f38e4c Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 25 Nov 2017 18:03:15 +0900 Subject: load settiongs from form --- src/shared/settings/default.js | 131 +++++++++++++++++++++++++++++++++++++++++ src/shared/settings/values.js | 35 +++++++++++ 2 files changed, 166 insertions(+) create mode 100644 src/shared/settings/default.js create mode 100644 src/shared/settings/values.js (limited to 'src/shared/settings') 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 }, + "": { "type": "scroll.vertically", "count": -1 }, + "": { "type": "scroll.vertically", "count": 1 }, + "": { "type": "scroll.pages", "count": -0.5 }, + "": { "type": "scroll.pages", "count": 0.5 }, + "": { "type": "scroll.pages", "count": -1 }, + "": { "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" }, + "": { "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}': '', + 'scroll.pages?{"count":0.5}': '', + 'scroll.pages?{"count":-1}': '', + 'scroll.pages?{"count":1}': '', + + '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': '', + '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 d15de42a75ee0f722e8779af1ecff8b51e59c56d Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 25 Nov 2017 22:14:28 +0900 Subject: settings helpers --- .eslintrc | 1 + src/settings/actions/setting.js | 4 +- src/shared/settings/values.js | 95 +++++++++++++++++++++++++----- test/shared/settings/values.test.js | 112 ++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 17 deletions(-) create mode 100644 test/shared/settings/values.test.js (limited to 'src/shared/settings') diff --git a/.eslintrc b/.eslintrc index 6717889..ab61dc7 100644 --- a/.eslintrc +++ b/.eslintrc @@ -44,6 +44,7 @@ "no-plusplus": "off", "no-ternary": "off", "no-undefined": "off", + "no-undef-init": "off", "no-unused-vars": ["error", { "varsIgnorePattern": "h" }], "no-use-before-define": "off", "no-warning-comments": "off", diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js index 1d4ef34..1d01fda 100644 --- a/src/settings/actions/setting.js +++ b/src/settings/actions/setting.js @@ -27,9 +27,9 @@ const save = (settings) => { const set = (settings) => { let value = JSON.parse(DefaultSettings.json); if (settings.source === 'json') { - value = settingsValues.fromJson(settings.json); + value = settingsValues.valueFromJson(settings.json); } else if (settings.source === 'form') { - value = settingsValues.fromForm(settings.form); + value = settingsValues.valueFromForm(settings.form); } return { diff --git a/src/shared/settings/values.js b/src/shared/settings/values.js index d86cfdc..4482fbb 100644 --- a/src/shared/settings/values.js +++ b/src/shared/settings/values.js @@ -1,4 +1,6 @@ -const operationFromName = (name) => { +import DefaultSettings from './default'; + +const operationFromFormName = (name) => { let [type, argStr] = name.split('?'); let args = {}; if (argStr) { @@ -7,29 +9,92 @@ const operationFromName = (name) => { return Object.assign({ type }, args); }; -const fromJson = (json) => { +const operationToFormName = (op) => { + let type = op.type; + let args = Object.assign({}, op); + delete args.type; + + if (Object.keys(args).length === 0) { + return type; + } + return op.type + '?' + JSON.stringify(args); +}; + +const valueFromJson = (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); +const valueFromForm = (form) => { + let keymaps = undefined; + if (form.keymaps) { + keymaps = {}; + for (let name of Object.keys(form.keymaps)) { + let keys = form.keymaps[name]; + keymaps[keys] = operationFromFormName(name); + } } - let engines = {}; - for (let { name, url } of form.search.engines) { - engines[name] = url; + let search = undefined; + if (form.search) { + search = { default: form.search.default }; + + if (form.search.engines) { + search.engines = {}; + for (let [name, url] of form.search.engines) { + search.engines[name] = url; + } + } } - let search = { - default: form.search.default, - engines, - }; let blacklist = form.blacklist; return { keymaps, search, blacklist }; }; -export { fromJson, fromForm }; +const jsonFromValue = (value) => { + return JSON.stringify(value, undefined, 2); +}; + +const formFromValue = (value) => { + + let keymaps = undefined; + if (value.keymaps) { + let allowedOps = new Set(Object.keys(DefaultSettings.form.keymaps)); + + keymaps = {}; + for (let keys of Object.keys(value.keymaps)) { + let op = operationToFormName(value.keymaps[keys]); + if (allowedOps.has(op)) { + keymaps[op] = keys; + } + } + } + + let search = undefined; + if (value.search) { + search = { default: value.search.default }; + if (value.search.engines) { + search.engines = Object.keys(value.search.engines).map((name) => { + return [name, value.search.engines[name]]; + }); + } + } + + let blacklist = value.blacklist; + + return { keymaps, search, blacklist }; +}; + +const jsonFromForm = (form) => { + return jsonFromValue(valueFromForm(form)); +}; + +const formFromJson = (json) => { + let value = valueFromJson(json); + return formFromValue(value); +}; + +export { + valueFromJson, valueFromForm, jsonFromValue, formFromValue, + jsonFromForm, formFromJson +}; diff --git a/test/shared/settings/values.test.js b/test/shared/settings/values.test.js new file mode 100644 index 0000000..2c222b6 --- /dev/null +++ b/test/shared/settings/values.test.js @@ -0,0 +1,112 @@ +import { expect } from 'chai'; +import * as values from 'shared/settings/values'; + +describe("settings values", () => { + describe('valueFromJson', () => { + it('return object from json string', () => { + let json = `{ + "keymaps": { "0": {"type": "scroll.home"}}, + "search": { "default": "google", "engines": { "google": "https://google.com/search?q={}" }}, + "blacklist": [ "*.slack.com"] + }`; + let value = values.valueFromJson(json); + + expect(value.keymaps).to.deep.equal({ 0: {type: "scroll.home"}}); + expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); + expect(value.blacklist).to.deep.equal(["*.slack.com"]); + }); + }); + + describe('valueFromForm', () => { + it('returns value from form', () => { + let form = { + keymaps: { + 'scroll.vertically?{"count":1}': 'j', + 'scroll.home': '0', + }, + search: { + default: 'google', + engines: [['google', 'https://google.com/search?q={}']], + }, + blacklist: ['*.slack.com'], + }; + let value = values.valueFromForm(form); + + expect(value.keymaps).to.have.deep.property('j', { type: "scroll.vertically", count: 1 }); + expect(value.keymaps).to.have.deep.property('0', { type: "scroll.home" }); + expect(JSON.stringify(value.search)).to.deep.equal(JSON.stringify({ default: "google", engines: { google: "https://google.com/search?q={}"} })); + expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); + expect(value.blacklist).to.deep.equal(["*.slack.com"]); + }); + + it('convert from empty form', () => { + let form = {}; + let value = values.valueFromForm(form); + expect(value).to.not.have.key('keymaps'); + expect(value).to.not.have.key('search'); + expect(value).to.not.have.key('blacklist'); + }); + + it('override keymaps', () => { + let form = { + keymaps: { + 'scroll.vertically?{"count":1}': 'j', + 'scroll.vertically?{"count":-1}': 'j', + } + }; + let value = values.valueFromForm(form); + + expect(value.keymaps).to.have.key('j'); + }); + + it('override search engine', () => { + let form = { + search: { + default: 'google', + engines: [ + ['google', 'https://google.com/search?q={}'], + ['google', 'https://google.co.jp/search?q={}'], + ] + } + }; + let value = values.valueFromForm(form); + + expect(value.search.engines).to.have.property('google', 'https://google.co.jp/search?q={}'); + }); + }); + + describe('jsonFromValue', () => { + }); + + describe('formFromValue', () => { + it('convert empty value to form', () => { + let value = {}; + let form = values.formFromValue(value); + + expect(value).to.not.have.key('keymaps'); + expect(value).to.not.have.key('search'); + expect(value).to.not.have.key('blacklist'); + }); + + it('convert value to form', () => { + let value = { + keymaps: { + j: { type: 'scroll.vertically', count: 1 }, + JJ: { type: 'scroll.vertically', count: 100 }, + 0: { type: 'scroll.home' }, + }, + search: { default: 'google', engines: { google: 'https://google.com/search?q={}' }}, + blacklist: [ '*.slack.com'] + }; + let form = values.formFromValue(value); + + expect(form.keymaps).to.have.property('scroll.vertically?{"count":1}', 'j'); + 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'); + expect(form.search).to.have.deep.property('engines', [['google', 'https://google.com/search?q={}']]); + expect(form.blacklist).to.have.lengthOf(1); + expect(form.blacklist).to.include('*.slack.com'); + }); + }); +}); -- cgit v1.2.3 From 2c46e9d448142c84b802ef8e0e1af53524dc4759 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka 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/shared/settings') 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 c934550a020259ae3c5fc8b05eca7fc7a0fb54f4 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 26 Nov 2017 20:19:14 +0900 Subject: remove / keymaps --- src/shared/settings/default.js | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/shared/settings') diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js index 69238e3..71465c9 100644 --- a/src/shared/settings/default.js +++ b/src/shared/settings/default.js @@ -15,8 +15,6 @@ export default { "j": { "type": "scroll.vertically", "count": 1 }, "h": { "type": "scroll.horizonally", "count": -1 }, "l": { "type": "scroll.horizonally", "count": 1 }, - "": { "type": "scroll.vertically", "count": -1 }, - "": { "type": "scroll.vertically", "count": 1 }, "": { "type": "scroll.pages", "count": -0.5 }, "": { "type": "scroll.pages", "count": 0.5 }, "": { "type": "scroll.pages", "count": -1 }, -- cgit v1.2.3 From 6b7fad3e494ddca1133fd9e9e6c7ebe7479b7f03 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka 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/shared/settings') 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}': '', 'scroll.pages?{"count":0.5}': '', 'scroll.pages?{"count":-1}': '', -- cgit v1.2.3 From 6821372fc71779b458eed52f614d5a15571129d0 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka 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/shared/settings') 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 50cc126e08056b4f5191f603c01f0e9951692696 Mon Sep 17 00:00:00 2001 From: Daniel Campoverde Date: Sun, 5 Nov 2017 18:04:46 -0500 Subject: Dummy selectPrevSelTab implementation --- src/background/actions/operation.js | 2 ++ src/background/tabs.js | 18 ++++++++++++++++-- src/shared/operations.js | 1 + src/shared/settings/default.js | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'src/shared/settings') diff --git a/src/background/actions/operation.js b/src/background/actions/operation.js index 1e4990c..cfee868 100644 --- a/src/background/actions/operation.js +++ b/src/background/actions/operation.js @@ -27,6 +27,8 @@ const exec = (operation, tab) => { return tabs.selectFirstTab(); case operations.TAB_LAST: return tabs.selectLastTab(); + case operations.TAB_PREV_SEL: + return tabs.selectPrevSelTab(); case operations.TAB_RELOAD: return tabs.reload(tab, operation.cache); case operations.TAB_PIN: diff --git a/src/background/tabs.js b/src/background/tabs.js index d641616..ce48eda 100644 --- a/src/background/tabs.js +++ b/src/background/tabs.js @@ -1,3 +1,6 @@ +// var prevSelTab = null; +var prevSelTab = 0; + const closeTab = (id) => { return browser.tabs.remove(id); }; @@ -93,6 +96,17 @@ const selectLastTab = () => { }); }; +const selectPrevSelTab = () => { + if (prevSelTab != null) { + return browser.tabs.query({ currentWindow: true }).then((tabs) => { + let id = tabs[prevSelTab].id; + return browser.tabs.update(id, { active: true }); + }); + } else { + // some error message + } +}; + const reload = (current, cache) => { return browser.tabs.reload( current.id, @@ -117,6 +131,6 @@ const duplicate = (id) => { export { closeTab, reopenTab, selectAt, selectByKeyword, getCompletions, - selectPrevTab, selectNextTab, selectFirstTab, selectLastTab, reload, - updateTabPinned, toggleTabPinned, duplicate + selectPrevTab, selectNextTab, selectFirstTab, selectLastTab, selectPrevSelTab, + reload, updateTabPinned, toggleTabPinned, duplicate }; diff --git a/src/shared/operations.js b/src/shared/operations.js index 4c221ba..235793a 100644 --- a/src/shared/operations.js +++ b/src/shared/operations.js @@ -38,6 +38,7 @@ export default { TAB_NEXT: 'tabs.next', TAB_FIRST: 'tabs.first', TAB_LAST: 'tabs.last', + TAB_PREV_SEL: 'tabs.prevsel', TAB_RELOAD: 'tabs.reload', TAB_PIN: 'tabs.pin', TAB_UNPIN: 'tabs.unpin', diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js index 69238e3..44ac5f4 100644 --- a/src/shared/settings/default.js +++ b/src/shared/settings/default.js @@ -30,6 +30,7 @@ export default { "J": { "type": "tabs.next", "count": 1 }, "g0": { "type": "tabs.first" }, "g$": { "type": "tabs.last" }, + "gl": { "type": "tabs.prevsel" }, "r": { "type": "tabs.reload", "cache": false }, "R": { "type": "tabs.reload", "cache": true }, "zp": { "type": "tabs.pin.toggle" }, -- cgit v1.2.3 From bab0616f1171cb3d70a11517afa5564f7e11addb Mon Sep 17 00:00:00 2001 From: Daniel Campoverde Date: Sun, 5 Nov 2017 18:47:20 -0500 Subject: Default mapping for TAB_PREV_SEL operation --- src/shared/settings/default.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/shared/settings') diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js index 44ac5f4..a9c363b 100644 --- a/src/shared/settings/default.js +++ b/src/shared/settings/default.js @@ -30,7 +30,7 @@ export default { "J": { "type": "tabs.next", "count": 1 }, "g0": { "type": "tabs.first" }, "g$": { "type": "tabs.last" }, - "gl": { "type": "tabs.prevsel" }, + "": { "type": "tabs.prevsel" }, "r": { "type": "tabs.reload", "cache": false }, "R": { "type": "tabs.reload", "cache": true }, "zp": { "type": "tabs.pin.toggle" }, -- cgit v1.2.3 From e1060f9bb218202d13a4382584f220d47173194c Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka 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/shared/settings') 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}': '', - 'scroll.pages?{"count":0.5}': '', - 'scroll.pages?{"count":-1}': '', - 'scroll.pages?{"count":1}': '', - - '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': '', - '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 54a7662cd1e7372910e9ce81aae1a904f3b26c82 Mon Sep 17 00:00:00 2001 From: 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/shared/settings') 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). - [ ] zi, zo: zoom-in and zoom-out - [ ] zz: set zoom level as default - [ ] y: yank current URL and show a message +- [ ] p: open clipbord's URL in current tab +- [ ] P: open clipbord's URL in new tab - [ ] Toggle enabled/disabled of plugin bu Shift+Esc ### 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: - zi, zo: zoom-in/zoom-out - zz: Set default zoom level - y: copy URL in current tab +- p: open clipbord's URL in current tab +- P: open clipbord's URL in new tab - Shift+Esc: 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 fbdec04786e28bad45021bef4a74e7077e34282f Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Thu, 4 Jan 2018 18:55:24 +0900 Subject: move settings validator --- src/settings/components/index.jsx | 2 +- src/shared/settings/validator.js | 61 +++++++++++++++++++++++++ src/shared/validators/setting.js | 61 ------------------------- test/shared/settings/validator.test.js | 82 ++++++++++++++++++++++++++++++++++ test/shared/validators/setting.test.js | 82 ---------------------------------- 5 files changed, 144 insertions(+), 144 deletions(-) create mode 100644 src/shared/settings/validator.js delete mode 100644 src/shared/validators/setting.js create mode 100644 test/shared/settings/validator.test.js delete mode 100644 test/shared/validators/setting.test.js (limited to 'src/shared/settings') diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index 73520ca..074c4c7 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -5,7 +5,7 @@ import SearchForm from './form/search-form'; import KeymapsForm from './form/keymaps-form'; import BlacklistForm from './form/blacklist-form'; import * as settingActions from 'settings/actions/setting'; -import * as validator from 'shared/validators/setting'; +import * as validator from 'shared/settings/validator'; import * as settingsValues from 'shared/settings/values'; const DO_YOU_WANT_TO_CONTINUE = diff --git a/src/shared/settings/validator.js b/src/shared/settings/validator.js new file mode 100644 index 0000000..949ab29 --- /dev/null +++ b/src/shared/settings/validator.js @@ -0,0 +1,61 @@ +import operations from 'shared/operations'; + +const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist']; +const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { + return operations[key]; +}); + +const validateInvalidTopKeys = (settings) => { + let invalidKey = Object.keys(settings).find((key) => { + return !VALID_TOP_KEYS.includes(key); + }); + if (invalidKey) { + throw Error(`Unknown key: "${invalidKey}"`); + } +}; + +const validateKeymaps = (keymaps) => { + for (let key of Object.keys(keymaps)) { + let value = keymaps[key]; + if (!VALID_OPERATION_VALUES.includes(value.type)) { + throw Error(`Unknown operation: "${value.type}"`); + } + } +}; + +const validateSearch = (search) => { + let engines = search.engines; + for (let key of Object.keys(engines)) { + if (/\s/.test(key)) { + throw new Error( + `While space in search engine name is not allowed: "${key}"` + ); + } + let url = engines[key]; + if (!url.match(/{}/)) { + throw new Error(`No {}-placeholders in URL of "${key}"`); + } + if (url.match(/{}/g).length > 1) { + throw new Error(`Multiple {}-placeholders in URL of "${key}"`); + } + } + + if (!search.default) { + throw new Error(`Default engine is not set`); + } + if (!Object.keys(engines).includes(search.default)) { + throw new Error(`Default engine "${search.default}" not found`); + } +}; + +const validate = (settings) => { + validateInvalidTopKeys(settings); + if (settings.keymaps) { + validateKeymaps(settings.keymaps); + } + if (settings.search) { + validateSearch(settings.search); + } +}; + +export { validate }; diff --git a/src/shared/validators/setting.js b/src/shared/validators/setting.js deleted file mode 100644 index 949ab29..0000000 --- a/src/shared/validators/setting.js +++ /dev/null @@ -1,61 +0,0 @@ -import operations from 'shared/operations'; - -const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist']; -const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { - return operations[key]; -}); - -const validateInvalidTopKeys = (settings) => { - let invalidKey = Object.keys(settings).find((key) => { - return !VALID_TOP_KEYS.includes(key); - }); - if (invalidKey) { - throw Error(`Unknown key: "${invalidKey}"`); - } -}; - -const validateKeymaps = (keymaps) => { - for (let key of Object.keys(keymaps)) { - let value = keymaps[key]; - if (!VALID_OPERATION_VALUES.includes(value.type)) { - throw Error(`Unknown operation: "${value.type}"`); - } - } -}; - -const validateSearch = (search) => { - let engines = search.engines; - for (let key of Object.keys(engines)) { - if (/\s/.test(key)) { - throw new Error( - `While space in search engine name is not allowed: "${key}"` - ); - } - let url = engines[key]; - if (!url.match(/{}/)) { - throw new Error(`No {}-placeholders in URL of "${key}"`); - } - if (url.match(/{}/g).length > 1) { - throw new Error(`Multiple {}-placeholders in URL of "${key}"`); - } - } - - if (!search.default) { - throw new Error(`Default engine is not set`); - } - if (!Object.keys(engines).includes(search.default)) { - throw new Error(`Default engine "${search.default}" not found`); - } -}; - -const validate = (settings) => { - validateInvalidTopKeys(settings); - if (settings.keymaps) { - validateKeymaps(settings.keymaps); - } - if (settings.search) { - validateSearch(settings.search); - } -}; - -export { validate }; diff --git a/test/shared/settings/validator.test.js b/test/shared/settings/validator.test.js new file mode 100644 index 0000000..61d976a --- /dev/null +++ b/test/shared/settings/validator.test.js @@ -0,0 +1,82 @@ +import { expect } from "chai"; +import { validate } from 'shared/settings/validator'; + +describe("setting validator", () => { + describe("unknown top keys", () => { + it('throws an error for unknown settings', () => { + let settings = { keymaps: {}, poison: 123 }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'poison'); + }) + }); + + describe("keymaps settings", () => { + it('throws an error for unknown operation', () => { + let settings = { + keymaps: { + a: { 'type': 'scroll.home' }, + b: { 'type': 'poison.dressing' }, + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'poison.dressing'); + }); + }); + + describe("search settings", () => { + it('throws an error for invalid search engine name', () => { + let settings = { + search: { + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}', + 'cherry pie': 'https://cherypie.com/search?q={}', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'cherry pie'); + }); + + it('throws an error for no {}-placeholder', () => { + let settings = { + search: { + default: 'google', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'yahoo'); + }); + + it('throws an error for no default engines', () => { + let settings = { + search: { + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?q={}', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'Default engine'); + }); + + it('throws an error for invalid default engine', () => { + let settings = { + search: { + default: 'twitter', + engines: { + 'google': 'https://google.com/search?q={}', + 'yahoo': 'https://search.yahoo.com/search?q={}', + } + } + }; + let fn = validate.bind(undefined, settings) + expect(fn).to.throw(Error, 'twitter'); + }); + }); +}); diff --git a/test/shared/validators/setting.test.js b/test/shared/validators/setting.test.js deleted file mode 100644 index 15d6a10..0000000 --- a/test/shared/validators/setting.test.js +++ /dev/null @@ -1,82 +0,0 @@ -import { expect } from "chai"; -import { validate } from 'shared/validators/setting'; - -describe("setting validator", () => { - describe("unknown top keys", () => { - it('throws an error for unknown settings', () => { - let settings = { keymaps: {}, poison: 123 }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'poison'); - }) - }); - - describe("keymaps settings", () => { - it('throws an error for unknown operation', () => { - let settings = { - keymaps: { - a: { 'type': 'scroll.home' }, - b: { 'type': 'poison.dressing' }, - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'poison.dressing'); - }); - }); - - describe("search settings", () => { - it('throws an error for invalid search engine name', () => { - let settings = { - search: { - default: 'google', - engines: { - 'google': 'https://google.com/search?q={}', - 'cherry pie': 'https://cherypie.com/search?q={}', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'cherry pie'); - }); - - it('throws an error for no {}-placeholder', () => { - let settings = { - search: { - default: 'google', - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'yahoo'); - }); - - it('throws an error for no default engines', () => { - let settings = { - search: { - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?q={}', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'Default engine'); - }); - - it('throws an error for invalid default engine', () => { - let settings = { - search: { - default: 'twitter', - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?q={}', - } - } - }; - let fn = validate.bind(undefined, settings) - expect(fn).to.throw(Error, 'twitter'); - }); - }); -}); -- cgit v1.2.3 From e19f89f16248ed4bf28deaa9ab4b5204061df5eb Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Thu, 4 Jan 2018 20:34:33 +0900 Subject: add property to settings --- src/shared/settings/property-types.js | 6 ++++++ src/shared/settings/validator.js | 17 ++++++++++++++++- src/shared/settings/values.js | 18 ++++++++++++------ test/shared/settings/values.test.js | 29 +++++++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 src/shared/settings/property-types.js (limited to 'src/shared/settings') diff --git a/src/shared/settings/property-types.js b/src/shared/settings/property-types.js new file mode 100644 index 0000000..bcfa809 --- /dev/null +++ b/src/shared/settings/property-types.js @@ -0,0 +1,6 @@ +export default { + // TODO describe property types here + // mystr: 'string', + // mynum: 'number', + // mybool: 'boolean', +}; diff --git a/src/shared/settings/validator.js b/src/shared/settings/validator.js index 949ab29..6fadac7 100644 --- a/src/shared/settings/validator.js +++ b/src/shared/settings/validator.js @@ -1,6 +1,7 @@ import operations from 'shared/operations'; +import propertyTypes from './property-types'; -const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist']; +const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist', 'properties']; const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { return operations[key]; }); @@ -48,6 +49,17 @@ const validateSearch = (search) => { } }; +const validateProperties = (properties) => { + for (let name of Object.keys(properties)) { + if (!propertyTypes[name]) { + throw new Error(`Unknown property name: "${name}"`); + } + if (typeof properties[name] !== propertyTypes[name]) { + throw new Error(`Invalid type for property: "${name}"`); + } + } +}; + const validate = (settings) => { validateInvalidTopKeys(settings); if (settings.keymaps) { @@ -56,6 +68,9 @@ const validate = (settings) => { if (settings.search) { validateSearch(settings.search); } + if (settings.properties) { + validateProperties(settings.properties); + } }; export { validate }; diff --git a/src/shared/settings/values.js b/src/shared/settings/values.js index 4e55fa0..5027ba5 100644 --- a/src/shared/settings/values.js +++ b/src/shared/settings/values.js @@ -44,9 +44,12 @@ const valueFromForm = (form) => { } } - let blacklist = form.blacklist; - - return { keymaps, search, blacklist }; + return { + keymaps, + search, + blacklist: form.blacklist, + properties: form.properties + }; }; const jsonFromValue = (value) => { @@ -78,9 +81,12 @@ const formFromValue = (value, allowedOps) => { } } - let blacklist = value.blacklist; - - return { keymaps, search, blacklist }; + return { + keymaps, + search, + blacklist: value.blacklist, + properties: value.properties, + }; }; const jsonFromForm = (form) => { diff --git a/test/shared/settings/values.test.js b/test/shared/settings/values.test.js index 2632cd7..62cfb5f 100644 --- a/test/shared/settings/values.test.js +++ b/test/shared/settings/values.test.js @@ -7,13 +7,21 @@ describe("settings values", () => { let json = `{ "keymaps": { "0": {"type": "scroll.home"}}, "search": { "default": "google", "engines": { "google": "https://google.com/search?q={}" }}, - "blacklist": [ "*.slack.com"] + "blacklist": [ "*.slack.com"], + "properties": { + "mystr": "value", + "mynum": 123, + "mybool": true + } }`; let value = values.valueFromJson(json); expect(value.keymaps).to.deep.equal({ 0: {type: "scroll.home"}}); expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); expect(value.blacklist).to.deep.equal(["*.slack.com"]); + expect(value.properties).to.have.property('mystr', 'value'); + expect(value.properties).to.have.property('mynum', 123); + expect(value.properties).to.have.property('mybool', true); }); }); @@ -29,6 +37,11 @@ describe("settings values", () => { engines: [['google', 'https://google.com/search?q={}']], }, blacklist: ['*.slack.com'], + "properties": { + "mystr": "value", + "mynum": 123, + "mybool": true, + } }; let value = values.valueFromForm(form); @@ -37,6 +50,9 @@ describe("settings values", () => { expect(JSON.stringify(value.search)).to.deep.equal(JSON.stringify({ default: "google", engines: { google: "https://google.com/search?q={}"} })); expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} }); expect(value.blacklist).to.deep.equal(["*.slack.com"]); + expect(value.properties).to.have.property('mystr', 'value'); + expect(value.properties).to.have.property('mynum', 123); + expect(value.properties).to.have.property('mybool', true); }); it('convert from empty form', () => { @@ -45,6 +61,7 @@ describe("settings values", () => { expect(value).to.not.have.key('keymaps'); expect(value).to.not.have.key('search'); expect(value).to.not.have.key('blacklist'); + expect(value).to.not.have.key('properties'); }); it('override keymaps', () => { @@ -96,7 +113,12 @@ describe("settings values", () => { 0: { type: 'scroll.home' }, }, search: { default: 'google', engines: { google: 'https://google.com/search?q={}' }}, - blacklist: [ '*.slack.com'] + blacklist: [ '*.slack.com'], + properties: { + "mystr": "value", + "mynum": 123, + "mybool": true, + } }; let allowed = ['scroll.vertically?{"count":1}', 'scroll.home' ]; let form = values.formFromValue(value, allowed); @@ -109,6 +131,9 @@ describe("settings values", () => { expect(form.search).to.have.deep.property('engines', [['google', 'https://google.com/search?q={}']]); expect(form.blacklist).to.have.lengthOf(1); expect(form.blacklist).to.include('*.slack.com'); + expect(form.properties).to.have.property('mystr', 'value'); + expect(form.properties).to.have.property('mynum', 123); + expect(form.properties).to.have.property('mybool', true); }); }); }); -- cgit v1.2.3 From f4499b840c73c8872c69a53ef7a4c2b9dca977a6 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 8 Jan 2018 13:54:18 +0900 Subject: Set default properties --- src/shared/settings/default.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/shared/settings') diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js index d187565..6425354 100644 --- a/src/shared/settings/default.js +++ b/src/shared/settings/default.js @@ -58,6 +58,8 @@ export default { "duckduckgo": "https://duckduckgo.com/?q={}", "twitter": "https://twitter.com/search?q={}", "wikipedia": "https://en.wikipedia.org/w/index.php?search={}" + }, + "properties": { } } }`, -- cgit v1.2.3 From fe48dce1c9b6f003c669cb19542063c8ac0c91ba Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 8 Jan 2018 16:25:09 +0900 Subject: default property values --- src/settings/components/index.jsx | 4 ++-- src/shared/settings/properties.js | 15 +++++++++++++++ src/shared/settings/property-types.js | 6 ------ src/shared/settings/validator.js | 5 ++--- src/shared/settings/values.js | 6 +++++- 5 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 src/shared/settings/properties.js delete mode 100644 src/shared/settings/property-types.js (limited to 'src/shared/settings') diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index c41aa6b..d7696a1 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -5,7 +5,7 @@ import SearchForm from './form/search-form'; import KeymapsForm from './form/keymaps-form'; import BlacklistForm from './form/blacklist-form'; import PropertiesForm from './form/properties-form'; -import PropertyTypes from 'shared/settings/property-types'; +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'; @@ -70,7 +70,7 @@ class SettingsComponent extends Component {
Properties this.bindForm('properties', value)} /> diff --git a/src/shared/settings/properties.js b/src/shared/settings/properties.js new file mode 100644 index 0000000..ff8039b --- /dev/null +++ b/src/shared/settings/properties.js @@ -0,0 +1,15 @@ +const types = { + // TODO describe property types here + // mystr: 'string', + // mynum: 'number', + // mybool: 'boolean', +}; + +const defaults = { + // TODO describe property defaults values + // mystr: 'hello', + // mynum: 123, + // mybool: true, +}; + +export { types, defaults }; diff --git a/src/shared/settings/property-types.js b/src/shared/settings/property-types.js deleted file mode 100644 index bcfa809..0000000 --- a/src/shared/settings/property-types.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - // TODO describe property types here - // mystr: 'string', - // mynum: 'number', - // mybool: 'boolean', -}; diff --git a/src/shared/settings/validator.js b/src/shared/settings/validator.js index 6fadac7..744f63d 100644 --- a/src/shared/settings/validator.js +++ b/src/shared/settings/validator.js @@ -1,5 +1,4 @@ import operations from 'shared/operations'; -import propertyTypes from './property-types'; const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist', 'properties']; const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { @@ -51,10 +50,10 @@ const validateSearch = (search) => { const validateProperties = (properties) => { for (let name of Object.keys(properties)) { - if (!propertyTypes[name]) { + if (!properties.types[name]) { throw new Error(`Unknown property name: "${name}"`); } - if (typeof properties[name] !== propertyTypes[name]) { + if (typeof properties[name] !== properties.types[name]) { throw new Error(`Invalid type for property: "${name}"`); } } diff --git a/src/shared/settings/values.js b/src/shared/settings/values.js index 5027ba5..bd03be2 100644 --- a/src/shared/settings/values.js +++ b/src/shared/settings/values.js @@ -1,3 +1,5 @@ +import * as properties from './properties'; + const operationFromFormName = (name) => { let [type, argStr] = name.split('?'); let args = {}; @@ -81,11 +83,13 @@ const formFromValue = (value, allowedOps) => { } } + let formProperties = Object.assign({}, properties.defaults, value.properties); + return { keymaps, search, blacklist: value.blacklist, - properties: value.properties, + properties: formProperties, }; }; -- cgit v1.2.3 From d23c190cad81ec2109f69b4afa957194d029caaf Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 8 Jan 2018 21:40:12 +0900 Subject: default properties --- src/shared/settings/validator.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/shared/settings') diff --git a/src/shared/settings/validator.js b/src/shared/settings/validator.js index 744f63d..1589420 100644 --- a/src/shared/settings/validator.js +++ b/src/shared/settings/validator.js @@ -1,4 +1,5 @@ import operations from 'shared/operations'; +import * as properties from './properties'; const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist', 'properties']; const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { @@ -48,12 +49,12 @@ const validateSearch = (search) => { } }; -const validateProperties = (properties) => { - for (let name of Object.keys(properties)) { +const validateProperties = (props) => { + for (let name of Object.keys(props)) { if (!properties.types[name]) { throw new Error(`Unknown property name: "${name}"`); } - if (typeof properties[name] !== properties.types[name]) { + if (typeof props[name] !== properties.types[name]) { throw new Error(`Invalid type for property: "${name}"`); } } -- cgit v1.2.3 From 6083e70ea089fa2683741a1118be0e4e6b76f858 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 8 Jan 2018 21:54:16 +0900 Subject: separate setting actions and reducers --- src/background/actions/index.js | 4 ++++ src/background/actions/setting.js | 13 +++++++++++++ src/background/components/background.js | 4 ++-- src/background/index.js | 4 ++-- src/background/reducers/index.js | 2 +- src/background/reducers/setting.js | 17 +++++++++++++++++ src/settings/actions/setting.js | 18 +++++++----------- src/shared/settings/storage.js | 31 +++++++++++++++++++++++++++++++ test/background/reducers/setting.test.js | 19 +++++++++++++++++++ 9 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 src/background/actions/index.js create mode 100644 src/background/actions/setting.js create mode 100644 src/background/reducers/setting.js create mode 100644 src/shared/settings/storage.js create mode 100644 test/background/reducers/setting.test.js (limited to 'src/shared/settings') diff --git a/src/background/actions/index.js b/src/background/actions/index.js new file mode 100644 index 0000000..8c212c2 --- /dev/null +++ b/src/background/actions/index.js @@ -0,0 +1,4 @@ +export default { + // Settings + SETTING_SET_SETTINGS: 'setting.set.settings', +}; diff --git a/src/background/actions/setting.js b/src/background/actions/setting.js new file mode 100644 index 0000000..0454a68 --- /dev/null +++ b/src/background/actions/setting.js @@ -0,0 +1,13 @@ +import actions from '../actions'; +import * as settingsStorage from 'shared/settings/storage'; + +const load = () => { + return settingsStorage.loadValue().then((value) => { + return { + type: actions.SETTING_SET_SETTINGS, + value, + }; + }); +}; + +export { load }; diff --git a/src/background/components/background.js b/src/background/components/background.js index 2d94310..22c6693 100644 --- a/src/background/components/background.js +++ b/src/background/components/background.js @@ -1,6 +1,6 @@ import messages from 'shared/messages'; import * as operationActions from 'background/actions/operation'; -import * as settingsActions from 'settings/actions/setting'; +import * as settingActions from 'background/actions/setting'; import * as tabActions from 'background/actions/tab'; import * as commands from 'shared/commands'; @@ -46,7 +46,7 @@ export default class BackgroundComponent { case messages.CONSOLE_QUERY_COMPLETIONS: return commands.complete(message.text, settings.value); case messages.SETTINGS_RELOAD: - this.store.dispatch(settingsActions.load()); + this.store.dispatch(settingActions.load()); return this.broadcastSettingsChanged(); } } diff --git a/src/background/index.js b/src/background/index.js index 8a68767..3ef712f 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -1,4 +1,4 @@ -import * as settingsActions from 'settings/actions/setting'; +import * as settingActions from 'background/actions/setting'; import messages from 'shared/messages'; import BackgroundComponent from 'background/components/background'; import reducers from 'background/reducers'; @@ -16,4 +16,4 @@ const store = createStore(reducers, (e, sender) => { // eslint-disable-next-line no-unused-vars const backgroundComponent = new BackgroundComponent(store); -store.dispatch(settingsActions.load()); +store.dispatch(settingActions.load()); diff --git a/src/background/reducers/index.js b/src/background/reducers/index.js index 4be8fac..dab0c62 100644 --- a/src/background/reducers/index.js +++ b/src/background/reducers/index.js @@ -1,4 +1,4 @@ -import settingReducer from 'settings/reducers/setting'; +import settingReducer from './setting'; // Make setting reducer instead of re-use const defaultState = { diff --git a/src/background/reducers/setting.js b/src/background/reducers/setting.js new file mode 100644 index 0000000..70bf8ea --- /dev/null +++ b/src/background/reducers/setting.js @@ -0,0 +1,17 @@ +import actions from 'settings/actions'; + +const defaultState = { + value: {}, +}; + +export default function reducer(state = defaultState, action = {}) { + switch (action.type) { + case actions.SETTING_SET_SETTINGS: + return { + value: action.value, + }; + default: + return state; + } +} + diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js index 1d01fda..92c9f8a 100644 --- a/src/settings/actions/setting.js +++ b/src/settings/actions/setting.js @@ -1,26 +1,22 @@ 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 settingsValues from 'shared/settings/values'; const load = () => { - return browser.storage.local.get('settings').then(({ settings }) => { - if (!settings) { - return set(DefaultSettings); - } - return set(Object.assign({}, DefaultSettings, settings)); - }, console.error); + return settingsStorage.loadRaw().then((settings) => { + return set(settings); + }); }; const save = (settings) => { - return browser.storage.local.set({ - settings, - }).then(() => { + return settingsStorage.save(settings).then(() => { return browser.runtime.sendMessage({ type: messages.SETTINGS_RELOAD - }).then(() => { - return set(settings); }); + }).then(() => { + return set(settings); }); }; diff --git a/src/shared/settings/storage.js b/src/shared/settings/storage.js new file mode 100644 index 0000000..1edb441 --- /dev/null +++ b/src/shared/settings/storage.js @@ -0,0 +1,31 @@ +import DefaultSettings from './default'; +import * as settingsValues from './values'; + +const loadRaw = () => { + return browser.storage.local.get('settings').then(({ settings }) => { + if (!settings) { + return DefaultSettings; + } + return Object.assign({}, DefaultSettings, settings); + }); +}; + +const loadValue = () => { + return loadRaw().then((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); + } + return value; + }); +}; + +const save = (settings) => { + return browser.storage.local.set({ + settings, + }); +}; + +export { loadRaw, loadValue, save }; diff --git a/test/background/reducers/setting.test.js b/test/background/reducers/setting.test.js new file mode 100644 index 0000000..a6a5573 --- /dev/null +++ b/test/background/reducers/setting.test.js @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import actions from 'background/actions'; +import settingReducer from 'background/reducers/setting'; + +describe("setting reducer", () => { + it('return the initial state', () => { + let state = settingReducer(undefined, {}); + expect(state).to.have.deep.property('value', {}); + }); + + it('return next state for SETTING_SET_SETTINGS', () => { + let action = { + type: actions.SETTING_SET_SETTINGS, + value: { key: 123 }, + }; + let state = settingReducer(undefined, action); + expect(state).to.have.deep.property('value', { key: 123 }); + }); +}); -- cgit v1.2.3 From 03bb124cce7acf3a245baca1c109e5136979162e Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Thu, 11 Jan 2018 21:52:07 +0900 Subject: support custom chars as hintchars --- src/content/components/top-content/follow-controller.js | 12 ++++++++---- src/shared/settings/properties.js | 15 +++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src/shared/settings') diff --git a/src/content/components/top-content/follow-controller.js b/src/content/components/top-content/follow-controller.js index d373177..1e7f3cd 100644 --- a/src/content/components/top-content/follow-controller.js +++ b/src/content/components/top-content/follow-controller.js @@ -1,8 +1,7 @@ import * as followControllerActions from 'content/actions/follow-controller'; import messages from 'shared/messages'; import HintKeyProducer from 'content/hint-key-producer'; - -const DEFAULT_HINT_CHARSET = 'abcdefghijklmnopqrstuvwxyz'; +import * as properties from 'shared/settings/properties'; const broadcastMessage = (win, message) => { let json = JSON.stringify(message); @@ -84,7 +83,7 @@ export default class FollowController { this.store.dispatch(followControllerActions.backspace()); break; default: - if (DEFAULT_HINT_CHARSET.includes(key)) { + if (this.hintchars().includes(key)) { this.store.dispatch(followControllerActions.keyPress(key)); } break; @@ -93,7 +92,7 @@ export default class FollowController { } count() { - this.producer = new HintKeyProducer(DEFAULT_HINT_CHARSET); + this.producer = new HintKeyProducer(this.hintchars()); let doc = this.win.document; let viewWidth = this.win.innerWidth || doc.documentElement.clientWidth; let viewHeight = this.win.innerHeight || doc.documentElement.clientHeight; @@ -135,4 +134,9 @@ export default class FollowController { type: messages.FOLLOW_REMOVE_HINTS, }); } + + hintchars() { + return this.store.getState().setting.properties.hintchars || + properties.defaults.hintchars; + } } diff --git a/src/shared/settings/properties.js b/src/shared/settings/properties.js index ff8039b..f695c58 100644 --- a/src/shared/settings/properties.js +++ b/src/shared/settings/properties.js @@ -1,15 +1,14 @@ +// describe types of a propety as: +// mystr: 'string', +// mynum: 'number', +// mybool: 'boolean', const types = { - // TODO describe property types here - // mystr: 'string', - // mynum: 'number', - // mybool: 'boolean', + hintchars: 'string', }; +// describe default values of a property const defaults = { - // TODO describe property defaults values - // mystr: 'hello', - // mynum: 123, - // mybool: true, + hintchars: 'abcdefghijklmnopqrstuvwxyz', }; export { types, defaults }; -- cgit v1.2.3 From 2ca1b54faacb261e5a25331e030da13d07c09662 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 13 Jan 2018 15:31:39 +0900 Subject: add smoothscroll property --- src/content/actions/operation.js | 19 +++++++++------- src/content/components/common/keymapper.js | 2 +- src/content/scrolls.js | 36 ++++++++++++++++++------------ src/shared/settings/properties.js | 2 ++ 4 files changed, 36 insertions(+), 23 deletions(-) (limited to 'src/shared/settings') diff --git a/src/content/actions/operation.js b/src/content/actions/operation.js index 8157127..d2e258c 100644 --- a/src/content/actions/operation.js +++ b/src/content/actions/operation.js @@ -5,9 +5,12 @@ import * as navigates from 'content/navigates'; import * as urls from 'content/urls'; import * as consoleFrames from 'content/console-frames'; import * as addonActions from './addon'; +import * as properties from 'shared/settings/properties'; // eslint-disable-next-line complexity -const exec = (operation) => { +const exec = (operation, settings) => { + let smoothscroll = settings.properties.smoothscroll || + properties.defaults.smoothscroll; switch (operation.type) { case operations.ADDON_ENABLE: return addonActions.enable(); @@ -24,19 +27,19 @@ const exec = (operation) => { type: messages.FIND_PREV, }), '*'); case operations.SCROLL_VERTICALLY: - return scrolls.scrollVertically(operation.count); + return scrolls.scrollVertically(operation.count, smoothscroll); case operations.SCROLL_HORIZONALLY: - return scrolls.scrollHorizonally(operation.count); + return scrolls.scrollHorizonally(operation.count, smoothscroll); case operations.SCROLL_PAGES: - return scrolls.scrollPages(operation.count); + return scrolls.scrollPages(operation.count, smoothscroll); case operations.SCROLL_TOP: - return scrolls.scrollTop(); + return scrolls.scrollTop(smoothscroll); case operations.SCROLL_BOTTOM: - return scrolls.scrollBottom(); + return scrolls.scrollBottom(smoothscroll); case operations.SCROLL_HOME: - return scrolls.scrollHome(); + return scrolls.scrollHome(smoothscroll); case operations.SCROLL_END: - return scrolls.scrollEnd(); + return scrolls.scrollEnd(smoothscroll); case operations.FOLLOW_START: return window.top.postMessage(JSON.stringify({ type: messages.FOLLOW_START, diff --git a/src/content/components/common/keymapper.js b/src/content/components/common/keymapper.js index fb8fabe..fa8c33a 100644 --- a/src/content/components/common/keymapper.js +++ b/src/content/components/common/keymapper.js @@ -47,7 +47,7 @@ export default class KeymapperComponent { return true; } let operation = keymaps.get(matched[0]); - this.store.dispatch(operationActions.exec(operation)); + this.store.dispatch(operationActions.exec(operation, state.setting)); this.store.dispatch(inputActions.clearKeys()); return true; } diff --git a/src/content/scrolls.js b/src/content/scrolls.js index 8daa36f..5aef1df 100644 --- a/src/content/scrolls.js +++ b/src/content/scrolls.js @@ -108,54 +108,62 @@ const roughScroll = (element, x, y) => { element.scrollTo(x, y); }; -const scrollVertically = (count) => { +const scroll = (element, x, y, smooth) => { + if (smooth) { + smoothScroll(element, x, y); + } else { + roughScroll(element, x, y); + } +}; + +const scrollVertically = (count, smooth) => { let target = scrollTarget(); let x = target.scrollLeft; let y = target.scrollTop + SCROLL_DELTA_Y * count; - roughScroll(target, x, y); + scroll(target, x, y, smooth); }; -const scrollHorizonally = (count) => { +const scrollHorizonally = (count, smooth) => { let target = scrollTarget(); let x = target.scrollLeft + SCROLL_DELTA_X * count; let y = target.scrollTop; - roughScroll(target, x, y); + scroll(target, x, y, smooth); }; -const scrollPages = (count) => { +const scrollPages = (count, smooth) => { let target = scrollTarget(); let height = target.clientHeight; let x = target.scrollLeft; let y = target.scrollTop + height * count; - roughScroll(target, x, y); + scroll(target, x, y, smooth); }; -const scrollTop = () => { +const scrollTop = (smooth) => { let target = scrollTarget(); let x = target.scrollLeft; let y = 0; - roughScroll(target, x, y); + scroll(target, x, y, smooth); }; -const scrollBottom = () => { +const scrollBottom = (smooth) => { let target = scrollTarget(); let x = target.scrollLeft; let y = target.scrollHeight; - roughScroll(target, x, y); + scroll(target, x, y, smooth); }; -const scrollHome = () => { +const scrollHome = (smooth) => { let target = scrollTarget(); let x = 0; let y = target.scrollTop; - roughScroll(target, x, y); + scroll(target, x, y, smooth); }; -const scrollEnd = () => { +const scrollEnd = (smooth) => { let target = scrollTarget(); let x = target.scrollWidth; let y = target.scrollTop; - roughScroll(target, x, y); + scroll(target, x, y, smooth); }; export { diff --git a/src/shared/settings/properties.js b/src/shared/settings/properties.js index f695c58..37dc881 100644 --- a/src/shared/settings/properties.js +++ b/src/shared/settings/properties.js @@ -4,11 +4,13 @@ // mybool: 'boolean', const types = { hintchars: 'string', + smoothscroll: 'boolean', }; // describe default values of a property const defaults = { hintchars: 'abcdefghijklmnopqrstuvwxyz', + smoothscroll: false, }; export { types, defaults }; -- cgit v1.2.3 From e3fdf742e7dc3fa3518746d185418a2e63ca2118 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka 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/shared/settings') 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 1d85b397c9b73a8a7fa5563f2b97d5904b5af84d Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 14 Jan 2018 09:01:23 +0900 Subject: fix default settings --- src/shared/settings/default.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/shared/settings') diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js index 0c3f0d9..bcd7731 100644 --- a/src/shared/settings/default.js +++ b/src/shared/settings/default.js @@ -60,9 +60,9 @@ export default { "duckduckgo": "https://duckduckgo.com/?q={}", "twitter": "https://twitter.com/search?q={}", "wikipedia": "https://en.wikipedia.org/w/index.php?search={}" - }, - "properties": { } + }, + "properties": { } }`, }; -- cgit v1.2.3 From 930cd14ac1b5d25bad28084bfa953ac4a13080d1 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 14 Jan 2018 09:04:30 +0900 Subject: fix default propertiest --- src/shared/settings/storage.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/shared/settings') diff --git a/src/shared/settings/storage.js b/src/shared/settings/storage.js index 1edb441..25ebfcd 100644 --- a/src/shared/settings/storage.js +++ b/src/shared/settings/storage.js @@ -18,7 +18,9 @@ const loadValue = () => { } else if (settings.source === 'form') { value = settingsValues.valueFromForm(settings.form); } - return value; + return Object.assign({}, + settingsValues.valueFromJson(DefaultSettings.json), + value); }); }; -- cgit v1.2.3 From e7dcd7f500f9c139835313a573f861a10aa49d18 Mon Sep 17 00:00:00 2001 From: Cornelius Matějka Date: Wed, 22 Nov 2017 19:22:30 +0100 Subject: Pinned tabs are not closeable by 'd' Added binding 'DD' to force tab close which also closes pinned tabs --- src/background/actions/operation.js | 2 ++ src/background/tabs.js | 15 ++++++++++++--- src/shared/operations.js | 1 + src/shared/settings/default.js | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) (limited to 'src/shared/settings') diff --git a/src/background/actions/operation.js b/src/background/actions/operation.js index cfee868..1188ea2 100644 --- a/src/background/actions/operation.js +++ b/src/background/actions/operation.js @@ -17,6 +17,8 @@ const exec = (operation, tab) => { switch (operation.type) { case operations.TAB_CLOSE: return tabs.closeTab(tab.id); + case operations.TAB_CLOSE_FORCE: + return tabs.closeTabForce(tab.id); case operations.TAB_REOPEN: return tabs.reopenTab(); case operations.TAB_PREV: diff --git a/src/background/tabs.js b/src/background/tabs.js index d50d8e5..e02932a 100644 --- a/src/background/tabs.js +++ b/src/background/tabs.js @@ -9,6 +9,14 @@ browser.tabs.onActivated.addListener((activeInfo) => { }); const closeTab = (id) => { + return browser.tabs.get(id).then((tab) => { + if(!tab.pinned) { + return browser.tabs.remove(id); + } + }) +}; + +const closeTabForce = (id) => { return browser.tabs.remove(id); }; @@ -130,7 +138,8 @@ const duplicate = (id) => { }; export { - closeTab, reopenTab, selectAt, selectByKeyword, getCompletions, - selectPrevTab, selectNextTab, selectFirstTab, selectLastTab, selectPrevSelTab, - reload, updateTabPinned, toggleTabPinned, duplicate + closeTab, closeTabForce, reopenTab, selectAt, selectByKeyword, + getCompletions, selectPrevTab, selectNextTab, selectFirstTab, + selectLastTab, selectPrevSelTab, reload, updateTabPinned, + toggleTabPinned, duplicate }; diff --git a/src/shared/operations.js b/src/shared/operations.js index 19466df..4172f8b 100644 --- a/src/shared/operations.js +++ b/src/shared/operations.js @@ -33,6 +33,7 @@ export default { // Tabs TAB_CLOSE: 'tabs.close', + TAB_CLOSE_FORCE: 'tabs.close.force', TAB_REOPEN: 'tabs.reopen', TAB_PREV: 'tabs.prev', TAB_NEXT: 'tabs.next', diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js index e81df2b..826e3f6 100644 --- a/src/shared/settings/default.js +++ b/src/shared/settings/default.js @@ -23,6 +23,7 @@ export default { "G": { "type": "scroll.bottom" }, "$": { "type": "scroll.end" }, "d": { "type": "tabs.close" }, + "DD": { "type": "tabs.close.force" }, "u": { "type": "tabs.reopen" }, "K": { "type": "tabs.prev", "count": 1 }, "J": { "type": "tabs.next", "count": 1 }, -- cgit v1.2.3 From 478aa3cfab255fdf33bef175358bd21478f56882 Mon Sep 17 00:00:00 2001 From: Cornelius Matějka Date: Sat, 13 Jan 2018 18:26:12 +0100 Subject: Changed default key binding for closing pined tabs ('DD' -> '!d')as requested in PR --- src/shared/settings/default.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/shared/settings') diff --git a/src/shared/settings/default.js b/src/shared/settings/default.js index 826e3f6..c85a079 100644 --- a/src/shared/settings/default.js +++ b/src/shared/settings/default.js @@ -23,7 +23,7 @@ export default { "G": { "type": "scroll.bottom" }, "$": { "type": "scroll.end" }, "d": { "type": "tabs.close" }, - "DD": { "type": "tabs.close.force" }, + "!d": { "type": "tabs.close.force" }, "u": { "type": "tabs.reopen" }, "K": { "type": "tabs.prev", "count": 1 }, "J": { "type": "tabs.next", "count": 1 }, -- cgit v1.2.3 From 1b2a5462f35b1f864945120aa479afb5d351d9e5 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Tue, 23 Jan 2018 21:03:33 +0900 Subject: set default properties --- src/shared/settings/storage.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/shared/settings') diff --git a/src/shared/settings/storage.js b/src/shared/settings/storage.js index 25ebfcd..9b8045d 100644 --- a/src/shared/settings/storage.js +++ b/src/shared/settings/storage.js @@ -18,6 +18,9 @@ const loadValue = () => { } else if (settings.source === 'form') { value = settingsValues.valueFromForm(settings.form); } + if (!value.properties) { + value.properties = {}; + } return Object.assign({}, settingsValues.valueFromJson(DefaultSettings.json), value); -- cgit v1.2.3