From 177940981ed9c4f096ad7db20f0b7ee044fd7b17 Mon Sep 17 00:00:00 2001 From: Erwan Ameil Date: Thu, 16 Nov 2017 13:03:38 +0000 Subject: Open adjacent tabs and background tabs --- src/shared/commands.js | 20 ++++++++++++++++---- src/shared/default-settings.js | 7 ++++--- src/shared/validators/setting.js | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) (limited to 'src/shared') diff --git a/src/shared/commands.js b/src/shared/commands.js index 8edeb5c..bcad313 100644 --- a/src/shared/commands.js +++ b/src/shared/commands.js @@ -33,8 +33,19 @@ const openCommand = (url) => { }); }; -const tabopenCommand = (url) => { - return browser.tabs.create({ url: url }); +const tabopenCommand = (url, background = false, adjacent = false) => { + if (adjacent) { + return browser.tabs.query({ + active: true, currentWindow: true + }).then((gotTabs) => { + return browser.tabs.create({ + url: url, + active: !background, + index: gotTabs[0].index + 1 + }); + }); + } + return browser.tabs.create({ url: url, active: !background }); }; const winopenCommand = (url) => { @@ -102,7 +113,8 @@ const doCommand = (line, settings) => { return openCommand(normalizeUrl(words, settings.search)); case 't': case 'tabopen': - return tabopenCommand(normalizeUrl(words, settings.search)); + return tabopenCommand( + normalizeUrl(words, settings.search), false, settings.openAdjacentTabs); case 'w': case 'winopen': return winopenCommand(normalizeUrl(words, settings.search)); @@ -166,4 +178,4 @@ const complete = (line, settings) => { return getCompletions(line, settings); }; -export { exec, complete }; +export { exec, complete, tabopenCommand }; diff --git a/src/shared/default-settings.js b/src/shared/default-settings.js index 608890b..d691859 100644 --- a/src/shared/default-settings.js +++ b/src/shared/default-settings.js @@ -37,8 +37,8 @@ export default { "zi": { "type": "zoom.in" }, "zo": { "type": "zoom.out" }, "zz": { "type": "zoom.neutral" }, - "f": { "type": "follow.start", "newTab": false }, - "F": { "type": "follow.start", "newTab": true }, + "f": { "type": "follow.start", "newTab": false, "background": false }, + "F": { "type": "follow.start", "newTab": true, "background": false }, "H": { "type": "navigate.history.prev" }, "L": { "type": "navigate.history.next" }, "[[": { "type": "navigate.link.prev" }, @@ -61,6 +61,7 @@ export default { "twitter": "https://twitter.com/search?q={}", "wikipedia": "https://en.wikipedia.org/w/index.php?search={}" } - } + }, + "openAdjacentTabs": false }` }; diff --git a/src/shared/validators/setting.js b/src/shared/validators/setting.js index 949ab29..5fe75b2 100644 --- a/src/shared/validators/setting.js +++ b/src/shared/validators/setting.js @@ -1,6 +1,6 @@ import operations from 'shared/operations'; -const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist']; +const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist', 'openAdjacentTabs']; const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { return operations[key]; }); -- cgit v1.2.3 From 44459e39c3526673ac2ac7065c5659e4af5ea7d8 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 18 Nov 2017 22:02:44 +0900 Subject: use preact --- .eslintrc | 2 ++ src/settings/components/index.jsx | 9 ++------- src/settings/index.jsx | 5 ++--- src/shared/store/provider.jsx | 13 +++++-------- webpack.config.js | 2 +- 5 files changed, 12 insertions(+), 19 deletions(-) (limited to 'src/shared') diff --git a/.eslintrc b/.eslintrc index 949b5a5..6717889 100644 --- a/.eslintrc +++ b/.eslintrc @@ -44,6 +44,7 @@ "no-plusplus": "off", "no-ternary": "off", "no-undefined": "off", + "no-unused-vars": ["error", { "varsIgnorePattern": "h" }], "no-use-before-define": "off", "no-warning-comments": "off", "object-curly-newline": ["error", { "consistent": true }], @@ -65,5 +66,6 @@ "react/jsx-indent": ["error", 2], "react/prop-types": "off", + "react/react-in-jsx-scope": "off" } } diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index 4418942..bb2045a 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -1,10 +1,9 @@ import './site.scss'; -import React from 'react'; -import PropTypes from 'prop-types'; +import { h, Component } from 'preact'; import * as settingActions from 'settings/actions/setting'; import * as validator from 'shared/validators/setting'; -class SettingsComponent extends React.Component { +class SettingsComponent extends Component { constructor(props, context) { super(props, context); @@ -84,8 +83,4 @@ class SettingsComponent extends React.Component { } } -SettingsComponent.contextTypes = { - store: PropTypes.any, -}; - export default SettingsComponent; diff --git a/src/settings/index.jsx b/src/settings/index.jsx index 7516fb7..eb251b4 100644 --- a/src/settings/index.jsx +++ b/src/settings/index.jsx @@ -1,5 +1,4 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import { h, render } from 'preact'; import SettingsComponent from './components'; import reducer from 'settings/reducers/setting'; import Provider from 'shared/store/provider'; @@ -9,7 +8,7 @@ const store = createStore(reducer); document.addEventListener('DOMContentLoaded', () => { let wrapper = document.getElementById('vimvixen-settings'); - ReactDOM.render( + render( , diff --git a/src/shared/store/provider.jsx b/src/shared/store/provider.jsx index 743f656..fe925aa 100644 --- a/src/shared/store/provider.jsx +++ b/src/shared/store/provider.jsx @@ -1,18 +1,15 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import { h, Component } from 'preact'; -class Provider extends React.PureComponent { +class Provider extends Component { getChildContext() { return { store: this.props.store }; } render() { - return React.Children.only(this.props.children); + return
+ { this.props.children } +
; } } -Provider.childContextTypes = { - store: PropTypes.any, -}; - export default Provider; diff --git a/webpack.config.js b/webpack.config.js index 16d437f..fc5ef5e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -25,7 +25,7 @@ config = { exclude: /node_modules/, loader: 'babel-loader', query: { - presets: ['es2015', 'react'] + presets: ['es2015', 'preact'] } }, { -- cgit v1.2.3 From 4e5ddc1d57ba4f42314eb49ae57a9b67950be596 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Wed, 22 Nov 2017 22:38:34 +0900 Subject: Add keybindings form --- src/settings/actions/setting.js | 7 +- src/settings/components/index.jsx | 139 ++++++++++++++++++++++++++++++---- src/settings/components/site.scss | 27 +++++++ src/settings/components/ui/input.jsx | 35 +++++---- src/settings/components/ui/input.scss | 37 +++++---- src/settings/reducers/setting.js | 2 + src/shared/default-settings.js | 66 +++++++++++++++- 7 files changed, 268 insertions(+), 45 deletions(-) (limited to 'src/shared') diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js index c1b27c8..fa158a3 100644 --- a/src/settings/actions/setting.js +++ b/src/settings/actions/setting.js @@ -4,10 +4,10 @@ import DefaultSettings from 'shared/default-settings'; const load = () => { return browser.storage.local.get('settings').then(({ settings }) => { - if (settings) { - return set(settings); + if (!settings) { + return set(DefaultSettings); } - return set(DefaultSettings); + return set(Object.assign({}, DefaultSettings, settings)); }, console.error); }; @@ -28,6 +28,7 @@ const set = (settings) => { type: actions.SETTING_SET_SETTINGS, source: settings.source, json: settings.json, + form: settings.form, value: JSON.parse(settings.json), }; }; diff --git a/src/settings/components/index.jsx b/src/settings/components/index.jsx index 98d8fb2..11411bd 100644 --- a/src/settings/components/index.jsx +++ b/src/settings/components/index.jsx @@ -4,6 +4,59 @@ import Input from './ui/input'; import * as settingActions from 'settings/actions/setting'; import * as validator from 'shared/validators/setting'; +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 SettingsComponent extends Component { constructor(props, context) { super(props, context); @@ -29,33 +82,87 @@ class SettingsComponent extends Component { settings: { source: settings.source, json: settings.json, + form: settings.form, } }); } + renderFormFields() { + let keymapFields = KeyMapFields.map((group, index) => { + return
+ { + group.map((field) => { + let name = field[0]; + let label = field[1]; + let value = this.state.settings.form.keymaps[name]; + return ; + }) + } +
; + }); + + return
+
+ Keybindings +
+ { keymapFields } +
+
+
; + } + + renderJsonFields() { + return
+ +
; + } + render() { + let fields = null; + if (this.state.settings.source === 'form') { + fields = this.renderFormFields(); + } else if (this.state.settings.source === 'json') { + fields = this.renderJsonFields(); + } return (

Configure Vim-Vixen

+ + value='json' + onChange={this.bindValue.bind(this)} /> - + { fields }
); @@ -82,9 +189,15 @@ class SettingsComponent extends Component { this.setState(next); } - bindAndSave(e) { - this.bindValue(e); + bindFormKeymapsValue(e) { + let next = Object.assign({}, this.state); + + next.settings.form.keymaps[e.target.name] = e.target.value; + + this.context.store.dispatch(settingActions.save(next.settings)); + } + save() { try { let json = this.state.settings.json; validator.validate(JSON.parse(json)); diff --git a/src/settings/components/site.scss b/src/settings/components/site.scss index aac4319..dcc52ce 100644 --- a/src/settings/components/site.scss +++ b/src/settings/components/site.scss @@ -7,4 +7,31 @@ min-height: 64ex; resize: vertical; } + + fieldset { + margin: 0; + padding: 0; + border: none; + margin-top: 1rem; + + fieldset:first-of-type { + margin-top: 1rem; + } + + legend { + font-size: 1.5rem; + line-height: 1.5rem; + font-weight: bold; + } + } + + .keymap-fields{ + column-count: 2; + .keymap-fields-group { + margin-top: 24px; + } + .keymap-fields-group:first-of-type { + margin-top: 0; + } + } } diff --git a/src/settings/components/ui/input.jsx b/src/settings/components/ui/input.jsx index 9b6c229..5138411 100644 --- a/src/settings/components/ui/input.jsx +++ b/src/settings/components/ui/input.jsx @@ -3,32 +3,35 @@ import './input.scss'; class Input extends Component { + renderText(props) { + let inputClassName = props.error ? 'input-error' : ''; + return
+ + +
; + } + renderRadio(props) { - let inputClasses = 'form-field-input'; - if (props.error) { - inputClasses += ' input-error'; - } - return
+ let inputClassName = props.error ? 'input-error' : ''; + return
; } renderTextArea(props) { - let inputClasses = 'form-field-input'; - if (props.error) { - inputClasses += ' input-error'; - } - return
+ let inputClassName = props.error ? 'input-error' : ''; + return
-