From c60d0e7392fc708e961614d6b756a045de74f458 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka
Date: Tue, 30 Apr 2019 14:00:07 +0900
Subject: Rename .js/.jsx to .ts/.tsx
---
src/console/actions/console.js | 96 -------------
src/console/actions/console.ts | 96 +++++++++++++
src/console/actions/index.js | 13 --
src/console/actions/index.ts | 13 ++
src/console/components/Console.jsx | 149 ---------------------
src/console/components/Console.tsx | 149 +++++++++++++++++++++
src/console/components/console/Completion.jsx | 86 ------------
src/console/components/console/Completion.tsx | 86 ++++++++++++
src/console/components/console/CompletionItem.jsx | 28 ----
src/console/components/console/CompletionItem.tsx | 28 ++++
src/console/components/console/CompletionTitle.jsx | 14 --
src/console/components/console/CompletionTitle.tsx | 14 ++
src/console/components/console/Input.jsx | 43 ------
src/console/components/console/Input.tsx | 43 ++++++
src/console/components/console/Message.jsx | 25 ----
src/console/components/console/Message.tsx | 25 ++++
src/console/index.jsx | 42 ------
src/console/index.tsx | 42 ++++++
src/console/reducers/index.js | 102 --------------
src/console/reducers/index.ts | 102 ++++++++++++++
20 files changed, 598 insertions(+), 598 deletions(-)
delete mode 100644 src/console/actions/console.js
create mode 100644 src/console/actions/console.ts
delete mode 100644 src/console/actions/index.js
create mode 100644 src/console/actions/index.ts
delete mode 100644 src/console/components/Console.jsx
create mode 100644 src/console/components/Console.tsx
delete mode 100644 src/console/components/console/Completion.jsx
create mode 100644 src/console/components/console/Completion.tsx
delete mode 100644 src/console/components/console/CompletionItem.jsx
create mode 100644 src/console/components/console/CompletionItem.tsx
delete mode 100644 src/console/components/console/CompletionTitle.jsx
create mode 100644 src/console/components/console/CompletionTitle.tsx
delete mode 100644 src/console/components/console/Input.jsx
create mode 100644 src/console/components/console/Input.tsx
delete mode 100644 src/console/components/console/Message.jsx
create mode 100644 src/console/components/console/Message.tsx
delete mode 100644 src/console/index.jsx
create mode 100644 src/console/index.tsx
delete mode 100644 src/console/reducers/index.js
create mode 100644 src/console/reducers/index.ts
(limited to 'src/console')
diff --git a/src/console/actions/console.js b/src/console/actions/console.js
deleted file mode 100644
index 3713a76..0000000
--- a/src/console/actions/console.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import messages from 'shared/messages';
-import actions from 'console/actions';
-
-const hide = () => {
- return {
- type: actions.CONSOLE_HIDE,
- };
-};
-
-const showCommand = (text) => {
- return {
- type: actions.CONSOLE_SHOW_COMMAND,
- text: text
- };
-};
-
-const showFind = () => {
- return {
- type: actions.CONSOLE_SHOW_FIND,
- };
-};
-
-const showError = (text) => {
- return {
- type: actions.CONSOLE_SHOW_ERROR,
- text: text
- };
-};
-
-const showInfo = (text) => {
- return {
- type: actions.CONSOLE_SHOW_INFO,
- text: text
- };
-};
-
-const hideCommand = () => {
- window.top.postMessage(JSON.stringify({
- type: messages.CONSOLE_UNFOCUS,
- }), '*');
- return {
- type: actions.CONSOLE_HIDE_COMMAND,
- };
-};
-
-const enterCommand = async(text) => {
- await browser.runtime.sendMessage({
- type: messages.CONSOLE_ENTER_COMMAND,
- text,
- });
- return hideCommand(text);
-};
-
-const enterFind = (text) => {
- window.top.postMessage(JSON.stringify({
- type: messages.CONSOLE_ENTER_FIND,
- text,
- }), '*');
- return hideCommand();
-};
-
-const setConsoleText = (consoleText) => {
- return {
- type: actions.CONSOLE_SET_CONSOLE_TEXT,
- consoleText,
- };
-};
-
-const getCompletions = async(text) => {
- let completions = await browser.runtime.sendMessage({
- type: messages.CONSOLE_QUERY_COMPLETIONS,
- text,
- });
- return {
- type: actions.CONSOLE_SET_COMPLETIONS,
- completions,
- completionSource: text,
- };
-};
-
-const completionNext = () => {
- return {
- type: actions.CONSOLE_COMPLETION_NEXT,
- };
-};
-
-const completionPrev = () => {
- return {
- type: actions.CONSOLE_COMPLETION_PREV,
- };
-};
-
-export {
- hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText,
- enterCommand, enterFind, getCompletions, completionNext, completionPrev
-};
diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts
new file mode 100644
index 0000000..3713a76
--- /dev/null
+++ b/src/console/actions/console.ts
@@ -0,0 +1,96 @@
+import messages from 'shared/messages';
+import actions from 'console/actions';
+
+const hide = () => {
+ return {
+ type: actions.CONSOLE_HIDE,
+ };
+};
+
+const showCommand = (text) => {
+ return {
+ type: actions.CONSOLE_SHOW_COMMAND,
+ text: text
+ };
+};
+
+const showFind = () => {
+ return {
+ type: actions.CONSOLE_SHOW_FIND,
+ };
+};
+
+const showError = (text) => {
+ return {
+ type: actions.CONSOLE_SHOW_ERROR,
+ text: text
+ };
+};
+
+const showInfo = (text) => {
+ return {
+ type: actions.CONSOLE_SHOW_INFO,
+ text: text
+ };
+};
+
+const hideCommand = () => {
+ window.top.postMessage(JSON.stringify({
+ type: messages.CONSOLE_UNFOCUS,
+ }), '*');
+ return {
+ type: actions.CONSOLE_HIDE_COMMAND,
+ };
+};
+
+const enterCommand = async(text) => {
+ await browser.runtime.sendMessage({
+ type: messages.CONSOLE_ENTER_COMMAND,
+ text,
+ });
+ return hideCommand(text);
+};
+
+const enterFind = (text) => {
+ window.top.postMessage(JSON.stringify({
+ type: messages.CONSOLE_ENTER_FIND,
+ text,
+ }), '*');
+ return hideCommand();
+};
+
+const setConsoleText = (consoleText) => {
+ return {
+ type: actions.CONSOLE_SET_CONSOLE_TEXT,
+ consoleText,
+ };
+};
+
+const getCompletions = async(text) => {
+ let completions = await browser.runtime.sendMessage({
+ type: messages.CONSOLE_QUERY_COMPLETIONS,
+ text,
+ });
+ return {
+ type: actions.CONSOLE_SET_COMPLETIONS,
+ completions,
+ completionSource: text,
+ };
+};
+
+const completionNext = () => {
+ return {
+ type: actions.CONSOLE_COMPLETION_NEXT,
+ };
+};
+
+const completionPrev = () => {
+ return {
+ type: actions.CONSOLE_COMPLETION_PREV,
+ };
+};
+
+export {
+ hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText,
+ enterCommand, enterFind, getCompletions, completionNext, completionPrev
+};
diff --git a/src/console/actions/index.js b/src/console/actions/index.js
deleted file mode 100644
index b394179..0000000
--- a/src/console/actions/index.js
+++ /dev/null
@@ -1,13 +0,0 @@
-export default {
- // console commands
- CONSOLE_HIDE: 'console.hide',
- CONSOLE_SHOW_COMMAND: 'console.show.command',
- CONSOLE_SHOW_ERROR: 'console.show.error',
- CONSOLE_SHOW_INFO: 'console.show.info',
- CONSOLE_HIDE_COMMAND: 'console.hide.command',
- CONSOLE_SET_CONSOLE_TEXT: 'console.set.command',
- CONSOLE_SET_COMPLETIONS: 'console.set.completions',
- CONSOLE_COMPLETION_NEXT: 'console.completion.next',
- CONSOLE_COMPLETION_PREV: 'console.completion.prev',
- CONSOLE_SHOW_FIND: 'console.show.find',
-};
diff --git a/src/console/actions/index.ts b/src/console/actions/index.ts
new file mode 100644
index 0000000..b394179
--- /dev/null
+++ b/src/console/actions/index.ts
@@ -0,0 +1,13 @@
+export default {
+ // console commands
+ CONSOLE_HIDE: 'console.hide',
+ CONSOLE_SHOW_COMMAND: 'console.show.command',
+ CONSOLE_SHOW_ERROR: 'console.show.error',
+ CONSOLE_SHOW_INFO: 'console.show.info',
+ CONSOLE_HIDE_COMMAND: 'console.hide.command',
+ CONSOLE_SET_CONSOLE_TEXT: 'console.set.command',
+ CONSOLE_SET_COMPLETIONS: 'console.set.completions',
+ CONSOLE_COMPLETION_NEXT: 'console.completion.next',
+ CONSOLE_COMPLETION_PREV: 'console.completion.prev',
+ CONSOLE_SHOW_FIND: 'console.show.find',
+};
diff --git a/src/console/components/Console.jsx b/src/console/components/Console.jsx
deleted file mode 100644
index 5427e43..0000000
--- a/src/console/components/Console.jsx
+++ /dev/null
@@ -1,149 +0,0 @@
-import './console.scss';
-import { connect } from 'react-redux';
-import React from 'react';
-import PropTypes from 'prop-types';
-import Input from './console/Input';
-import Completion from './console/Completion';
-import Message from './console/Message';
-import * as consoleActions from '../../console/actions/console';
-
-const COMPLETION_MAX_ITEMS = 33;
-
-class Console extends React.Component {
- onBlur() {
- if (this.props.mode === 'command' || this.props.mode === 'find') {
- return this.props.dispatch(consoleActions.hideCommand());
- }
- }
-
- doEnter(e) {
- e.stopPropagation();
- e.preventDefault();
-
- let value = e.target.value;
- if (this.props.mode === 'command') {
- return this.props.dispatch(consoleActions.enterCommand(value));
- } else if (this.props.mode === 'find') {
- return this.props.dispatch(consoleActions.enterFind(value));
- }
- }
-
- selectNext(e) {
- this.props.dispatch(consoleActions.completionNext());
- e.stopPropagation();
- e.preventDefault();
- }
-
- selectPrev(e) {
- this.props.dispatch(consoleActions.completionPrev());
- e.stopPropagation();
- e.preventDefault();
- }
-
- onKeyDown(e) {
- if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) {
- this.props.dispatch(consoleActions.hideCommand());
- }
- switch (e.keyCode) {
- case KeyboardEvent.DOM_VK_ESCAPE:
- return this.props.dispatch(consoleActions.hideCommand());
- case KeyboardEvent.DOM_VK_RETURN:
- return this.doEnter(e);
- case KeyboardEvent.DOM_VK_TAB:
- if (e.shiftKey) {
- this.props.dispatch(consoleActions.completionPrev());
- } else {
- this.props.dispatch(consoleActions.completionNext());
- }
- e.stopPropagation();
- e.preventDefault();
- break;
- case KeyboardEvent.DOM_VK_OPEN_BRACKET:
- if (e.ctrlKey) {
- return this.props.dispatch(consoleActions.hideCommand());
- }
- break;
- case KeyboardEvent.DOM_VK_M:
- if (e.ctrlKey) {
- return this.doEnter(e);
- }
- break;
- case KeyboardEvent.DOM_VK_N:
- if (e.ctrlKey) {
- this.selectNext(e);
- }
- break;
- case KeyboardEvent.DOM_VK_P:
- if (e.ctrlKey) {
- this.selectPrev(e);
- }
- break;
- }
- }
-
- onChange(e) {
- let text = e.target.value;
- this.props.dispatch(consoleActions.setConsoleText(text));
- if (this.props.mode === 'command') {
- this.props.dispatch(consoleActions.getCompletions(text));
- }
- }
-
-
- componentDidUpdate(prevProps) {
- if (!this.input) {
- return;
- }
- if (prevProps.mode !== 'command' && this.props.mode === 'command') {
- this.props.dispatch(
- consoleActions.getCompletions(this.props.consoleText));
- this.focus();
- } else if (prevProps.mode !== 'find' && this.props.mode === 'find') {
- this.focus();
- }
- }
-
- render() {
- switch (this.props.mode) {
- case 'command':
- case 'find':
- return
-
- { this.input = c; }}
- mode={this.props.mode}
- onBlur={this.onBlur.bind(this)}
- onKeyDown={this.onKeyDown.bind(this)}
- onChange={this.onChange.bind(this)}
- value={this.props.consoleText}
- />
-
;
- case 'info':
- case 'error':
- return
- { this.props.messageText }
- ;
- default:
- return null;
- }
- }
-
- focus() {
- window.focus();
- this.input.focus();
- }
-}
-
-Console.propTypes = {
- mode: PropTypes.string,
- consoleText: PropTypes.string,
- messageText: PropTypes.string,
- children: PropTypes.string,
-};
-
-const mapStateToProps = state => state;
-export default connect(mapStateToProps)(Console);
diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx
new file mode 100644
index 0000000..5427e43
--- /dev/null
+++ b/src/console/components/Console.tsx
@@ -0,0 +1,149 @@
+import './console.scss';
+import { connect } from 'react-redux';
+import React from 'react';
+import PropTypes from 'prop-types';
+import Input from './console/Input';
+import Completion from './console/Completion';
+import Message from './console/Message';
+import * as consoleActions from '../../console/actions/console';
+
+const COMPLETION_MAX_ITEMS = 33;
+
+class Console extends React.Component {
+ onBlur() {
+ if (this.props.mode === 'command' || this.props.mode === 'find') {
+ return this.props.dispatch(consoleActions.hideCommand());
+ }
+ }
+
+ doEnter(e) {
+ e.stopPropagation();
+ e.preventDefault();
+
+ let value = e.target.value;
+ if (this.props.mode === 'command') {
+ return this.props.dispatch(consoleActions.enterCommand(value));
+ } else if (this.props.mode === 'find') {
+ return this.props.dispatch(consoleActions.enterFind(value));
+ }
+ }
+
+ selectNext(e) {
+ this.props.dispatch(consoleActions.completionNext());
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ selectPrev(e) {
+ this.props.dispatch(consoleActions.completionPrev());
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ onKeyDown(e) {
+ if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) {
+ this.props.dispatch(consoleActions.hideCommand());
+ }
+ switch (e.keyCode) {
+ case KeyboardEvent.DOM_VK_ESCAPE:
+ return this.props.dispatch(consoleActions.hideCommand());
+ case KeyboardEvent.DOM_VK_RETURN:
+ return this.doEnter(e);
+ case KeyboardEvent.DOM_VK_TAB:
+ if (e.shiftKey) {
+ this.props.dispatch(consoleActions.completionPrev());
+ } else {
+ this.props.dispatch(consoleActions.completionNext());
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ break;
+ case KeyboardEvent.DOM_VK_OPEN_BRACKET:
+ if (e.ctrlKey) {
+ return this.props.dispatch(consoleActions.hideCommand());
+ }
+ break;
+ case KeyboardEvent.DOM_VK_M:
+ if (e.ctrlKey) {
+ return this.doEnter(e);
+ }
+ break;
+ case KeyboardEvent.DOM_VK_N:
+ if (e.ctrlKey) {
+ this.selectNext(e);
+ }
+ break;
+ case KeyboardEvent.DOM_VK_P:
+ if (e.ctrlKey) {
+ this.selectPrev(e);
+ }
+ break;
+ }
+ }
+
+ onChange(e) {
+ let text = e.target.value;
+ this.props.dispatch(consoleActions.setConsoleText(text));
+ if (this.props.mode === 'command') {
+ this.props.dispatch(consoleActions.getCompletions(text));
+ }
+ }
+
+
+ componentDidUpdate(prevProps) {
+ if (!this.input) {
+ return;
+ }
+ if (prevProps.mode !== 'command' && this.props.mode === 'command') {
+ this.props.dispatch(
+ consoleActions.getCompletions(this.props.consoleText));
+ this.focus();
+ } else if (prevProps.mode !== 'find' && this.props.mode === 'find') {
+ this.focus();
+ }
+ }
+
+ render() {
+ switch (this.props.mode) {
+ case 'command':
+ case 'find':
+ return
+
+ { this.input = c; }}
+ mode={this.props.mode}
+ onBlur={this.onBlur.bind(this)}
+ onKeyDown={this.onKeyDown.bind(this)}
+ onChange={this.onChange.bind(this)}
+ value={this.props.consoleText}
+ />
+
;
+ case 'info':
+ case 'error':
+ return
+ { this.props.messageText }
+ ;
+ default:
+ return null;
+ }
+ }
+
+ focus() {
+ window.focus();
+ this.input.focus();
+ }
+}
+
+Console.propTypes = {
+ mode: PropTypes.string,
+ consoleText: PropTypes.string,
+ messageText: PropTypes.string,
+ children: PropTypes.string,
+};
+
+const mapStateToProps = state => state;
+export default connect(mapStateToProps)(Console);
diff --git a/src/console/components/console/Completion.jsx b/src/console/components/console/Completion.jsx
deleted file mode 100644
index 5477cb6..0000000
--- a/src/console/components/console/Completion.jsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import CompletionItem from './CompletionItem';
-import CompletionTitle from './CompletionTitle';
-
-class Completion extends React.Component {
- constructor() {
- super();
- this.state = { viewOffset: 0, select: -1 };
- }
-
- static getDerivedStateFromProps(nextProps, prevState) {
- if (prevState.select === nextProps.select) {
- return null;
- }
-
- let viewSelect = (() => {
- let index = 0;
- for (let i = 0; i < nextProps.completions.length; ++i) {
- ++index;
- let g = nextProps.completions[i];
- if (nextProps.select + i + 1 < index + g.items.length) {
- return nextProps.select + i + 1;
- }
- index += g.items.length;
- }
- })();
-
- let viewOffset = 0;
- if (nextProps.select < 0) {
- viewOffset = 0;
- } else if (prevState.select < nextProps.select) {
- viewOffset = Math.max(prevState.viewOffset,
- viewSelect - nextProps.size + 1);
- } else if (prevState.select > nextProps.select) {
- viewOffset = Math.min(prevState.viewOffset, viewSelect);
- }
- return { viewOffset, select: nextProps.select };
- }
-
- render() {
- let eles = [];
- let index = 0;
-
- for (let group of this.props.completions) {
- eles.push();
- for (let item of group.items) {
- eles.push();
- ++index;
- }
- }
-
- let viewOffset = this.state.viewOffset;
- eles = eles.slice(viewOffset, viewOffset + this.props.size);
-
- return (
-
- );
- }
-}
-
-Completion.propTypes = {
- select: PropTypes.number,
- size: PropTypes.number,
- completions: PropTypes.arrayOf(PropTypes.shape({
- name: PropTypes.string,
- items: PropTypes.arrayOf(PropTypes.shape({
- icon: PropTypes.string,
- caption: PropTypes.string,
- url: PropTypes.string,
- })),
- })),
-};
-
-export default Completion;
diff --git a/src/console/components/console/Completion.tsx b/src/console/components/console/Completion.tsx
new file mode 100644
index 0000000..5477cb6
--- /dev/null
+++ b/src/console/components/console/Completion.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import CompletionItem from './CompletionItem';
+import CompletionTitle from './CompletionTitle';
+
+class Completion extends React.Component {
+ constructor() {
+ super();
+ this.state = { viewOffset: 0, select: -1 };
+ }
+
+ static getDerivedStateFromProps(nextProps, prevState) {
+ if (prevState.select === nextProps.select) {
+ return null;
+ }
+
+ let viewSelect = (() => {
+ let index = 0;
+ for (let i = 0; i < nextProps.completions.length; ++i) {
+ ++index;
+ let g = nextProps.completions[i];
+ if (nextProps.select + i + 1 < index + g.items.length) {
+ return nextProps.select + i + 1;
+ }
+ index += g.items.length;
+ }
+ })();
+
+ let viewOffset = 0;
+ if (nextProps.select < 0) {
+ viewOffset = 0;
+ } else if (prevState.select < nextProps.select) {
+ viewOffset = Math.max(prevState.viewOffset,
+ viewSelect - nextProps.size + 1);
+ } else if (prevState.select > nextProps.select) {
+ viewOffset = Math.min(prevState.viewOffset, viewSelect);
+ }
+ return { viewOffset, select: nextProps.select };
+ }
+
+ render() {
+ let eles = [];
+ let index = 0;
+
+ for (let group of this.props.completions) {
+ eles.push();
+ for (let item of group.items) {
+ eles.push();
+ ++index;
+ }
+ }
+
+ let viewOffset = this.state.viewOffset;
+ eles = eles.slice(viewOffset, viewOffset + this.props.size);
+
+ return (
+
+ );
+ }
+}
+
+Completion.propTypes = {
+ select: PropTypes.number,
+ size: PropTypes.number,
+ completions: PropTypes.arrayOf(PropTypes.shape({
+ name: PropTypes.string,
+ items: PropTypes.arrayOf(PropTypes.shape({
+ icon: PropTypes.string,
+ caption: PropTypes.string,
+ url: PropTypes.string,
+ })),
+ })),
+};
+
+export default Completion;
diff --git a/src/console/components/console/CompletionItem.jsx b/src/console/components/console/CompletionItem.jsx
deleted file mode 100644
index 3dc552b..0000000
--- a/src/console/components/console/CompletionItem.jsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-const CompletionItem = (props) => {
- let className = 'vimvixen-console-completion-item';
- if (props.highlight) {
- className += ' vimvixen-completion-selected';
- }
- return
- {props.caption}
- {props.url}
- ;
-};
-
-CompletionItem.propTypes = {
- highlight: PropTypes.bool,
- caption: PropTypes.string,
- url: PropTypes.string,
-};
-
-export default CompletionItem;
diff --git a/src/console/components/console/CompletionItem.tsx b/src/console/components/console/CompletionItem.tsx
new file mode 100644
index 0000000..3dc552b
--- /dev/null
+++ b/src/console/components/console/CompletionItem.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const CompletionItem = (props) => {
+ let className = 'vimvixen-console-completion-item';
+ if (props.highlight) {
+ className += ' vimvixen-completion-selected';
+ }
+ return
+ {props.caption}
+ {props.url}
+ ;
+};
+
+CompletionItem.propTypes = {
+ highlight: PropTypes.bool,
+ caption: PropTypes.string,
+ url: PropTypes.string,
+};
+
+export default CompletionItem;
diff --git a/src/console/components/console/CompletionTitle.jsx b/src/console/components/console/CompletionTitle.jsx
deleted file mode 100644
index 4fcba3f..0000000
--- a/src/console/components/console/CompletionTitle.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-const CompletionTitle = (props) => {
- return
- {props.title}
- ;
-};
-
-CompletionTitle.propTypes = {
- title: PropTypes.string,
-};
-
-export default CompletionTitle;
diff --git a/src/console/components/console/CompletionTitle.tsx b/src/console/components/console/CompletionTitle.tsx
new file mode 100644
index 0000000..4fcba3f
--- /dev/null
+++ b/src/console/components/console/CompletionTitle.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const CompletionTitle = (props) => {
+ return
+ {props.title}
+ ;
+};
+
+CompletionTitle.propTypes = {
+ title: PropTypes.string,
+};
+
+export default CompletionTitle;
diff --git a/src/console/components/console/Input.jsx b/src/console/components/console/Input.jsx
deleted file mode 100644
index cbd3348..0000000
--- a/src/console/components/console/Input.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-class Input extends React.Component {
- focus() {
- this.input.focus();
- }
-
- render() {
- let prompt = '';
- if (this.props.mode === 'command') {
- prompt = ':';
- } else if (this.props.mode === 'find') {
- prompt = '/';
- }
-
- return (
-
-
- { prompt }
-
- { this.input = c; }}
- onBlur={this.props.onBlur}
- onKeyDown={this.props.onKeyDown}
- onChange={this.props.onChange}
- value={this.props.value}
- />
-
- );
- }
-}
-
-Input.propTypes = {
- mode: PropTypes.string,
- value: PropTypes.string,
- onBlur: PropTypes.func,
- onKeyDown: PropTypes.func,
- onChange: PropTypes.func,
-};
-
-export default Input;
diff --git a/src/console/components/console/Input.tsx b/src/console/components/console/Input.tsx
new file mode 100644
index 0000000..cbd3348
--- /dev/null
+++ b/src/console/components/console/Input.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class Input extends React.Component {
+ focus() {
+ this.input.focus();
+ }
+
+ render() {
+ let prompt = '';
+ if (this.props.mode === 'command') {
+ prompt = ':';
+ } else if (this.props.mode === 'find') {
+ prompt = '/';
+ }
+
+ return (
+
+
+ { prompt }
+
+ { this.input = c; }}
+ onBlur={this.props.onBlur}
+ onKeyDown={this.props.onKeyDown}
+ onChange={this.props.onChange}
+ value={this.props.value}
+ />
+
+ );
+ }
+}
+
+Input.propTypes = {
+ mode: PropTypes.string,
+ value: PropTypes.string,
+ onBlur: PropTypes.func,
+ onKeyDown: PropTypes.func,
+ onChange: PropTypes.func,
+};
+
+export default Input;
diff --git a/src/console/components/console/Message.jsx b/src/console/components/console/Message.jsx
deleted file mode 100644
index dd96248..0000000
--- a/src/console/components/console/Message.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-const Message = (props) => {
- switch (props.mode) {
- case 'error':
- return (
-
- { props.children }
-
- );
- case 'info':
- return (
-
- { props.children }
-
- );
- }
-};
-
-Message.propTypes = {
- children: PropTypes.string,
-};
-
-export default Message;
diff --git a/src/console/components/console/Message.tsx b/src/console/components/console/Message.tsx
new file mode 100644
index 0000000..dd96248
--- /dev/null
+++ b/src/console/components/console/Message.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const Message = (props) => {
+ switch (props.mode) {
+ case 'error':
+ return (
+
+ { props.children }
+
+ );
+ case 'info':
+ return (
+
+ { props.children }
+
+ );
+ }
+};
+
+Message.propTypes = {
+ children: PropTypes.string,
+};
+
+export default Message;
diff --git a/src/console/index.jsx b/src/console/index.jsx
deleted file mode 100644
index 3190a9a..0000000
--- a/src/console/index.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import messages from 'shared/messages';
-import reducers from 'console/reducers';
-import { createStore, applyMiddleware } from 'redux';
-import promise from 'redux-promise';
-import * as consoleActions from 'console/actions/console';
-import { Provider } from 'react-redux';
-import Console from './components/Console';
-import React from 'react';
-import ReactDOM from 'react-dom';
-
-const store = createStore(
- reducers,
- applyMiddleware(promise),
-);
-
-window.addEventListener('load', () => {
- let wrapper = document.getElementById('vimvixen-console');
- ReactDOM.render(
-
-
- ,
- wrapper);
-});
-
-const onMessage = (message) => {
- switch (message.type) {
- case messages.CONSOLE_SHOW_COMMAND:
- return store.dispatch(consoleActions.showCommand(message.command));
- case messages.CONSOLE_SHOW_FIND:
- return store.dispatch(consoleActions.showFind());
- case messages.CONSOLE_SHOW_ERROR:
- return store.dispatch(consoleActions.showError(message.text));
- case messages.CONSOLE_SHOW_INFO:
- return store.dispatch(consoleActions.showInfo(message.text));
- case messages.CONSOLE_HIDE:
- return store.dispatch(consoleActions.hide());
- }
-};
-
-browser.runtime.onMessage.addListener(onMessage);
-let port = browser.runtime.connect({ name: 'vimvixen-console' });
-port.onMessage.addListener(onMessage);
diff --git a/src/console/index.tsx b/src/console/index.tsx
new file mode 100644
index 0000000..3190a9a
--- /dev/null
+++ b/src/console/index.tsx
@@ -0,0 +1,42 @@
+import messages from 'shared/messages';
+import reducers from 'console/reducers';
+import { createStore, applyMiddleware } from 'redux';
+import promise from 'redux-promise';
+import * as consoleActions from 'console/actions/console';
+import { Provider } from 'react-redux';
+import Console from './components/Console';
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+const store = createStore(
+ reducers,
+ applyMiddleware(promise),
+);
+
+window.addEventListener('load', () => {
+ let wrapper = document.getElementById('vimvixen-console');
+ ReactDOM.render(
+
+
+ ,
+ wrapper);
+});
+
+const onMessage = (message) => {
+ switch (message.type) {
+ case messages.CONSOLE_SHOW_COMMAND:
+ return store.dispatch(consoleActions.showCommand(message.command));
+ case messages.CONSOLE_SHOW_FIND:
+ return store.dispatch(consoleActions.showFind());
+ case messages.CONSOLE_SHOW_ERROR:
+ return store.dispatch(consoleActions.showError(message.text));
+ case messages.CONSOLE_SHOW_INFO:
+ return store.dispatch(consoleActions.showInfo(message.text));
+ case messages.CONSOLE_HIDE:
+ return store.dispatch(consoleActions.hide());
+ }
+};
+
+browser.runtime.onMessage.addListener(onMessage);
+let port = browser.runtime.connect({ name: 'vimvixen-console' });
+port.onMessage.addListener(onMessage);
diff --git a/src/console/reducers/index.js b/src/console/reducers/index.js
deleted file mode 100644
index 614a72f..0000000
--- a/src/console/reducers/index.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import actions from 'console/actions';
-
-const defaultState = {
- mode: '',
- messageText: '',
- consoleText: '',
- completionSource: '',
- completions: [],
- select: -1,
- viewIndex: 0,
-};
-
-const nextSelection = (state) => {
- if (state.completions.length === 0) {
- return -1;
- }
- if (state.select < 0) {
- return 0;
- }
-
- let length = state.completions
- .map(g => g.items.length)
- .reduce((x, y) => x + y);
- if (state.select + 1 < length) {
- return state.select + 1;
- }
- return -1;
-};
-
-const prevSelection = (state) => {
- let length = state.completions
- .map(g => g.items.length)
- .reduce((x, y) => x + y);
- if (state.select < 0) {
- return length - 1;
- }
- return state.select - 1;
-};
-
-const nextConsoleText = (completions, select, defaults) => {
- if (select < 0) {
- return defaults;
- }
- let items = completions.map(g => g.items).reduce((g1, g2) => g1.concat(g2));
- return items[select].content;
-};
-
-// eslint-disable-next-line max-lines-per-function
-export default function reducer(state = defaultState, action = {}) {
- switch (action.type) {
- case actions.CONSOLE_HIDE:
- return { ...state,
- mode: '', };
- case actions.CONSOLE_SHOW_COMMAND:
- return { ...state,
- mode: 'command',
- consoleText: action.text,
- completions: []};
- case actions.CONSOLE_SHOW_FIND:
- return { ...state,
- mode: 'find',
- consoleText: '',
- completions: []};
- case actions.CONSOLE_SHOW_ERROR:
- return { ...state,
- mode: 'error',
- messageText: action.text, };
- case actions.CONSOLE_SHOW_INFO:
- return { ...state,
- mode: 'info',
- messageText: action.text, };
- case actions.CONSOLE_HIDE_COMMAND:
- return {
- ...state,
- mode: state.mode === 'command' || state.mode === 'find' ? '' : state.mode,
- };
- case actions.CONSOLE_SET_CONSOLE_TEXT:
- return { ...state,
- consoleText: action.consoleText, };
- case actions.CONSOLE_SET_COMPLETIONS:
- return { ...state,
- completions: action.completions,
- completionSource: action.completionSource,
- select: -1 };
- case actions.CONSOLE_COMPLETION_NEXT: {
- let select = nextSelection(state);
- return { ...state,
- select: select,
- consoleText: nextConsoleText(
- state.completions, select, state.completionSource) };
- }
- case actions.CONSOLE_COMPLETION_PREV: {
- let select = prevSelection(state);
- return { ...state,
- select: select,
- consoleText: nextConsoleText(
- state.completions, select, state.completionSource) };
- }
- default:
- return state;
- }
-}
diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts
new file mode 100644
index 0000000..614a72f
--- /dev/null
+++ b/src/console/reducers/index.ts
@@ -0,0 +1,102 @@
+import actions from 'console/actions';
+
+const defaultState = {
+ mode: '',
+ messageText: '',
+ consoleText: '',
+ completionSource: '',
+ completions: [],
+ select: -1,
+ viewIndex: 0,
+};
+
+const nextSelection = (state) => {
+ if (state.completions.length === 0) {
+ return -1;
+ }
+ if (state.select < 0) {
+ return 0;
+ }
+
+ let length = state.completions
+ .map(g => g.items.length)
+ .reduce((x, y) => x + y);
+ if (state.select + 1 < length) {
+ return state.select + 1;
+ }
+ return -1;
+};
+
+const prevSelection = (state) => {
+ let length = state.completions
+ .map(g => g.items.length)
+ .reduce((x, y) => x + y);
+ if (state.select < 0) {
+ return length - 1;
+ }
+ return state.select - 1;
+};
+
+const nextConsoleText = (completions, select, defaults) => {
+ if (select < 0) {
+ return defaults;
+ }
+ let items = completions.map(g => g.items).reduce((g1, g2) => g1.concat(g2));
+ return items[select].content;
+};
+
+// eslint-disable-next-line max-lines-per-function
+export default function reducer(state = defaultState, action = {}) {
+ switch (action.type) {
+ case actions.CONSOLE_HIDE:
+ return { ...state,
+ mode: '', };
+ case actions.CONSOLE_SHOW_COMMAND:
+ return { ...state,
+ mode: 'command',
+ consoleText: action.text,
+ completions: []};
+ case actions.CONSOLE_SHOW_FIND:
+ return { ...state,
+ mode: 'find',
+ consoleText: '',
+ completions: []};
+ case actions.CONSOLE_SHOW_ERROR:
+ return { ...state,
+ mode: 'error',
+ messageText: action.text, };
+ case actions.CONSOLE_SHOW_INFO:
+ return { ...state,
+ mode: 'info',
+ messageText: action.text, };
+ case actions.CONSOLE_HIDE_COMMAND:
+ return {
+ ...state,
+ mode: state.mode === 'command' || state.mode === 'find' ? '' : state.mode,
+ };
+ case actions.CONSOLE_SET_CONSOLE_TEXT:
+ return { ...state,
+ consoleText: action.consoleText, };
+ case actions.CONSOLE_SET_COMPLETIONS:
+ return { ...state,
+ completions: action.completions,
+ completionSource: action.completionSource,
+ select: -1 };
+ case actions.CONSOLE_COMPLETION_NEXT: {
+ let select = nextSelection(state);
+ return { ...state,
+ select: select,
+ consoleText: nextConsoleText(
+ state.completions, select, state.completionSource) };
+ }
+ case actions.CONSOLE_COMPLETION_PREV: {
+ let select = prevSelection(state);
+ return { ...state,
+ select: select,
+ consoleText: nextConsoleText(
+ state.completions, select, state.completionSource) };
+ }
+ default:
+ return state;
+ }
+}
--
cgit v1.2.3
From 0452370df43cc4263f268e7064f824d7e6e489b3 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka
Date: Wed, 1 May 2019 23:10:37 +0900
Subject: Types on src/console
---
src/background/usecases/CompletionsUseCase.ts | 12 ++--
src/console/actions/console.ts | 34 +++++-----
src/console/actions/index.ts | 76 ++++++++++++++++++----
src/console/components/Console.tsx | 43 +++++++-----
src/console/components/console/Completion.tsx | 45 ++++++++-----
src/console/components/console/CompletionItem.tsx | 9 ++-
src/console/components/console/CompletionTitle.tsx | 11 ++--
src/console/components/console/Input.tsx | 31 +++++----
src/console/components/console/Message.tsx | 13 ++--
src/console/index.tsx | 10 +--
src/console/reducers/index.ts | 23 +++++--
test/console/actions/console.test.ts | 2 +-
test/console/reducers/console.test.ts | 2 +-
13 files changed, 206 insertions(+), 105 deletions(-)
(limited to 'src/console')
diff --git a/src/background/usecases/CompletionsUseCase.ts b/src/background/usecases/CompletionsUseCase.ts
index 037d6eb..f3a808b 100644
--- a/src/background/usecases/CompletionsUseCase.ts
+++ b/src/background/usecases/CompletionsUseCase.ts
@@ -1,4 +1,3 @@
-import Completions from '../domains/Completions';
import CompletionGroup from '../domains/CompletionGroup';
import CommandDocs from '../domains/CommandDocs';
import CompletionsRepository from '../repositories/CompletionsRepository';
@@ -25,7 +24,7 @@ export default class CompletionsUseCase {
this.settingRepository = new SettingRepository();
}
- queryConsoleCommand(prefix: string): Promise {
+ queryConsoleCommand(prefix: string): Promise {
let keys = Object.keys(CommandDocs);
let items = keys
.filter(name => name.startsWith(prefix))
@@ -38,10 +37,10 @@ export default class CompletionsUseCase {
if (items.length === 0) {
return Promise.resolve([]);
}
- return Promise.resolve([{ name: 'Console CompletionGroup', items }]);
+ return Promise.resolve([{ name: 'Console Command', items }]);
}
- async queryOpen(name: string, keywords: string): Promise {
+ async queryOpen(name: string, keywords: string): Promise {
let settings = await this.settingRepository.get();
let groups: CompletionGroup[] = [];
@@ -71,7 +70,10 @@ export default class CompletionsUseCase {
}
// eslint-disable-next-line max-statements
- async queryBuffer(name: string, keywords: string): Promise {
+ async queryBuffer(
+ name: string,
+ keywords: string,
+ ): Promise {
let lastId = await this.tabPresenter.getLastSelectedId();
let trimmed = keywords.trim();
let tabs: Tab[] = [];
diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts
index 3713a76..ceb419c 100644
--- a/src/console/actions/console.ts
+++ b/src/console/actions/console.ts
@@ -1,40 +1,40 @@
-import messages from 'shared/messages';
-import actions from 'console/actions';
+import messages from '../../shared/messages';
+import * as actions from './index';
-const hide = () => {
+const hide = (): actions.ConsoleAction => {
return {
type: actions.CONSOLE_HIDE,
};
};
-const showCommand = (text) => {
+const showCommand = (text: string): actions.ConsoleAction => {
return {
type: actions.CONSOLE_SHOW_COMMAND,
text: text
};
};
-const showFind = () => {
+const showFind = (): actions.ConsoleAction => {
return {
type: actions.CONSOLE_SHOW_FIND,
};
};
-const showError = (text) => {
+const showError = (text: string): actions.ConsoleAction => {
return {
type: actions.CONSOLE_SHOW_ERROR,
text: text
};
};
-const showInfo = (text) => {
+const showInfo = (text: string): actions.ConsoleAction => {
return {
type: actions.CONSOLE_SHOW_INFO,
text: text
};
};
-const hideCommand = () => {
+const hideCommand = (): actions.ConsoleAction => {
window.top.postMessage(JSON.stringify({
type: messages.CONSOLE_UNFOCUS,
}), '*');
@@ -43,15 +43,17 @@ const hideCommand = () => {
};
};
-const enterCommand = async(text) => {
+const enterCommand = async(
+ text: string,
+): Promise => {
await browser.runtime.sendMessage({
type: messages.CONSOLE_ENTER_COMMAND,
text,
});
- return hideCommand(text);
+ return hideCommand();
};
-const enterFind = (text) => {
+const enterFind = (text: string): actions.ConsoleAction => {
window.top.postMessage(JSON.stringify({
type: messages.CONSOLE_ENTER_FIND,
text,
@@ -59,14 +61,14 @@ const enterFind = (text) => {
return hideCommand();
};
-const setConsoleText = (consoleText) => {
+const setConsoleText = (consoleText: string): actions.ConsoleAction => {
return {
type: actions.CONSOLE_SET_CONSOLE_TEXT,
consoleText,
};
};
-const getCompletions = async(text) => {
+const getCompletions = async(text: string): Promise => {
let completions = await browser.runtime.sendMessage({
type: messages.CONSOLE_QUERY_COMPLETIONS,
text,
@@ -78,13 +80,13 @@ const getCompletions = async(text) => {
};
};
-const completionNext = () => {
+const completionNext = (): actions.ConsoleAction => {
return {
type: actions.CONSOLE_COMPLETION_NEXT,
};
};
-const completionPrev = () => {
+const completionPrev = (): actions.ConsoleAction => {
return {
type: actions.CONSOLE_COMPLETION_PREV,
};
@@ -92,5 +94,5 @@ const completionPrev = () => {
export {
hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText,
- enterCommand, enterFind, getCompletions, completionNext, completionPrev
+ enterCommand, enterFind, getCompletions, completionNext, completionPrev,
};
diff --git a/src/console/actions/index.ts b/src/console/actions/index.ts
index b394179..3770496 100644
--- a/src/console/actions/index.ts
+++ b/src/console/actions/index.ts
@@ -1,13 +1,63 @@
-export default {
- // console commands
- CONSOLE_HIDE: 'console.hide',
- CONSOLE_SHOW_COMMAND: 'console.show.command',
- CONSOLE_SHOW_ERROR: 'console.show.error',
- CONSOLE_SHOW_INFO: 'console.show.info',
- CONSOLE_HIDE_COMMAND: 'console.hide.command',
- CONSOLE_SET_CONSOLE_TEXT: 'console.set.command',
- CONSOLE_SET_COMPLETIONS: 'console.set.completions',
- CONSOLE_COMPLETION_NEXT: 'console.completion.next',
- CONSOLE_COMPLETION_PREV: 'console.completion.prev',
- CONSOLE_SHOW_FIND: 'console.show.find',
-};
+// console commands
+export const CONSOLE_HIDE = 'console.hide';
+export const CONSOLE_SHOW_COMMAND = 'console.show.command';
+export const CONSOLE_SHOW_ERROR = 'console.show.error';
+export const CONSOLE_SHOW_INFO = 'console.show.info';
+export const CONSOLE_HIDE_COMMAND = 'console.hide.command';
+export const CONSOLE_SET_CONSOLE_TEXT = 'console.set.command';
+export const CONSOLE_SET_COMPLETIONS = 'console.set.completions';
+export const CONSOLE_COMPLETION_NEXT = 'console.completion.next';
+export const CONSOLE_COMPLETION_PREV = 'console.completion.prev';
+export const CONSOLE_SHOW_FIND = 'console.show.find';
+
+interface HideAction {
+ type: typeof CONSOLE_HIDE;
+}
+
+interface ShowCommand {
+ type: typeof CONSOLE_SHOW_COMMAND;
+ text: string;
+}
+
+interface ShowFindAction {
+ type: typeof CONSOLE_SHOW_FIND;
+}
+
+interface ShowErrorAction {
+ type: typeof CONSOLE_SHOW_ERROR;
+ text: string;
+}
+
+interface ShowInfoAction {
+ type: typeof CONSOLE_SHOW_INFO;
+ text: string;
+}
+
+interface HideCommandAction {
+ type: typeof CONSOLE_HIDE_COMMAND;
+}
+
+interface SetConsoleTextAction {
+ type: typeof CONSOLE_SET_CONSOLE_TEXT;
+ consoleText: string;
+}
+
+interface SetCompletionsAction {
+ type: typeof CONSOLE_SET_COMPLETIONS;
+ completions: any[];
+ completionSource: string;
+}
+
+interface CompletionNextAction {
+ type: typeof CONSOLE_COMPLETION_NEXT;
+}
+
+interface CompletionPrevAction {
+ type: typeof CONSOLE_COMPLETION_PREV;
+}
+
+export type ConsoleAction =
+ HideAction | ShowCommand | ShowFindAction | ShowErrorAction |
+ ShowInfoAction | HideCommandAction | SetConsoleTextAction |
+ SetCompletionsAction | CompletionNextAction | CompletionPrevAction;
+
diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx
index 5427e43..09c0f50 100644
--- a/src/console/components/Console.tsx
+++ b/src/console/components/Console.tsx
@@ -1,7 +1,6 @@
import './console.scss';
import { connect } from 'react-redux';
import React from 'react';
-import PropTypes from 'prop-types';
import Input from './console/Input';
import Completion from './console/Completion';
import Message from './console/Message';
@@ -9,14 +8,29 @@ import * as consoleActions from '../../console/actions/console';
const COMPLETION_MAX_ITEMS = 33;
-class Console extends React.Component {
+interface Props {
+ mode?: string;
+ consoleText?: string;
+ messageText?: string;
+ children?: string;
+}
+
+class Console extends React.Component {
+ private input: HTMLInputElement | null;
+
+ constructor(props: Props) {
+ super(props);
+
+ this.input = null;
+ }
+
onBlur() {
if (this.props.mode === 'command' || this.props.mode === 'find') {
return this.props.dispatch(consoleActions.hideCommand());
}
}
- doEnter(e) {
+ doEnter(e: React.KeyboardEvent) {
e.stopPropagation();
e.preventDefault();
@@ -28,19 +42,19 @@ class Console extends React.Component {
}
}
- selectNext(e) {
+ selectNext(e: React.KeyboardEvent) {
this.props.dispatch(consoleActions.completionNext());
e.stopPropagation();
e.preventDefault();
}
- selectPrev(e) {
+ selectPrev(e: React.KeyboardEvent) {
this.props.dispatch(consoleActions.completionPrev());
e.stopPropagation();
e.preventDefault();
}
- onKeyDown(e) {
+ onKeyDown(e: React.KeyboardEvent) {
if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) {
this.props.dispatch(consoleActions.hideCommand());
}
@@ -81,7 +95,7 @@ class Console extends React.Component {
}
}
- onChange(e) {
+ onChange(e: React.ChangeEvent) {
let text = e.target.value;
this.props.dispatch(consoleActions.setConsoleText(text));
if (this.props.mode === 'command') {
@@ -90,7 +104,7 @@ class Console extends React.Component {
}
- componentDidUpdate(prevProps) {
+ componentDidUpdate(prevProps: Props) {
if (!this.input) {
return;
}
@@ -134,16 +148,11 @@ class Console extends React.Component {
focus() {
window.focus();
- this.input.focus();
+ if (this.input) {
+ this.input.focus();
+ }
}
}
-Console.propTypes = {
- mode: PropTypes.string,
- consoleText: PropTypes.string,
- messageText: PropTypes.string,
- children: PropTypes.string,
-};
-
-const mapStateToProps = state => state;
+const mapStateToProps = (state: any) => state;
export default connect(mapStateToProps)(Console);
diff --git a/src/console/components/console/Completion.tsx b/src/console/components/console/Completion.tsx
index 5477cb6..169a39c 100644
--- a/src/console/components/console/Completion.tsx
+++ b/src/console/components/console/Completion.tsx
@@ -1,15 +1,36 @@
import React from 'react';
-import PropTypes from 'prop-types';
import CompletionItem from './CompletionItem';
import CompletionTitle from './CompletionTitle';
-class Completion extends React.Component {
- constructor() {
- super();
+interface Item {
+ icon?: string;
+ caption?: string;
+ url?: string;
+}
+
+interface Group {
+ name: string;
+ items: Item[];
+}
+
+interface Props {
+ select: number;
+ size: number;
+ completions: Group[];
+}
+
+interface State {
+ viewOffset: number;
+ select: number;
+}
+
+class Completion extends React.Component {
+ constructor(props: Props) {
+ super(props);
this.state = { viewOffset: 0, select: -1 };
}
- static getDerivedStateFromProps(nextProps, prevState) {
+ static getDerivedStateFromProps(nextProps: Props, prevState: State) {
if (prevState.select === nextProps.select) {
return null;
}
@@ -24,6 +45,7 @@ class Completion extends React.Component {
}
index += g.items.length;
}
+ return -1;
})();
let viewOffset = 0;
@@ -70,17 +92,4 @@ class Completion extends React.Component {
}
}
-Completion.propTypes = {
- select: PropTypes.number,
- size: PropTypes.number,
- completions: PropTypes.arrayOf(PropTypes.shape({
- name: PropTypes.string,
- items: PropTypes.arrayOf(PropTypes.shape({
- icon: PropTypes.string,
- caption: PropTypes.string,
- url: PropTypes.string,
- })),
- })),
-};
-
export default Completion;
diff --git a/src/console/components/console/CompletionItem.tsx b/src/console/components/console/CompletionItem.tsx
index 3dc552b..1cbf3de 100644
--- a/src/console/components/console/CompletionItem.tsx
+++ b/src/console/components/console/CompletionItem.tsx
@@ -1,7 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
-const CompletionItem = (props) => {
+interface Props {
+ highlight: boolean;
+ caption?: string;
+ url?: string;
+ icon?: string;
+}
+
+const CompletionItem = (props: Props) => {
let className = 'vimvixen-console-completion-item';
if (props.highlight) {
className += ' vimvixen-completion-selected';
diff --git a/src/console/components/console/CompletionTitle.tsx b/src/console/components/console/CompletionTitle.tsx
index 4fcba3f..2543619 100644
--- a/src/console/components/console/CompletionTitle.tsx
+++ b/src/console/components/console/CompletionTitle.tsx
@@ -1,14 +1,13 @@
import React from 'react';
-import PropTypes from 'prop-types';
-const CompletionTitle = (props) => {
+interface Props {
+ title: string;
+}
+
+const CompletionTitle = (props: Props) => {
return
{props.title}
;
};
-CompletionTitle.propTypes = {
- title: PropTypes.string,
-};
-
export default CompletionTitle;
diff --git a/src/console/components/console/Input.tsx b/src/console/components/console/Input.tsx
index cbd3348..d0348bd 100644
--- a/src/console/components/console/Input.tsx
+++ b/src/console/components/console/Input.tsx
@@ -1,9 +1,26 @@
import React from 'react';
-import PropTypes from 'prop-types';
-class Input extends React.Component {
+interface Props {
+ mode: string;
+ value: string;
+ onBlur: (e: React.FocusEvent) => void;
+ onKeyDown: (e: React.KeyboardEvent) => void;
+ onChange: (e: React.ChangeEvent) => void;
+}
+
+class Input extends React.Component {
+ private input: HTMLInputElement | null;
+
+ constructor(props: Props) {
+ super(props);
+
+ this.input = null;
+ }
+
focus() {
- this.input.focus();
+ if (this.input) {
+ this.input.focus();
+ }
}
render() {
@@ -32,12 +49,4 @@ class Input extends React.Component {
}
}
-Input.propTypes = {
- mode: PropTypes.string,
- value: PropTypes.string,
- onBlur: PropTypes.func,
- onKeyDown: PropTypes.func,
- onChange: PropTypes.func,
-};
-
export default Input;
diff --git a/src/console/components/console/Message.tsx b/src/console/components/console/Message.tsx
index dd96248..07a929e 100644
--- a/src/console/components/console/Message.tsx
+++ b/src/console/components/console/Message.tsx
@@ -1,7 +1,11 @@
import React from 'react';
-import PropTypes from 'prop-types';
-const Message = (props) => {
+interface Props {
+ mode: string;
+ children: string[];
+}
+
+const Message = (props: Props) => {
switch (props.mode) {
case 'error':
return (
@@ -16,10 +20,7 @@ const Message = (props) => {
);
}
-};
-
-Message.propTypes = {
- children: PropTypes.string,
+ return null;
};
export default Message;
diff --git a/src/console/index.tsx b/src/console/index.tsx
index 3190a9a..ee3a8ee 100644
--- a/src/console/index.tsx
+++ b/src/console/index.tsx
@@ -1,8 +1,8 @@
-import messages from 'shared/messages';
-import reducers from 'console/reducers';
+import messages from '../shared/messages';
+import reducers from './reducers';
import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise';
-import * as consoleActions from 'console/actions/console';
+import * as consoleActions from './actions/console';
import { Provider } from 'react-redux';
import Console from './components/Console';
import React from 'react';
@@ -22,7 +22,7 @@ window.addEventListener('load', () => {
wrapper);
});
-const onMessage = (message) => {
+const onMessage = (message: any): any => {
switch (message.type) {
case messages.CONSOLE_SHOW_COMMAND:
return store.dispatch(consoleActions.showCommand(message.command));
@@ -38,5 +38,5 @@ const onMessage = (message) => {
};
browser.runtime.onMessage.addListener(onMessage);
-let port = browser.runtime.connect({ name: 'vimvixen-console' });
+let port = browser.runtime.connect(undefined, { name: 'vimvixen-console' });
port.onMessage.addListener(onMessage);
diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts
index 614a72f..37ed715 100644
--- a/src/console/reducers/index.ts
+++ b/src/console/reducers/index.ts
@@ -1,4 +1,14 @@
-import actions from 'console/actions';
+import * as actions from '../actions';
+
+interface State {
+ mode: string;
+ messageText: string;
+ consoleText: string;
+ completionSource: string;
+ completions: any[],
+ select: number;
+ viewIndex: number;
+}
const defaultState = {
mode: '',
@@ -10,7 +20,7 @@ const defaultState = {
viewIndex: 0,
};
-const nextSelection = (state) => {
+const nextSelection = (state: State): number => {
if (state.completions.length === 0) {
return -1;
}
@@ -27,7 +37,7 @@ const nextSelection = (state) => {
return -1;
};
-const prevSelection = (state) => {
+const prevSelection = (state: State): number => {
let length = state.completions
.map(g => g.items.length)
.reduce((x, y) => x + y);
@@ -37,7 +47,7 @@ const prevSelection = (state) => {
return state.select - 1;
};
-const nextConsoleText = (completions, select, defaults) => {
+const nextConsoleText = (completions: any[], select: number, defaults: any) => {
if (select < 0) {
return defaults;
}
@@ -46,7 +56,10 @@ const nextConsoleText = (completions, select, defaults) => {
};
// eslint-disable-next-line max-lines-per-function
-export default function reducer(state = defaultState, action = {}) {
+export default function reducer(
+ state: State = defaultState,
+ action: actions.ConsoleAction,
+): State {
switch (action.type) {
case actions.CONSOLE_HIDE:
return { ...state,
diff --git a/test/console/actions/console.test.ts b/test/console/actions/console.test.ts
index 10cd9fe..e45d008 100644
--- a/test/console/actions/console.test.ts
+++ b/test/console/actions/console.test.ts
@@ -1,4 +1,4 @@
-import actions from 'console/actions';
+import * as actions from 'console/actions';
import * as consoleActions from 'console/actions/console';
describe("console actions", () => {
diff --git a/test/console/reducers/console.test.ts b/test/console/reducers/console.test.ts
index d5a38cf..47e7daf 100644
--- a/test/console/reducers/console.test.ts
+++ b/test/console/reducers/console.test.ts
@@ -1,4 +1,4 @@
-import actions from 'console/actions';
+import * as actions from 'console/actions';
import reducer from 'console/reducers';
describe("console reducer", () => {
--
cgit v1.2.3
From d01db82c0dca352de2d7644c383d388fc3ec0366 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka
Date: Thu, 2 May 2019 14:08:51 +0900
Subject: Types src/content
---
.eslintrc | 2 +
package.json | 1 +
src/background/controllers/OperationController.ts | 4 +-
src/background/controllers/VersionController.ts | 2 +-
src/background/domains/Setting.ts | 20 +-
src/background/infrastructures/ConsoleClient.ts | 2 +-
.../infrastructures/ContentMessageClient.ts | 2 +-
.../infrastructures/ContentMessageListener.ts | 6 +-
src/background/presenters/NotifyPresenter.ts | 6 +-
src/background/usecases/VersionUseCase.ts | 2 +-
src/console/actions/console.ts | 2 +-
src/console/index.tsx | 11 +-
src/content/MessageListener.ts | 32 ++
src/content/actions/addon.ts | 10 +-
src/content/actions/find.ts | 40 +-
src/content/actions/follow-controller.ts | 12 +-
src/content/actions/index.ts | 151 ++++--
src/content/actions/input.ts | 6 +-
src/content/actions/mark.ts | 20 +-
src/content/actions/operation.ts | 25 +-
src/content/actions/setting.ts | 14 +-
src/content/components/common/follow.ts | 79 +++-
src/content/components/common/hint.ts | 33 +-
src/content/components/common/index.ts | 43 +-
src/content/components/common/input.ts | 46 +-
src/content/components/common/keymapper.ts | 8 +-
src/content/components/common/mark.ts | 2 +-
src/content/components/top-content/find.ts | 25 +-
.../components/top-content/follow-controller.ts | 65 ++-
src/content/components/top-content/index.ts | 28 +-
src/content/console-frames.ts | 18 +-
src/content/focuses.ts | 8 +-
src/content/hint-key-producer.ts | 10 +-
src/content/index.ts | 9 +-
src/content/navigates.ts | 45 +-
src/content/reducers/addon.ts | 13 +-
src/content/reducers/find.ts | 14 +-
src/content/reducers/follow-controller.ts | 16 +-
src/content/reducers/index.ts | 22 +-
src/content/reducers/input.ts | 13 +-
src/content/reducers/mark.ts | 20 +-
src/content/reducers/setting.ts | 11 +-
src/content/scrolls.ts | 38 +-
src/content/store/index.ts | 8 +
src/content/urls.ts | 8 +-
src/shared/messages.ts | 346 +++++++++++---
src/shared/operations.ts | 523 ++++++++++++++++++---
src/shared/settings/validator.ts | 2 +-
src/shared/utils/keys.ts | 2 +-
test/content/actions/follow-controller.test.ts | 2 +-
test/content/actions/input.test.ts | 2 +-
test/content/actions/mark.test.ts | 2 +-
test/content/actions/setting.test.ts | 2 +-
test/content/components/common/input.test.ts | 14 +-
test/content/reducers/addon.test.ts | 2 +-
test/content/reducers/find.test.ts | 2 +-
test/content/reducers/follow-controller.test.ts | 2 +-
test/content/reducers/input.test.ts | 2 +-
test/content/reducers/mark.test.ts | 2 +-
test/content/reducers/setting.test.ts | 2 +-
test/shared/operations.test.ts | 41 ++
tsconfig.json | 9 +-
62 files changed, 1426 insertions(+), 483 deletions(-)
create mode 100644 src/content/MessageListener.ts
create mode 100644 src/content/store/index.ts
create mode 100644 test/shared/operations.test.ts
(limited to 'src/console')
diff --git a/.eslintrc b/.eslintrc
index fb60bc2..7845ca5 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -35,6 +35,7 @@
"indent": ["error", 2],
"jsx-quotes": ["error", "prefer-single"],
"max-classes-per-file": "off",
+ "max-lines": "off",
"max-params": ["error", 5],
"max-statements": ["error", 15],
"multiline-comment-style": "off",
@@ -47,6 +48,7 @@
"no-console": ["error", { "allow": ["warn", "error"] }],
"no-continue": "off",
"no-empty-function": "off",
+ "no-extra-parens": "off",
"no-magic-numbers": "off",
"no-mixed-operators": "off",
"no-plusplus": "off",
diff --git a/package.json b/package.json
index 5d44a1b..a799554 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
"build": "NODE_ENV=production webpack --mode production --progress --display-error-details",
"package": "npm run build && script/package",
"lint": "eslint --ext .js,.jsx,.ts,.tsx src",
+ "type-checks": "tsc",
"test": "karma start",
"test:e2e": "mocha --timeout 8000 e2e"
},
diff --git a/src/background/controllers/OperationController.ts b/src/background/controllers/OperationController.ts
index 4e9c106..fa09512 100644
--- a/src/background/controllers/OperationController.ts
+++ b/src/background/controllers/OperationController.ts
@@ -1,4 +1,4 @@
-import operations from '../../shared/operations';
+import * as operations from '../../shared/operations';
import FindUseCase from '../usecases/FindUseCase';
import ConsoleUseCase from '../usecases/ConsoleUseCase';
import TabUseCase from '../usecases/TabUseCase';
@@ -25,7 +25,7 @@ export default class OperationController {
}
// eslint-disable-next-line complexity, max-lines-per-function
- exec(operation: any): Promise {
+ exec(operation: operations.Operation): Promise {
switch (operation.type) {
case operations.TAB_CLOSE:
return this.tabUseCase.close(false);
diff --git a/src/background/controllers/VersionController.ts b/src/background/controllers/VersionController.ts
index f402ed0..2e2a197 100644
--- a/src/background/controllers/VersionController.ts
+++ b/src/background/controllers/VersionController.ts
@@ -7,7 +7,7 @@ export default class VersionController {
this.versionUseCase = new VersionUseCase();
}
- notify(): void {
+ notify(): Promise {
return this.versionUseCase.notify();
}
}
diff --git a/src/background/domains/Setting.ts b/src/background/domains/Setting.ts
index 106ec0f..b2b1ff2 100644
--- a/src/background/domains/Setting.ts
+++ b/src/background/domains/Setting.ts
@@ -1,22 +1,30 @@
import DefaultSettings from '../../shared/settings/default';
import * as settingsValues from '../../shared/settings/values';
+type SettingValue = {
+ source: string,
+ json: string,
+ form: any
+}
+
export default class Setting {
- constructor({ source, json, form }) {
+ private obj: SettingValue;
+
+ constructor({ source, json, form }: SettingValue) {
this.obj = {
source, json, form
};
}
- get source() {
+ get source(): string {
return this.obj.source;
}
- get json() {
+ get json(): string {
return this.obj.json;
}
- get form() {
+ get form(): any {
return this.obj.form;
}
@@ -33,11 +41,11 @@ export default class Setting {
return { ...settingsValues.valueFromJson(DefaultSettings.json), ...value };
}
- serialize() {
+ serialize(): SettingValue {
return this.obj;
}
- static deserialize(obj) {
+ static deserialize(obj: SettingValue): Setting {
return new Setting({ source: obj.source, json: obj.json, form: obj.form });
}
diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts
index 7ad5d24..c162634 100644
--- a/src/background/infrastructures/ConsoleClient.ts
+++ b/src/background/infrastructures/ConsoleClient.ts
@@ -1,4 +1,4 @@
-import messages from '../../shared/messages';
+import * as messages from '../../shared/messages';
export default class ConsoleClient {
showCommand(tabId: number, command: string): Promise {
diff --git a/src/background/infrastructures/ContentMessageClient.ts b/src/background/infrastructures/ContentMessageClient.ts
index 20057c7..d4bc476 100644
--- a/src/background/infrastructures/ContentMessageClient.ts
+++ b/src/background/infrastructures/ContentMessageClient.ts
@@ -1,4 +1,4 @@
-import messages from '../../shared/messages';
+import * as messages from '../../shared/messages';
export default class ContentMessageClient {
async broadcastSettingsChanged(): Promise {
diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts
index 81d3232..1cc2696 100644
--- a/src/background/infrastructures/ContentMessageListener.ts
+++ b/src/background/infrastructures/ContentMessageListener.ts
@@ -1,4 +1,4 @@
-import messages from '../../shared/messages';
+import * as messages from '../../shared/messages';
import CompletionGroup from '../domains/CompletionGroup';
import CommandController from '../controllers/CommandController';
import SettingController from '../controllers/SettingController';
@@ -68,7 +68,9 @@ export default class ContentMessageListener {
browser.runtime.onConnect.addListener(this.onConnected.bind(this));
}
- onMessage(message: any, senderTab: browser.tabs.Tab): Promise | any {
+ onMessage(
+ message: messages.Message, senderTab: browser.tabs.Tab,
+ ): Promise | any {
switch (message.type) {
case messages.CONSOLE_QUERY_COMPLETIONS:
return this.onConsoleQueryCompletions(message.text);
diff --git a/src/background/presenters/NotifyPresenter.ts b/src/background/presenters/NotifyPresenter.ts
index c83c205..23932f7 100644
--- a/src/background/presenters/NotifyPresenter.ts
+++ b/src/background/presenters/NotifyPresenter.ts
@@ -1,11 +1,11 @@
const NOTIFICATION_ID = 'vimvixen-update';
export default class NotifyPresenter {
- notify(
+ async notify(
title: string,
message: string,
onclick: () => void,
- ): Promise {
+ ): Promise {
const listener = (id: string) => {
if (id !== NOTIFICATION_ID) {
return;
@@ -17,7 +17,7 @@ export default class NotifyPresenter {
};
browser.notifications.onClicked.addListener(listener);
- return browser.notifications.create(NOTIFICATION_ID, {
+ await browser.notifications.create(NOTIFICATION_ID, {
'type': 'basic',
'iconUrl': browser.extension.getURL('resources/icon_48x48.png'),
title,
diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts
index 207f9e2..3a3cc2e 100644
--- a/src/background/usecases/VersionUseCase.ts
+++ b/src/background/usecases/VersionUseCase.ts
@@ -12,7 +12,7 @@ export default class VersionUseCase {
this.notifyPresenter = new NotifyPresenter();
}
- notify(): Promise {
+ notify(): Promise {
let title = `Vim Vixen ${manifest.version} has been installed`;
let message = 'Click here to see release notes';
let url = this.releaseNoteUrl(manifest.version);
diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts
index ceb419c..b1494b0 100644
--- a/src/console/actions/console.ts
+++ b/src/console/actions/console.ts
@@ -1,4 +1,4 @@
-import messages from '../../shared/messages';
+import * as messages from '../../shared/messages';
import * as actions from './index';
const hide = (): actions.ConsoleAction => {
diff --git a/src/console/index.tsx b/src/console/index.tsx
index ee3a8ee..b655154 100644
--- a/src/console/index.tsx
+++ b/src/console/index.tsx
@@ -1,4 +1,4 @@
-import messages from '../shared/messages';
+import * as messages from '../shared/messages';
import reducers from './reducers';
import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise';
@@ -23,15 +23,16 @@ window.addEventListener('load', () => {
});
const onMessage = (message: any): any => {
- switch (message.type) {
+ let msg = messages.valueOf(message);
+ switch (msg.type) {
case messages.CONSOLE_SHOW_COMMAND:
- return store.dispatch(consoleActions.showCommand(message.command));
+ return store.dispatch(consoleActions.showCommand(msg.command));
case messages.CONSOLE_SHOW_FIND:
return store.dispatch(consoleActions.showFind());
case messages.CONSOLE_SHOW_ERROR:
- return store.dispatch(consoleActions.showError(message.text));
+ return store.dispatch(consoleActions.showError(msg.text));
case messages.CONSOLE_SHOW_INFO:
- return store.dispatch(consoleActions.showInfo(message.text));
+ return store.dispatch(consoleActions.showInfo(msg.text));
case messages.CONSOLE_HIDE:
return store.dispatch(consoleActions.hide());
}
diff --git a/src/content/MessageListener.ts b/src/content/MessageListener.ts
new file mode 100644
index 0000000..105d028
--- /dev/null
+++ b/src/content/MessageListener.ts
@@ -0,0 +1,32 @@
+import { Message, valueOf } from '../shared/messages';
+
+export type WebMessageSender = Window | MessagePort | ServiceWorker | null;
+export type WebExtMessageSender = browser.runtime.MessageSender;
+
+export default class MessageListener {
+ onWebMessage(
+ listener: (msg: Message, sender: WebMessageSender) => void,
+ ) {
+ window.addEventListener('message', (event: MessageEvent) => {
+ let sender = event.source;
+ let message = null;
+ try {
+ message = JSON.parse(event.data);
+ } catch (e) {
+ // ignore unexpected message
+ return;
+ }
+ listener(message, sender);
+ });
+ }
+
+ onBackgroundMessage(
+ listener: (msg: Message, sender: WebExtMessageSender) => any,
+ ) {
+ browser.runtime.onMessage.addListener(
+ (msg: any, sender: WebExtMessageSender) => {
+ listener(valueOf(msg), sender);
+ },
+ );
+ }
+}
diff --git a/src/content/actions/addon.ts b/src/content/actions/addon.ts
index b30cf16..8dedae0 100644
--- a/src/content/actions/addon.ts
+++ b/src/content/actions/addon.ts
@@ -1,11 +1,11 @@
-import messages from 'shared/messages';
-import actions from 'content/actions';
+import * as messages from '../../shared/messages';
+import * as actions from './index';
-const enable = () => setEnabled(true);
+const enable = (): Promise => setEnabled(true);
-const disable = () => setEnabled(false);
+const disable = (): Promise => setEnabled(false);
-const setEnabled = async(enabled) => {
+const setEnabled = async(enabled: boolean): Promise => {
await browser.runtime.sendMessage({
type: messages.ADDON_ENABLED_RESPONSE,
enabled,
diff --git a/src/content/actions/find.ts b/src/content/actions/find.ts
index e08d7e5..6dd2ae6 100644
--- a/src/content/actions/find.ts
+++ b/src/content/actions/find.ts
@@ -5,28 +5,41 @@
// NOTE: window.find is not standard API
// https://developer.mozilla.org/en-US/docs/Web/API/Window/find
-import messages from 'shared/messages';
-import actions from 'content/actions';
+import * as messages from '../../shared/messages';
+import * as actions from './index';
import * as consoleFrames from '../console-frames';
-const find = (string, backwards) => {
+const find = (str: string, backwards: boolean): boolean => {
let caseSensitive = false;
let wrapScan = true;
// NOTE: aWholeWord dows not implemented, and aSearchInFrames does not work
// because of same origin policy
- let found = window.find(string, caseSensitive, backwards, wrapScan);
+
+ // eslint-disable-next-line no-extra-parens
+ let found = (window).find(str, caseSensitive, backwards, wrapScan);
if (found) {
return found;
}
- window.getSelection().removeAllRanges();
- return window.find(string, caseSensitive, backwards, wrapScan);
+ let sel = window.getSelection();
+ if (sel) {
+ sel.removeAllRanges();
+ }
+
+ // eslint-disable-next-line no-extra-parens
+ return (window).find(str, caseSensitive, backwards, wrapScan);
};
-const findNext = async(currentKeyword, reset, backwards) => {
+// eslint-disable-next-line max-statements
+const findNext = async(
+ currentKeyword: string, reset: boolean, backwards: boolean,
+): Promise => {
if (reset) {
- window.getSelection().removeAllRanges();
+ let sel = window.getSelection();
+ if (sel) {
+ sel.removeAllRanges();
+ }
}
let keyword = currentKeyword;
@@ -41,7 +54,8 @@ const findNext = async(currentKeyword, reset, backwards) => {
});
}
if (!keyword) {
- return consoleFrames.postError('No previous search keywords');
+ await consoleFrames.postError('No previous search keywords');
+ return { type: actions.NOOP };
}
let found = find(keyword, backwards);
if (found) {
@@ -57,11 +71,15 @@ const findNext = async(currentKeyword, reset, backwards) => {
};
};
-const next = (currentKeyword, reset) => {
+const next = (
+ currentKeyword: string, reset: boolean,
+): Promise => {
return findNext(currentKeyword, reset, false);
};
-const prev = (currentKeyword, reset) => {
+const prev = (
+ currentKeyword: string, reset: boolean,
+): Promise => {
return findNext(currentKeyword, reset, true);
};
diff --git a/src/content/actions/follow-controller.ts b/src/content/actions/follow-controller.ts
index 006b248..115b3b6 100644
--- a/src/content/actions/follow-controller.ts
+++ b/src/content/actions/follow-controller.ts
@@ -1,6 +1,8 @@
-import actions from 'content/actions';
+import * as actions from './index';
-const enable = (newTab, background) => {
+const enable = (
+ newTab: boolean, background: boolean,
+): actions.FollowAction => {
return {
type: actions.FOLLOW_CONTROLLER_ENABLE,
newTab,
@@ -8,20 +10,20 @@ const enable = (newTab, background) => {
};
};
-const disable = () => {
+const disable = (): actions.FollowAction => {
return {
type: actions.FOLLOW_CONTROLLER_DISABLE,
};
};
-const keyPress = (key) => {
+const keyPress = (key: string): actions.FollowAction => {
return {
type: actions.FOLLOW_CONTROLLER_KEY_PRESS,
key: key
};
};
-const backspace = () => {
+const backspace = (): actions.FollowAction => {
return {
type: actions.FOLLOW_CONTROLLER_BACKSPACE,
};
diff --git a/src/content/actions/index.ts b/src/content/actions/index.ts
index 0a16fdf..18d0a69 100644
--- a/src/content/actions/index.ts
+++ b/src/content/actions/index.ts
@@ -1,31 +1,120 @@
-export default {
- // Enable/disable
- ADDON_SET_ENABLED: 'addon.set.enabled',
-
- // Settings
- SETTING_SET: 'setting.set',
-
- // User input
- INPUT_KEY_PRESS: 'input.key.press',
- INPUT_CLEAR_KEYS: 'input.clear.keys',
-
- // Completion
- COMPLETION_SET_ITEMS: 'completion.set.items',
- COMPLETION_SELECT_NEXT: 'completions.select.next',
- COMPLETION_SELECT_PREV: 'completions.select.prev',
-
- // Follow
- FOLLOW_CONTROLLER_ENABLE: 'follow.controller.enable',
- FOLLOW_CONTROLLER_DISABLE: 'follow.controller.disable',
- FOLLOW_CONTROLLER_KEY_PRESS: 'follow.controller.key.press',
- FOLLOW_CONTROLLER_BACKSPACE: 'follow.controller.backspace',
-
- // Find
- FIND_SET_KEYWORD: 'find.set.keyword',
-
- // Mark
- MARK_START_SET: 'mark.start.set',
- MARK_START_JUMP: 'mark.start.jump',
- MARK_CANCEL: 'mark.cancel',
- MARK_SET_LOCAL: 'mark.set.local',
-};
+import Redux from 'redux';
+
+// Enable/disable
+export const ADDON_SET_ENABLED = 'addon.set.enabled';
+
+// Find
+export const FIND_SET_KEYWORD = 'find.set.keyword';
+
+// Settings
+export const SETTING_SET = 'setting.set';
+
+// User input
+export const INPUT_KEY_PRESS = 'input.key.press';
+export const INPUT_CLEAR_KEYS = 'input.clear.keys';
+
+// Completion
+export const COMPLETION_SET_ITEMS = 'completion.set.items';
+export const COMPLETION_SELECT_NEXT = 'completions.select.next';
+export const COMPLETION_SELECT_PREV = 'completions.select.prev';
+
+// Follow
+export const FOLLOW_CONTROLLER_ENABLE = 'follow.controller.enable';
+export const FOLLOW_CONTROLLER_DISABLE = 'follow.controller.disable';
+export const FOLLOW_CONTROLLER_KEY_PRESS = 'follow.controller.key.press';
+export const FOLLOW_CONTROLLER_BACKSPACE = 'follow.controller.backspace';
+
+// Mark
+export const MARK_START_SET = 'mark.start.set';
+export const MARK_START_JUMP = 'mark.start.jump';
+export const MARK_CANCEL = 'mark.cancel';
+export const MARK_SET_LOCAL = 'mark.set.local';
+
+export const NOOP = 'noop';
+
+export interface AddonSetEnabledAction extends Redux.Action {
+ type: typeof ADDON_SET_ENABLED;
+ enabled: boolean;
+}
+
+export interface FindSetKeywordAction extends Redux.Action {
+ type: typeof FIND_SET_KEYWORD;
+ keyword: string;
+ found: boolean;
+}
+
+export interface SettingSetAction extends Redux.Action {
+ type: typeof SETTING_SET;
+ value: any;
+}
+
+export interface InputKeyPressAction extends Redux.Action {
+ type: typeof INPUT_KEY_PRESS;
+ key: string;
+}
+
+export interface InputClearKeysAction extends Redux.Action {
+ type: typeof INPUT_CLEAR_KEYS;
+}
+
+export interface FollowControllerEnableAction extends Redux.Action {
+ type: typeof FOLLOW_CONTROLLER_ENABLE;
+ newTab: boolean;
+ background: boolean;
+}
+
+export interface FollowControllerDisableAction extends Redux.Action {
+ type: typeof FOLLOW_CONTROLLER_DISABLE;
+}
+
+export interface FollowControllerKeyPressAction extends Redux.Action {
+ type: typeof FOLLOW_CONTROLLER_KEY_PRESS;
+ key: string;
+}
+
+export interface FollowControllerBackspaceAction extends Redux.Action {
+ type: typeof FOLLOW_CONTROLLER_BACKSPACE;
+}
+
+export interface MarkStartSetAction extends Redux.Action {
+ type: typeof MARK_START_SET;
+}
+
+export interface MarkStartJumpAction extends Redux.Action {
+ type: typeof MARK_START_JUMP;
+}
+
+export interface MarkCancelAction extends Redux.Action {
+ type: typeof MARK_CANCEL;
+}
+
+export interface MarkSetLocalAction extends Redux.Action {
+ type: typeof MARK_SET_LOCAL;
+ key: string;
+ x: number;
+ y: number;
+}
+
+export interface NoopAction extends Redux.Action {
+ type: typeof NOOP;
+}
+
+export type AddonAction = AddonSetEnabledAction;
+export type FindAction = FindSetKeywordAction | NoopAction;
+export type SettingAction = SettingSetAction;
+export type InputAction = InputKeyPressAction | InputClearKeysAction;
+export type FollowAction =
+ FollowControllerEnableAction | FollowControllerDisableAction |
+ FollowControllerKeyPressAction | FollowControllerBackspaceAction;
+export type MarkAction =
+ MarkStartSetAction | MarkStartJumpAction |
+ MarkCancelAction | MarkSetLocalAction | NoopAction;
+
+export type Action =
+ AddonAction |
+ FindAction |
+ SettingAction |
+ InputAction |
+ FollowAction |
+ MarkAction |
+ NoopAction;
diff --git a/src/content/actions/input.ts b/src/content/actions/input.ts
index 465a486..21c912e 100644
--- a/src/content/actions/input.ts
+++ b/src/content/actions/input.ts
@@ -1,13 +1,13 @@
-import actions from 'content/actions';
+import * as actions from './index';
-const keyPress = (key) => {
+const keyPress = (key: string): actions.InputAction => {
return {
type: actions.INPUT_KEY_PRESS,
key,
};
};
-const clearKeys = () => {
+const clearKeys = (): actions.InputAction => {
return {
type: actions.INPUT_CLEAR_KEYS
};
diff --git a/src/content/actions/mark.ts b/src/content/actions/mark.ts
index 712a811..5eb9554 100644
--- a/src/content/actions/mark.ts
+++ b/src/content/actions/mark.ts
@@ -1,19 +1,19 @@
-import actions from 'content/actions';
-import messages from 'shared/messages';
+import * as actions from './index';
+import * as messages from '../../shared/messages';
-const startSet = () => {
+const startSet = (): actions.MarkAction => {
return { type: actions.MARK_START_SET };
};
-const startJump = () => {
+const startJump = (): actions.MarkAction => {
return { type: actions.MARK_START_JUMP };
};
-const cancel = () => {
+const cancel = (): actions.MarkAction => {
return { type: actions.MARK_CANCEL };
};
-const setLocal = (key, x, y) => {
+const setLocal = (key: string, x: number, y: number): actions.MarkAction => {
return {
type: actions.MARK_SET_LOCAL,
key,
@@ -22,22 +22,22 @@ const setLocal = (key, x, y) => {
};
};
-const setGlobal = (key, x, y) => {
+const setGlobal = (key: string, x: number, y: number): actions.MarkAction => {
browser.runtime.sendMessage({
type: messages.MARK_SET_GLOBAL,
key,
x,
y,
});
- return { type: '' };
+ return { type: actions.NOOP };
};
-const jumpGlobal = (key) => {
+const jumpGlobal = (key: string): actions.MarkAction => {
browser.runtime.sendMessage({
type: messages.MARK_JUMP_GLOBAL,
key,
});
- return { type: '' };
+ return { type: actions.NOOP };
};
export {
diff --git a/src/content/actions/operation.ts b/src/content/actions/operation.ts
index ed9b2cf..6acb407 100644
--- a/src/content/actions/operation.ts
+++ b/src/content/actions/operation.ts
@@ -1,16 +1,21 @@
-import operations from 'shared/operations';
-import messages from 'shared/messages';
-import * as scrolls from 'content/scrolls';
-import * as navigates from 'content/navigates';
-import * as focuses from 'content/focuses';
-import * as urls from 'content/urls';
-import * as consoleFrames from 'content/console-frames';
+import * as operations from '../../shared/operations';
+import * as actions from './index';
+import * as messages from '../../shared/messages';
+import * as scrolls from '../scrolls';
+import * as navigates from '../navigates';
+import * as focuses from '../focuses';
+import * as urls from '../urls';
+import * as consoleFrames from '../console-frames';
import * as addonActions from './addon';
import * as markActions from './mark';
-import * as properties from 'shared/settings/properties';
+import * as properties from '../../shared/settings/properties';
// eslint-disable-next-line complexity, max-lines-per-function
-const exec = (operation, settings, addonEnabled) => {
+const exec = (
+ operation: operations.Operation,
+ settings: any,
+ addonEnabled: boolean,
+): Promise | actions.Action => {
let smoothscroll = settings.properties.smoothscroll ||
properties.defaults.smoothscroll;
switch (operation.type) {
@@ -98,7 +103,7 @@ const exec = (operation, settings, addonEnabled) => {
operation,
});
}
- return { type: '' };
+ return { type: actions.NOOP };
};
export { exec };
diff --git a/src/content/actions/setting.ts b/src/content/actions/setting.ts
index 1c15dd7..a8f049a 100644
--- a/src/content/actions/setting.ts
+++ b/src/content/actions/setting.ts
@@ -1,15 +1,15 @@
-import actions from 'content/actions';
-import * as keyUtils from 'shared/utils/keys';
-import operations from 'shared/operations';
-import messages from 'shared/messages';
+import * as actions from './index';
+import * as keyUtils from '../../shared/utils/keys';
+import * as operations from '../../shared/operations';
+import * as messages from '../../shared/messages';
const reservedKeymaps = {
'': { type: operations.CANCEL },
'': { type: operations.CANCEL },
};
-const set = (value) => {
- let entries = [];
+const set = (value: any): actions.SettingAction => {
+ let entries: any[] = [];
if (value.keymaps) {
let keymaps = { ...value.keymaps, ...reservedKeymaps };
entries = Object.entries(keymaps).map((entry) => {
@@ -27,7 +27,7 @@ const set = (value) => {
};
};
-const load = async() => {
+const load = async(): Promise => {
let settings = await browser.runtime.sendMessage({
type: messages.SETTINGS_QUERY,
});
diff --git a/src/content/components/common/follow.ts b/src/content/components/common/follow.ts
index 63ce603..67f2dd9 100644
--- a/src/content/components/common/follow.ts
+++ b/src/content/components/common/follow.ts
@@ -1,6 +1,8 @@
-import messages from 'shared/messages';
+import MessageListener from '../../MessageListener';
import Hint from './hint';
-import * as dom from 'shared/utils/dom';
+import * as dom from '../../../shared/utils/dom';
+import * as messages from '../../../shared/messages';
+import * as keyUtils from '../../../shared/utils/keys';
const TARGET_SELECTOR = [
'a', 'button', 'input', 'textarea', 'area',
@@ -8,8 +10,22 @@ const TARGET_SELECTOR = [
'[role="button"]', 'summary'
].join(',');
+interface Size {
+ width: number;
+ height: number;
+}
+
+interface Point {
+ x: number;
+ y: number;
+}
-const inViewport = (win, element, viewSize, framePosition) => {
+const inViewport = (
+ win: Window,
+ element: Element,
+ viewSize: Size,
+ framePosition: Point,
+): boolean => {
let {
top, left, bottom, right
} = dom.viewportRect(element);
@@ -30,34 +46,44 @@ const inViewport = (win, element, viewSize, framePosition) => {
return true;
};
-const isAriaHiddenOrAriaDisabled = (win, element) => {
+const isAriaHiddenOrAriaDisabled = (win: Window, element: Element): boolean => {
if (!element || win.document.documentElement === element) {
return false;
}
for (let attr of ['aria-hidden', 'aria-disabled']) {
- if (element.hasAttribute(attr)) {
- let hidden = element.getAttribute(attr).toLowerCase();
+ let value = element.getAttribute(attr);
+ if (value !== null) {
+ let hidden = value.toLowerCase();
if (hidden === '' || hidden === 'true') {
return true;
}
}
}
- return isAriaHiddenOrAriaDisabled(win, element.parentNode);
+ return isAriaHiddenOrAriaDisabled(win, element.parentElement as Element);
};
export default class Follow {
- constructor(win, store) {
+ private win: Window;
+
+ private newTab: boolean;
+
+ private background: boolean;
+
+ private hints: {[key: string]: Hint };
+
+ private targets: HTMLElement[] = [];
+
+ constructor(win: Window) {
this.win = win;
- this.store = store;
this.newTab = false;
this.background = false;
this.hints = {};
this.targets = [];
- messages.onMessage(this.onMessage.bind(this));
+ new MessageListener().onWebMessage(this.onMessage.bind(this));
}
- key(key) {
+ key(key: keyUtils.Key): boolean {
if (Object.keys(this.hints).length === 0) {
return false;
}
@@ -69,7 +95,7 @@ export default class Follow {
return true;
}
- openLink(element) {
+ openLink(element: HTMLAreaElement|HTMLAnchorElement) {
// Browser prevent new tab by link with target='_blank'
if (!this.newTab && element.getAttribute('target') !== '_blank') {
element.click();
@@ -90,7 +116,7 @@ export default class Follow {
});
}
- countHints(sender, viewSize, framePosition) {
+ countHints(sender: any, viewSize: Size, framePosition: Point) {
this.targets = Follow.getTargetElements(this.win, viewSize, framePosition);
sender.postMessage(JSON.stringify({
type: messages.FOLLOW_RESPONSE_COUNT_TARGETS,
@@ -98,7 +124,7 @@ export default class Follow {
}), '*');
}
- createHints(keysArray, newTab, background) {
+ createHints(keysArray: string[], newTab: boolean, background: boolean) {
if (keysArray.length !== this.targets.length) {
throw new Error('illegal hint count');
}
@@ -113,7 +139,7 @@ export default class Follow {
}
}
- showHints(keys) {
+ showHints(keys: string) {
Object.keys(this.hints).filter(key => key.startsWith(keys))
.forEach(key => this.hints[key].show());
Object.keys(this.hints).filter(key => !key.startsWith(keys))
@@ -128,18 +154,19 @@ export default class Follow {
this.targets = [];
}
- activateHints(keys) {
+ activateHints(keys: string) {
let hint = this.hints[keys];
if (!hint) {
return;
}
- let element = hint.target;
+ let element = hint.getTarget();
switch (element.tagName.toLowerCase()) {
case 'a':
+ return this.openLink(element as HTMLAnchorElement);
case 'area':
- return this.openLink(element);
+ return this.openLink(element as HTMLAreaElement);
case 'input':
- switch (element.type) {
+ switch ((element as HTMLInputElement).type) {
case 'file':
case 'checkbox':
case 'radio':
@@ -166,7 +193,7 @@ export default class Follow {
}
}
- onMessage(message, sender) {
+ onMessage(message: messages.Message, sender: any) {
switch (message.type) {
case messages.FOLLOW_REQUEST_COUNT_TARGETS:
return this.countHints(sender, message.viewSize, message.framePosition);
@@ -178,19 +205,23 @@ export default class Follow {
case messages.FOLLOW_ACTIVATE:
return this.activateHints(message.keys);
case messages.FOLLOW_REMOVE_HINTS:
- return this.removeHints(message.keys);
+ return this.removeHints();
}
}
- static getTargetElements(win, viewSize, framePosition) {
+ static getTargetElements(
+ win: Window,
+ viewSize:
+ Size, framePosition: Point,
+ ): HTMLElement[] {
let all = win.document.querySelectorAll(TARGET_SELECTOR);
- let filtered = Array.prototype.filter.call(all, (element) => {
+ let filtered = Array.prototype.filter.call(all, (element: HTMLElement) => {
let style = win.getComputedStyle(element);
// AREA's 'display' in Browser style is 'none'
return (element.tagName === 'AREA' || style.display !== 'none') &&
style.visibility !== 'hidden' &&
- element.type !== 'hidden' &&
+ (element as HTMLInputElement).type !== 'hidden' &&
element.offsetHeight > 0 &&
!isAriaHiddenOrAriaDisabled(win, element) &&
inViewport(win, element, viewSize, framePosition);
diff --git a/src/content/components/common/hint.ts b/src/content/components/common/hint.ts
index 1472587..2fcbb0f 100644
--- a/src/content/components/common/hint.ts
+++ b/src/content/components/common/hint.ts
@@ -1,6 +1,11 @@
-import * as dom from 'shared/utils/dom';
+import * as dom from '../../../shared/utils/dom';
-const hintPosition = (element) => {
+interface Point {
+ x: number;
+ y: number;
+}
+
+const hintPosition = (element: Element): Point => {
let { left, top, right, bottom } = dom.viewportRect(element);
if (element.tagName !== 'AREA') {
@@ -14,17 +19,21 @@ const hintPosition = (element) => {
};
export default class Hint {
- constructor(target, tag) {
- if (!(document.body instanceof HTMLElement)) {
- throw new TypeError('target is not an HTMLElement');
- }
+ private target: HTMLElement;
- this.target = target;
+ private element: HTMLElement;
+ constructor(target: HTMLElement, tag: string) {
let doc = target.ownerDocument;
+ if (doc === null) {
+ throw new TypeError('ownerDocument is null');
+ }
+
let { x, y } = hintPosition(target);
let { scrollX, scrollY } = window;
+ this.target = target;
+
this.element = doc.createElement('span');
this.element.className = 'vimvixen-hint';
this.element.textContent = tag;
@@ -35,15 +44,19 @@ export default class Hint {
doc.body.append(this.element);
}
- show() {
+ show(): void {
this.element.style.display = 'inline';
}
- hide() {
+ hide(): void {
this.element.style.display = 'none';
}
- remove() {
+ remove(): void {
this.element.remove();
}
+
+ getTarget(): HTMLElement {
+ return this.target;
+ }
}
diff --git a/src/content/components/common/index.ts b/src/content/components/common/index.ts
index bcab4fa..9b5164e 100644
--- a/src/content/components/common/index.ts
+++ b/src/content/components/common/index.ts
@@ -2,33 +2,37 @@ import InputComponent from './input';
import FollowComponent from './follow';
import MarkComponent from './mark';
import KeymapperComponent from './keymapper';
-import * as settingActions from 'content/actions/setting';
-import messages from 'shared/messages';
+import * as settingActions from '../../actions/setting';
+import * as messages from '../../../shared/messages';
+import MessageListener from '../../MessageListener';
import * as addonActions from '../../actions/addon';
-import * as blacklists from 'shared/blacklists';
+import * as blacklists from '../../../shared/blacklists';
+import * as keys from '../../../shared/utils/keys';
export default class Common {
- constructor(win, store) {
- const input = new InputComponent(win.document.body, store);
- const follow = new FollowComponent(win, store);
+ private win: Window;
+
+ private store: any;
+
+ constructor(win: Window, store: any) {
+ const input = new InputComponent(win.document.body);
+ const follow = new FollowComponent(win);
const mark = new MarkComponent(win.document.body, store);
const keymapper = new KeymapperComponent(store);
- input.onKey(key => follow.key(key));
- input.onKey(key => mark.key(key));
- input.onKey(key => keymapper.key(key));
+ input.onKey((key: keys.Key) => follow.key(key));
+ input.onKey((key: keys.Key) => mark.key(key));
+ input.onKey((key: keys.Key) => keymapper.key(key));
this.win = win;
this.store = store;
- this.prevEnabled = undefined;
- this.prevBlacklist = undefined;
this.reloadSettings();
- messages.onMessage(this.onMessage.bind(this));
+ new MessageListener().onBackgroundMessage(this.onMessage.bind(this));
}
- onMessage(message) {
+ onMessage(message: messages.Message) {
let { enabled } = this.store.getState().addon;
switch (message.type) {
case messages.SETTINGS_CHANGED:
@@ -40,12 +44,13 @@ export default class Common {
reloadSettings() {
try {
- this.store.dispatch(settingActions.load()).then(({ value: settings }) => {
- let enabled = !blacklists.includes(
- settings.blacklist, this.win.location.href
- );
- this.store.dispatch(addonActions.setEnabled(enabled));
- });
+ this.store.dispatch(settingActions.load())
+ .then(({ value: settings }: any) => {
+ let enabled = !blacklists.includes(
+ settings.blacklist, this.win.location.href
+ );
+ this.store.dispatch(addonActions.setEnabled(enabled));
+ });
} catch (e) {
// Sometime sendMessage fails when background script is not ready.
console.warn(e);
diff --git a/src/content/components/common/input.ts b/src/content/components/common/input.ts
index eefaf10..64eb5f3 100644
--- a/src/content/components/common/input.ts
+++ b/src/content/components/common/input.ts
@@ -1,12 +1,16 @@
-import * as dom from 'shared/utils/dom';
-import * as keys from 'shared/utils/keys';
+import * as dom from '../../../shared/utils/dom';
+import * as keys from '../../../shared/utils/keys';
-const cancelKey = (e) => {
+const cancelKey = (e: KeyboardEvent): boolean => {
return e.key === 'Escape' || e.key === '[' && e.ctrlKey;
};
export default class InputComponent {
- constructor(target) {
+ private pressed: {[key: string]: string} = {};
+
+ private onKeyListeners: ((key: keys.Key) => boolean)[] = [];
+
+ constructor(target: HTMLElement) {
this.pressed = {};
this.onKeyListeners = [];
@@ -15,11 +19,11 @@ export default class InputComponent {
target.addEventListener('keyup', this.onKeyUp.bind(this));
}
- onKey(cb) {
+ onKey(cb: (key: keys.Key) => boolean) {
this.onKeyListeners.push(cb);
}
- onKeyPress(e) {
+ onKeyPress(e: KeyboardEvent) {
if (this.pressed[e.key] && this.pressed[e.key] !== 'keypress') {
return;
}
@@ -27,7 +31,7 @@ export default class InputComponent {
this.capture(e);
}
- onKeyDown(e) {
+ onKeyDown(e: KeyboardEvent) {
if (this.pressed[e.key] && this.pressed[e.key] !== 'keydown') {
return;
}
@@ -35,14 +39,19 @@ export default class InputComponent {
this.capture(e);
}
- onKeyUp(e) {
+ onKeyUp(e: KeyboardEvent) {
delete this.pressed[e.key];
}
- capture(e) {
- if (this.fromInput(e)) {
- if (cancelKey(e) && e.target.blur) {
- e.target.blur();
+ // eslint-disable-next-line max-statements
+ capture(e: KeyboardEvent) {
+ let target = e.target;
+ if (!(target instanceof HTMLElement)) {
+ return;
+ }
+ if (this.fromInput(target)) {
+ if (cancelKey(e) && target.blur) {
+ target.blur();
}
return;
}
@@ -63,13 +72,10 @@ export default class InputComponent {
}
}
- fromInput(e) {
- if (!e.target) {
- return false;
- }
- return e.target instanceof HTMLInputElement ||
- e.target instanceof HTMLTextAreaElement ||
- e.target instanceof HTMLSelectElement ||
- dom.isContentEditable(e.target);
+ fromInput(e: Element) {
+ return e instanceof HTMLInputElement ||
+ e instanceof HTMLTextAreaElement ||
+ e instanceof HTMLSelectElement ||
+ dom.isContentEditable(e);
}
}
diff --git a/src/content/components/common/keymapper.ts b/src/content/components/common/keymapper.ts
index ec0d093..d9c9834 100644
--- a/src/content/components/common/keymapper.ts
+++ b/src/content/components/common/keymapper.ts
@@ -1,7 +1,7 @@
-import * as inputActions from 'content/actions/input';
-import * as operationActions from 'content/actions/operation';
-import operations from 'shared/operations';
-import * as keyUtils from 'shared/utils/keys';
+import * as inputActions from '../../actions/input';
+import * as operationActions from '../../actions/operation';
+import * as operations from '../../../shared/operations';
+import * as keyUtils from '../../../shared/utils/keys';
const mapStartsWith = (mapping, keys) => {
if (mapping.length < keys.length) {
diff --git a/src/content/components/common/mark.ts b/src/content/components/common/mark.ts
index 0f838a9..500d03b 100644
--- a/src/content/components/common/mark.ts
+++ b/src/content/components/common/mark.ts
@@ -3,7 +3,7 @@ import * as scrolls from 'content/scrolls';
import * as consoleFrames from 'content/console-frames';
import * as properties from 'shared/settings/properties';
-const cancelKey = (key) => {
+const cancelKey = (key): boolean => {
return key.key === 'Esc' || key.key === '[' && key.ctrlKey;
};
diff --git a/src/content/components/top-content/find.ts b/src/content/components/top-content/find.ts
index 4d46d79..74b95bc 100644
--- a/src/content/components/top-content/find.ts
+++ b/src/content/components/top-content/find.ts
@@ -1,15 +1,17 @@
-import * as findActions from 'content/actions/find';
-import messages from 'shared/messages';
+import * as findActions from '../../actions/find';
+import * as messages from '../../../shared/messages';
+import MessageListener from '../../MessageListener';
export default class FindComponent {
- constructor(win, store) {
- this.win = win;
+ private store: any;
+
+ constructor(store: any) {
this.store = store;
- messages.onMessage(this.onMessage.bind(this));
+ new MessageListener().onWebMessage(this.onMessage.bind(this));
}
- onMessage(message) {
+ onMessage(message: messages.Message) {
switch (message.type) {
case messages.CONSOLE_ENTER_FIND:
return this.start(message.text);
@@ -20,22 +22,25 @@ export default class FindComponent {
}
}
- start(text) {
+ start(text: string) {
let state = this.store.getState().find;
if (text.length === 0) {
- return this.store.dispatch(findActions.next(state.keyword, true));
+ return this.store.dispatch(
+ findActions.next(state.keyword as string, true));
}
return this.store.dispatch(findActions.next(text, true));
}
next() {
let state = this.store.getState().find;
- return this.store.dispatch(findActions.next(state.keyword, false));
+ return this.store.dispatch(
+ findActions.next(state.keyword as string, false));
}
prev() {
let state = this.store.getState().find;
- return this.store.dispatch(findActions.prev(state.keyword, false));
+ return this.store.dispatch(
+ findActions.prev(state.keyword as string, false));
}
}
diff --git a/src/content/components/top-content/follow-controller.ts b/src/content/components/top-content/follow-controller.ts
index 7f36604..be71f6e 100644
--- a/src/content/components/top-content/follow-controller.ts
+++ b/src/content/components/top-content/follow-controller.ts
@@ -1,30 +1,46 @@
-import * as followControllerActions from 'content/actions/follow-controller';
-import messages from 'shared/messages';
-import HintKeyProducer from 'content/hint-key-producer';
-import * as properties from 'shared/settings/properties';
+import * as followControllerActions from '../../actions/follow-controller';
+import * as messages from '../../../shared/messages';
+import MessageListener, { WebMessageSender } from '../../MessageListener';
+import HintKeyProducer from '../../hint-key-producer';
+import * as properties from '../../../shared/settings/properties';
-const broadcastMessage = (win, message) => {
+const broadcastMessage = (win: Window, message: messages.Message): void => {
let json = JSON.stringify(message);
- let frames = [window.self].concat(Array.from(window.frames));
+ let frames = [win.self].concat(Array.from(win.frames as any));
frames.forEach(frame => frame.postMessage(json, '*'));
};
export default class FollowController {
- constructor(win, store) {
+ private win: Window;
+
+ private store: any;
+
+ private state: {
+ enabled?: boolean;
+ newTab?: boolean;
+ background?: boolean;
+ keys?: string,
+ };
+
+ private keys: string[];
+
+ private producer: HintKeyProducer | null;
+
+ constructor(win: Window, store: any) {
this.win = win;
this.store = store;
this.state = {};
this.keys = [];
this.producer = null;
- messages.onMessage(this.onMessage.bind(this));
+ new MessageListener().onWebMessage(this.onMessage.bind(this));
store.subscribe(() => {
this.update();
});
}
- onMessage(message, sender) {
+ onMessage(message: messages.Message, sender: WebMessageSender) {
switch (message.type) {
case messages.FOLLOW_START:
return this.store.dispatch(
@@ -36,7 +52,7 @@ export default class FollowController {
}
}
- update() {
+ update(): void {
let prevState = this.state;
this.state = this.store.getState().followController;
@@ -49,8 +65,10 @@ export default class FollowController {
}
}
- updateHints() {
- let shown = this.keys.filter(key => key.startsWith(this.state.keys));
+ updateHints(): void {
+ let shown = this.keys.filter((key) => {
+ return key.startsWith(this.state.keys as string);
+ });
if (shown.length === 1) {
this.activate();
this.store.dispatch(followControllerActions.disable());
@@ -58,18 +76,18 @@ export default class FollowController {
broadcastMessage(this.win, {
type: messages.FOLLOW_SHOW_HINTS,
- keys: this.state.keys,
+ keys: this.state.keys as string,
});
}
- activate() {
+ activate(): void {
broadcastMessage(this.win, {
type: messages.FOLLOW_ACTIVATE,
- keys: this.state.keys,
+ keys: this.state.keys as string,
});
}
- keyPress(key, ctrlKey) {
+ keyPress(key: string, ctrlKey: boolean): boolean {
if (key === '[' && ctrlKey) {
this.store.dispatch(followControllerActions.disable());
return true;
@@ -107,25 +125,28 @@ export default class FollowController {
viewSize: { width: viewWidth, height: viewHeight },
framePosition: { x: 0, y: 0 },
}), '*');
- frameElements.forEach((element) => {
- let { left: frameX, top: frameY } = element.getBoundingClientRect();
+ frameElements.forEach((ele) => {
+ let { left: frameX, top: frameY } = ele.getBoundingClientRect();
let message = JSON.stringify({
type: messages.FOLLOW_REQUEST_COUNT_TARGETS,
viewSize: { width: viewWidth, height: viewHeight },
framePosition: { x: frameX, y: frameY },
});
- element.contentWindow.postMessage(message, '*');
+ if (ele instanceof HTMLFrameElement && ele.contentWindow ||
+ ele instanceof HTMLIFrameElement && ele.contentWindow) {
+ ele.contentWindow.postMessage(message, '*');
+ }
});
}
- create(count, sender) {
+ create(count: number, sender: WebMessageSender) {
let produced = [];
for (let i = 0; i < count; ++i) {
- produced.push(this.producer.produce());
+ produced.push((this.producer as HintKeyProducer).produce());
}
this.keys = this.keys.concat(produced);
- sender.postMessage(JSON.stringify({
+ (sender as Window).postMessage(JSON.stringify({
type: messages.FOLLOW_CREATE_HINTS,
keysArray: produced,
newTab: this.state.newTab,
diff --git a/src/content/components/top-content/index.ts b/src/content/components/top-content/index.ts
index 1aaef1b..ac95ea9 100644
--- a/src/content/components/top-content/index.ts
+++ b/src/content/components/top-content/index.ts
@@ -2,33 +2,43 @@ import CommonComponent from '../common';
import FollowController from './follow-controller';
import FindComponent from './find';
import * as consoleFrames from '../../console-frames';
-import messages from 'shared/messages';
-import * as scrolls from 'content/scrolls';
+import * as messages from '../../../shared/messages';
+import MessageListener from '../../MessageListener';
+import * as scrolls from '../../scrolls';
export default class TopContent {
+ private win: Window;
- constructor(win, store) {
+ private store: any;
+
+ constructor(win: Window, store: any) {
this.win = win;
this.store = store;
new CommonComponent(win, store); // eslint-disable-line no-new
new FollowController(win, store); // eslint-disable-line no-new
- new FindComponent(win, store); // eslint-disable-line no-new
+ new FindComponent(store); // eslint-disable-line no-new
// TODO make component
consoleFrames.initialize(this.win.document);
- messages.onMessage(this.onMessage.bind(this));
+ new MessageListener().onWebMessage(this.onWebMessage.bind(this));
+ new MessageListener().onBackgroundMessage(
+ this.onBackgroundMessage.bind(this));
}
- onMessage(message) {
- let addonState = this.store.getState().addon;
-
+ onWebMessage(message: messages.Message) {
switch (message.type) {
case messages.CONSOLE_UNFOCUS:
this.win.focus();
consoleFrames.blur(window.document);
- return Promise.resolve();
+ }
+ }
+
+ onBackgroundMessage(message: messages.Message) {
+ let addonState = this.store.getState().addon;
+
+ switch (message.type) {
case messages.ADDON_ENABLED_QUERY:
return Promise.resolve({
type: messages.ADDON_ENABLED_RESPONSE,
diff --git a/src/content/console-frames.ts b/src/content/console-frames.ts
index ecb5a87..bd6b835 100644
--- a/src/content/console-frames.ts
+++ b/src/content/console-frames.ts
@@ -1,6 +1,6 @@
-import messages from 'shared/messages';
+import * as messages from '../shared/messages';
-const initialize = (doc) => {
+const initialize = (doc: Document): HTMLIFrameElement => {
let iframe = doc.createElement('iframe');
iframe.src = browser.runtime.getURL('build/console.html');
iframe.id = 'vimvixen-console-frame';
@@ -10,13 +10,13 @@ const initialize = (doc) => {
return iframe;
};
-const blur = (doc) => {
- let iframe = doc.getElementById('vimvixen-console-frame');
- iframe.blur();
+const blur = (doc: Document) => {
+ let ele = doc.getElementById('vimvixen-console-frame') as HTMLIFrameElement;
+ ele.blur();
};
-const postError = (text) => {
- browser.runtime.sendMessage({
+const postError = (text: string): Promise => {
+ return browser.runtime.sendMessage({
type: messages.CONSOLE_FRAME_MESSAGE,
message: {
type: messages.CONSOLE_SHOW_ERROR,
@@ -25,8 +25,8 @@ const postError = (text) => {
});
};
-const postInfo = (text) => {
- browser.runtime.sendMessage({
+const postInfo = (text: string): Promise => {
+ return browser.runtime.sendMessage({
type: messages.CONSOLE_FRAME_MESSAGE,
message: {
type: messages.CONSOLE_SHOW_INFO,
diff --git a/src/content/focuses.ts b/src/content/focuses.ts
index a6f6cc8..8f53881 100644
--- a/src/content/focuses.ts
+++ b/src/content/focuses.ts
@@ -1,11 +1,13 @@
-import * as doms from 'shared/utils/dom';
+import * as doms from '../shared/utils/dom';
-const focusInput = () => {
+const focusInput = (): void => {
let inputTypes = ['email', 'number', 'search', 'tel', 'text', 'url'];
let inputSelector = inputTypes.map(type => `input[type=${type}]`).join(',');
let targets = window.document.querySelectorAll(inputSelector + ',textarea');
let target = Array.from(targets).find(doms.isVisible);
- if (target) {
+ if (target instanceof HTMLInputElement) {
+ target.focus();
+ } else if (target instanceof HTMLTextAreaElement) {
target.focus();
}
};
diff --git a/src/content/hint-key-producer.ts b/src/content/hint-key-producer.ts
index 14b23b6..935394e 100644
--- a/src/content/hint-key-producer.ts
+++ b/src/content/hint-key-producer.ts
@@ -1,5 +1,9 @@
export default class HintKeyProducer {
- constructor(charset) {
+ private charset: string;
+
+ private counter: number[];
+
+ constructor(charset: string) {
if (charset.length === 0) {
throw new TypeError('charset is empty');
}
@@ -8,13 +12,13 @@ export default class HintKeyProducer {
this.counter = [];
}
- produce() {
+ produce(): string {
this.increment();
return this.counter.map(x => this.charset[x]).join('');
}
- increment() {
+ private increment(): void {
let max = this.charset.length - 1;
if (this.counter.every(x => x === max)) {
this.counter = new Array(this.counter.length + 1).fill(0);
diff --git a/src/content/index.ts b/src/content/index.ts
index 9edb712..309f27f 100644
--- a/src/content/index.ts
+++ b/src/content/index.ts
@@ -1,14 +1,9 @@
-import { createStore, applyMiddleware } from 'redux';
-import promise from 'redux-promise';
-import reducers from 'content/reducers';
import TopContentComponent from './components/top-content';
import FrameContentComponent from './components/frame-content';
import consoleFrameStyle from './site-style';
+import { newStore } from './store';
-const store = createStore(
- reducers,
- applyMiddleware(promise),
-);
+const store = newStore();
if (window.self === window.top) {
new TopContentComponent(window, store); // eslint-disable-line no-new
diff --git a/src/content/navigates.ts b/src/content/navigates.ts
index c9baa30..a2007a6 100644
--- a/src/content/navigates.ts
+++ b/src/content/navigates.ts
@@ -1,58 +1,63 @@
-const REL_PATTERN = {
+const REL_PATTERN: {[key: string]: RegExp} = {
prev: /^(?:prev(?:ious)?|older)\b|\u2039|\u2190|\xab|\u226a|<>/i,
};
// Return the last element in the document matching the supplied selector
// and the optional filter, or null if there are no matches.
-const selectLast = (win, selector, filter) => {
- let nodes = win.document.querySelectorAll(selector);
+// eslint-disable-next-line func-style
+function selectLast(
+ win: Window,
+ selector: string,
+ filter?: (e: E) => boolean,
+): E | null {
+ let nodes = Array.from(
+ win.document.querySelectorAll(selector) as NodeListOf
+ );
if (filter) {
- nodes = Array.from(nodes).filter(filter);
+ nodes = nodes.filter(filter);
}
-
return nodes.length ? nodes[nodes.length - 1] : null;
-};
+}
-const historyPrev = (win) => {
+const historyPrev = (win: Window): void => {
win.history.back();
};
-const historyNext = (win) => {
+const historyNext = (win: Window): void => {
win.history.forward();
};
// Code common to linkPrev and linkNext which navigates to the specified page.
-const linkRel = (win, rel) => {
- let link = selectLast(win, `link[rel~=${rel}][href]`);
-
+const linkRel = (win: Window, rel: string): void => {
+ let link = selectLast(win, `link[rel~=${rel}][href]`);
if (link) {
- win.location = link.href;
+ win.location.href = link.href;
return;
}
const pattern = REL_PATTERN[rel];
- link = selectLast(win, `a[rel~=${rel}][href]`) ||
+ let a = selectLast(win, `a[rel~=${rel}][href]`) ||
// `innerText` is much slower than `textContent`, but produces much better
// (i.e. less unexpected) results
selectLast(win, 'a[href]', lnk => pattern.test(lnk.innerText));
- if (link) {
- link.click();
+ if (a) {
+ a.click();
}
};
-const linkPrev = (win) => {
+const linkPrev = (win: Window): void => {
linkRel(win, 'prev');
};
-const linkNext = (win) => {
+const linkNext = (win: Window): void => {
linkRel(win, 'next');
};
-const parent = (win) => {
+const parent = (win: Window): void => {
const loc = win.location;
if (loc.hash !== '') {
loc.hash = '';
@@ -71,8 +76,8 @@ const parent = (win) => {
}
};
-const root = (win) => {
- win.location = win.location.origin;
+const root = (win: Window): void => {
+ win.location.href = win.location.origin;
};
export { historyPrev, historyNext, linkPrev, linkNext, parent, root };
diff --git a/src/content/reducers/addon.ts b/src/content/reducers/addon.ts
index 0def55a..2131228 100644
--- a/src/content/reducers/addon.ts
+++ b/src/content/reducers/addon.ts
@@ -1,10 +1,17 @@
-import actions from 'content/actions';
+import * as actions from '../actions';
-const defaultState = {
+export interface State {
+ enabled: boolean;
+}
+
+const defaultState: State = {
enabled: true,
};
-export default function reducer(state = defaultState, action = {}) {
+export default function reducer(
+ state: State = defaultState,
+ action: actions.AddonAction,
+): State {
switch (action.type) {
case actions.ADDON_SET_ENABLED:
return { ...state,
diff --git a/src/content/reducers/find.ts b/src/content/reducers/find.ts
index 4560e2c..8c3e637 100644
--- a/src/content/reducers/find.ts
+++ b/src/content/reducers/find.ts
@@ -1,11 +1,19 @@
-import actions from 'content/actions';
+import * as actions from '../actions';
-const defaultState = {
+export interface State {
+ keyword: string | null;
+ found: boolean;
+}
+
+const defaultState: State = {
keyword: null,
found: false,
};
-export default function reducer(state = defaultState, action = {}) {
+export default function reducer(
+ state: State = defaultState,
+ action: actions.FindAction,
+): State {
switch (action.type) {
case actions.FIND_SET_KEYWORD:
return { ...state,
diff --git a/src/content/reducers/follow-controller.ts b/src/content/reducers/follow-controller.ts
index 5869c47..6965704 100644
--- a/src/content/reducers/follow-controller.ts
+++ b/src/content/reducers/follow-controller.ts
@@ -1,13 +1,23 @@
-import actions from 'content/actions';
+import * as actions from '../actions';
-const defaultState = {
+export interface State {
+ enabled: boolean;
+ newTab: boolean;
+ background: boolean;
+ keys: string,
+}
+
+const defaultState: State = {
enabled: false,
newTab: false,
background: false,
keys: '',
};
-export default function reducer(state = defaultState, action = {}) {
+export default function reducer(
+ state: State = defaultState,
+ action: actions.FollowAction,
+): State {
switch (action.type) {
case actions.FOLLOW_CONTROLLER_ENABLE:
return { ...state,
diff --git a/src/content/reducers/index.ts b/src/content/reducers/index.ts
index bf612a3..fb5eb84 100644
--- a/src/content/reducers/index.ts
+++ b/src/content/reducers/index.ts
@@ -1,10 +1,20 @@
import { combineReducers } from 'redux';
-import addon from './addon';
-import find from './find';
-import setting from './setting';
-import input from './input';
-import followController from './follow-controller';
-import mark from './mark';
+import addon, { State as AddonState } from './addon';
+import find, { State as FindState } from './find';
+import setting, { State as SettingState } from './setting';
+import input, { State as InputState } from './input';
+import followController, { State as FollowControllerState }
+ from './follow-controller';
+import mark, { State as MarkState } from './mark';
+
+export interface State {
+ addon: AddonState;
+ find: FindState;
+ setting: SettingState;
+ input: InputState;
+ followController: FollowControllerState;
+ mark: MarkState;
+}
export default combineReducers({
addon, find, setting, input, followController, mark,
diff --git a/src/content/reducers/input.ts b/src/content/reducers/input.ts
index 23e7dd2..6257e49 100644
--- a/src/content/reducers/input.ts
+++ b/src/content/reducers/input.ts
@@ -1,10 +1,17 @@
-import actions from 'content/actions';
+import * as actions from '../actions';
-const defaultState = {
+export interface State {
+ keys: string[];
+}
+
+const defaultState: State = {
keys: []
};
-export default function reducer(state = defaultState, action = {}) {
+export default function reducer(
+ state: State = defaultState,
+ action: actions.InputAction,
+): State {
switch (action.type) {
case actions.INPUT_KEY_PRESS:
return { ...state,
diff --git a/src/content/reducers/mark.ts b/src/content/reducers/mark.ts
index 2c96cc5..e78b7b9 100644
--- a/src/content/reducers/mark.ts
+++ b/src/content/reducers/mark.ts
@@ -1,12 +1,26 @@
-import actions from 'content/actions';
+import * as actions from '../actions';
-const defaultState = {
+interface Mark {
+ x: number;
+ y: number;
+}
+
+export interface State {
+ setMode: boolean;
+ jumpMode: boolean;
+ marks: { [key: string]: Mark };
+}
+
+const defaultState: State = {
setMode: false,
jumpMode: false,
marks: {},
};
-export default function reducer(state = defaultState, action = {}) {
+export default function reducer(
+ state: State = defaultState,
+ action: actions.MarkAction,
+): State {
switch (action.type) {
case actions.MARK_START_SET:
return { ...state, setMode: true };
diff --git a/src/content/reducers/setting.ts b/src/content/reducers/setting.ts
index a49db6d..fa8e8ee 100644
--- a/src/content/reducers/setting.ts
+++ b/src/content/reducers/setting.ts
@@ -1,11 +1,18 @@
-import actions from 'content/actions';
+import * as actions from '../actions';
+
+export interface State {
+ keymaps: any[];
+}
const defaultState = {
// keymaps is and arrays of key-binding pairs, which is entries of Map
keymaps: [],
};
-export default function reducer(state = defaultState, action = {}) {
+export default function reducer(
+ state: State = defaultState,
+ action: actions.SettingAction,
+): State {
switch (action.type) {
case actions.SETTING_SET:
return { ...action.value };
diff --git a/src/content/scrolls.ts b/src/content/scrolls.ts
index bbf2491..6a35315 100644
--- a/src/content/scrolls.ts
+++ b/src/content/scrolls.ts
@@ -1,19 +1,19 @@
-import * as doms from 'shared/utils/dom';
+import * as doms from '../shared/utils/dom';
const SCROLL_DELTA_X = 64;
const SCROLL_DELTA_Y = 64;
// dirty way to store scrolling state on globally
let scrolling = false;
-let lastTimeoutId = null;
+let lastTimeoutId: number | null = null;
-const isScrollableStyle = (element) => {
+const isScrollableStyle = (element: Element): boolean => {
let { overflowX, overflowY } = window.getComputedStyle(element);
return !(overflowX !== 'scroll' && overflowX !== 'auto' &&
overflowY !== 'scroll' && overflowY !== 'auto');
};
-const isOverflowed = (element) => {
+const isOverflowed = (element: Element): boolean => {
return element.scrollWidth > element.clientWidth ||
element.scrollHeight > element.clientHeight;
};
@@ -22,7 +22,7 @@ const isOverflowed = (element) => {
// this method is called by each scrolling, and the returned value of this
// method is not cached. That does not cause performance issue because in the
// most pages, the window is root element i,e, documentElement.
-const findScrollable = (element) => {
+const findScrollable = (element: Element): Element | null => {
if (isScrollableStyle(element) && isOverflowed(element)) {
return element;
}
@@ -56,12 +56,16 @@ const resetScrolling = () => {
};
class Scroller {
- constructor(element, smooth) {
+ private element: Element;
+
+ private smooth: boolean;
+
+ constructor(element: Element, smooth: boolean) {
this.element = element;
this.smooth = smooth;
}
- scrollTo(x, y) {
+ scrollTo(x: number, y: number): void {
if (!this.smooth) {
this.element.scrollTo(x, y);
return;
@@ -74,13 +78,13 @@ class Scroller {
this.prepareReset();
}
- scrollBy(x, y) {
+ scrollBy(x: number, y: number): void {
let left = this.element.scrollLeft + x;
let top = this.element.scrollTop + y;
this.scrollTo(left, top);
}
- prepareReset() {
+ prepareReset(): void {
scrolling = true;
if (lastTimeoutId) {
clearTimeout(lastTimeoutId);
@@ -95,7 +99,7 @@ const getScroll = () => {
return { x: target.scrollLeft, y: target.scrollTop };
};
-const scrollVertically = (count, smooth) => {
+const scrollVertically = (count: number, smooth: boolean): void => {
let target = scrollTarget();
let delta = SCROLL_DELTA_Y * count;
if (scrolling) {
@@ -104,7 +108,7 @@ const scrollVertically = (count, smooth) => {
new Scroller(target, smooth).scrollBy(0, delta);
};
-const scrollHorizonally = (count, smooth) => {
+const scrollHorizonally = (count: number, smooth: boolean): void => {
let target = scrollTarget();
let delta = SCROLL_DELTA_X * count;
if (scrolling) {
@@ -113,7 +117,7 @@ const scrollHorizonally = (count, smooth) => {
new Scroller(target, smooth).scrollBy(delta, 0);
};
-const scrollPages = (count, smooth) => {
+const scrollPages = (count: number, smooth: boolean): void => {
let target = scrollTarget();
let height = target.clientHeight;
let delta = height * count;
@@ -123,33 +127,33 @@ const scrollPages = (count, smooth) => {
new Scroller(target, smooth).scrollBy(0, delta);
};
-const scrollTo = (x, y, smooth) => {
+const scrollTo = (x: number, y: number, smooth: boolean): void => {
let target = scrollTarget();
new Scroller(target, smooth).scrollTo(x, y);
};
-const scrollToTop = (smooth) => {
+const scrollToTop = (smooth: boolean): void => {
let target = scrollTarget();
let x = target.scrollLeft;
let y = 0;
new Scroller(target, smooth).scrollTo(x, y);
};
-const scrollToBottom = (smooth) => {
+const scrollToBottom = (smooth: boolean): void => {
let target = scrollTarget();
let x = target.scrollLeft;
let y = target.scrollHeight;
new Scroller(target, smooth).scrollTo(x, y);
};
-const scrollToHome = (smooth) => {
+const scrollToHome = (smooth: boolean): void => {
let target = scrollTarget();
let x = 0;
let y = target.scrollTop;
new Scroller(target, smooth).scrollTo(x, y);
};
-const scrollToEnd = (smooth) => {
+const scrollToEnd = (smooth: boolean): void => {
let target = scrollTarget();
let x = target.scrollWidth;
let y = target.scrollTop;
diff --git a/src/content/store/index.ts b/src/content/store/index.ts
new file mode 100644
index 0000000..5c41744
--- /dev/null
+++ b/src/content/store/index.ts
@@ -0,0 +1,8 @@
+import promise from 'redux-promise';
+import reducers from '../reducers';
+import { createStore, applyMiddleware } from 'redux';
+
+export const newStore = () => createStore(
+ reducers,
+ applyMiddleware(promise),
+);
diff --git a/src/content/urls.ts b/src/content/urls.ts
index 6e7ea31..390efde 100644
--- a/src/content/urls.ts
+++ b/src/content/urls.ts
@@ -1,7 +1,7 @@
-import messages from 'shared/messages';
+import * as messages from '../shared/messages';
import * as urls from '../shared/urls';
-const yank = (win) => {
+const yank = (win: Window) => {
let input = win.document.createElement('input');
win.document.body.append(input);
@@ -15,7 +15,7 @@ const yank = (win) => {
input.remove();
};
-const paste = (win, newTab, searchSettings) => {
+const paste = (win: Window, newTab: boolean, searchSettings: any) => {
let textarea = win.document.createElement('textarea');
win.document.body.append(textarea);
@@ -25,7 +25,7 @@ const paste = (win, newTab, searchSettings) => {
textarea.focus();
if (win.document.execCommand('paste')) {
- let value = textarea.textContent;
+ let value = textarea.textContent as string;
let url = urls.searchUrl(value, searchSettings);
browser.runtime.sendMessage({
type: messages.OPEN_URL,
diff --git a/src/shared/messages.ts b/src/shared/messages.ts
index 2bc12d8..41b0f0b 100644
--- a/src/shared/messages.ts
+++ b/src/shared/messages.ts
@@ -1,78 +1,276 @@
-type WebMessageSender = Window | MessagePort | ServiceWorker | null;
-type WebMessageListener = (msg: any, sender: WebMessageSender | null) => void;
-
-const onWebMessage = (listener: WebMessageListener) => {
- window.addEventListener('message', (event: MessageEvent) => {
- let sender = event.source;
- let message = null;
- try {
- message = JSON.parse(event.data);
- } catch (e) {
- // ignore unexpected message
- return;
- }
- listener(message, sender);
- });
-};
+import * as operations from './operations';
-const onBackgroundMessage = (
- listener: (msg: any, sender: browser.runtime.MessageSender,
-) => void) => {
- browser.runtime.onMessage.addListener(listener);
-};
+export const BACKGROUND_OPERATION = 'background.operation';
-const onMessage = (
- listener: (msg: any, sender: WebMessageSender | browser.runtime.MessageSender,
-) => void) => {
- onWebMessage(listener);
- onBackgroundMessage(listener);
-};
+export const CONSOLE_UNFOCUS = 'console.unfocus';
+export const CONSOLE_ENTER_COMMAND = 'console.enter.command';
+export const CONSOLE_ENTER_FIND = 'console.enter.find';
+export const CONSOLE_QUERY_COMPLETIONS = 'console.query.completions';
+export const CONSOLE_SHOW_COMMAND = 'console.show.command';
+export const CONSOLE_SHOW_ERROR = 'console.show.error';
+export const CONSOLE_SHOW_INFO = 'console.show.info';
+export const CONSOLE_SHOW_FIND = 'console.show.find';
+export const CONSOLE_HIDE = 'console.hide';
+
+export const FOLLOW_START = 'follow.start';
+export const FOLLOW_REQUEST_COUNT_TARGETS = 'follow.request.count.targets';
+export const FOLLOW_RESPONSE_COUNT_TARGETS = 'follow.response.count.targets';
+export const FOLLOW_CREATE_HINTS = 'follow.create.hints';
+export const FOLLOW_SHOW_HINTS = 'follow.update.hints';
+export const FOLLOW_REMOVE_HINTS = 'follow.remove.hints';
+export const FOLLOW_ACTIVATE = 'follow.activate';
+export const FOLLOW_KEY_PRESS = 'follow.key.press';
+
+export const MARK_SET_GLOBAL = 'mark.set.global';
+export const MARK_JUMP_GLOBAL = 'mark.jump.global';
+
+export const TAB_SCROLL_TO = 'tab.scroll.to';
+
+export const FIND_NEXT = 'find.next';
+export const FIND_PREV = 'find.prev';
+export const FIND_GET_KEYWORD = 'find.get.keyword';
+export const FIND_SET_KEYWORD = 'find.set.keyword';
+
+export const ADDON_ENABLED_QUERY = 'addon.enabled.query';
+export const ADDON_ENABLED_RESPONSE = 'addon.enabled.response';
+export const ADDON_TOGGLE_ENABLED = 'addon.toggle.enabled';
+
+export const OPEN_URL = 'open.url';
+
+export const SETTINGS_CHANGED = 'settings.changed';
+export const SETTINGS_QUERY = 'settings.query';
+
+export const CONSOLE_FRAME_MESSAGE = 'console.frame.message';
+
+interface BackgroundOperationMessage {
+ type: typeof BACKGROUND_OPERATION;
+ operation: operations.Operation;
+}
+
+interface ConsoleUnfocusMessage {
+ type: typeof CONSOLE_UNFOCUS;
+}
+
+interface ConsoleEnterCommandMessage {
+ type: typeof CONSOLE_ENTER_COMMAND;
+ text: string;
+}
+
+interface ConsoleEnterFindMessage {
+ type: typeof CONSOLE_ENTER_FIND;
+ text: string;
+}
+
+interface ConsoleQueryCompletionsMessage {
+ type: typeof CONSOLE_QUERY_COMPLETIONS;
+ text: string;
+}
+
+interface ConsoleShowCommandMessage {
+ type: typeof CONSOLE_SHOW_COMMAND;
+ command: string;
+}
+
+interface ConsoleShowErrorMessage {
+ type: typeof CONSOLE_SHOW_ERROR;
+ text: string;
+}
+
+interface ConsoleShowInfoMessage {
+ type: typeof CONSOLE_SHOW_INFO;
+ text: string;
+}
+
+interface ConsoleShowFindMessage {
+ type: typeof CONSOLE_SHOW_FIND;
+}
+
+interface ConsoleHideMessage {
+ type: typeof CONSOLE_HIDE;
+}
+
+interface FollowStartMessage {
+ type: typeof FOLLOW_START;
+ newTab: boolean;
+ background: boolean;
+}
+
+interface FollowRequestCountTargetsMessage {
+ type: typeof FOLLOW_REQUEST_COUNT_TARGETS;
+ viewSize: { width: number, height: number };
+ framePosition: { x: number, y: number };
+}
+
+interface FollowResponseCountTargetsMessage {
+ type: typeof FOLLOW_RESPONSE_COUNT_TARGETS;
+ count: number;
+}
+
+interface FollowCreateHintsMessage {
+ type: typeof FOLLOW_CREATE_HINTS;
+ keysArray: string[];
+ newTab: boolean;
+ background: boolean;
+}
+
+interface FollowShowHintsMessage {
+ type: typeof FOLLOW_SHOW_HINTS;
+ keys: string;
+}
+
+interface FollowRemoveHintsMessage {
+ type: typeof FOLLOW_REMOVE_HINTS;
+}
+
+interface FollowActivateMessage {
+ type: typeof FOLLOW_ACTIVATE;
+ keys: string;
+}
+
+interface FollowKeyPressMessage {
+ type: typeof FOLLOW_KEY_PRESS;
+ key: string;
+ ctrlKey: boolean;
+}
+
+interface MarkSetGlobalMessage {
+ type: typeof MARK_SET_GLOBAL;
+ key: string;
+ x: number;
+ y: number;
+}
+
+interface MarkJumpGlobalMessage {
+ type: typeof MARK_JUMP_GLOBAL;
+ key: string;
+}
+
+interface TabScrollToMessage {
+ type: typeof TAB_SCROLL_TO;
+ x: number;
+ y: number;
+}
+
+interface FindNextMessage {
+ type: typeof FIND_NEXT;
+}
+
+interface FindPrevMessage {
+ type: typeof FIND_PREV;
+}
+
+interface FindGetKeywordMessage {
+ type: typeof FIND_GET_KEYWORD;
+}
+
+interface FindSetKeywordMessage {
+ type: typeof FIND_SET_KEYWORD;
+ keyword: string;
+ found: boolean;
+}
+
+interface AddonEnabledQueryMessage {
+ type: typeof ADDON_ENABLED_QUERY;
+}
+
+interface AddonEnabledResponseMessage {
+ type: typeof ADDON_ENABLED_RESPONSE;
+ enabled: boolean;
+}
+
+interface AddonToggleEnabledMessage {
+ type: typeof ADDON_TOGGLE_ENABLED;
+}
+
+interface OpenUrlMessage {
+ type: typeof OPEN_URL;
+ url: string;
+ newTab: boolean;
+ background: boolean;
+}
+
+interface SettingsChangedMessage {
+ type: typeof SETTINGS_CHANGED;
+}
+
+interface SettingsQueryMessage {
+ type: typeof SETTINGS_QUERY;
+}
+
+interface ConsoleFrameMessageMessage {
+ type: typeof CONSOLE_FRAME_MESSAGE;
+ message: any;
+}
+
+export type Message =
+ BackgroundOperationMessage |
+ ConsoleUnfocusMessage |
+ ConsoleEnterCommandMessage |
+ ConsoleEnterFindMessage |
+ ConsoleQueryCompletionsMessage |
+ ConsoleShowCommandMessage |
+ ConsoleShowErrorMessage |
+ ConsoleShowInfoMessage |
+ ConsoleShowFindMessage |
+ ConsoleHideMessage |
+ FollowStartMessage |
+ FollowRequestCountTargetsMessage |
+ FollowResponseCountTargetsMessage |
+ FollowCreateHintsMessage |
+ FollowShowHintsMessage |
+ FollowRemoveHintsMessage |
+ FollowActivateMessage |
+ FollowKeyPressMessage |
+ MarkSetGlobalMessage |
+ MarkJumpGlobalMessage |
+ TabScrollToMessage |
+ FindNextMessage |
+ FindPrevMessage |
+ FindGetKeywordMessage |
+ FindSetKeywordMessage |
+ AddonEnabledQueryMessage |
+ AddonEnabledResponseMessage |
+ AddonToggleEnabledMessage |
+ OpenUrlMessage |
+ SettingsChangedMessage |
+ SettingsQueryMessage |
+ ConsoleFrameMessageMessage;
-export default {
- BACKGROUND_OPERATION: 'background.operation',
-
- CONSOLE_UNFOCUS: 'console.unfocus',
- CONSOLE_ENTER_COMMAND: 'console.enter.command',
- CONSOLE_ENTER_FIND: 'console.enter.find',
- CONSOLE_QUERY_COMPLETIONS: 'console.query.completions',
- CONSOLE_SHOW_COMMAND: 'console.show.command',
- CONSOLE_SHOW_ERROR: 'console.show.error',
- CONSOLE_SHOW_INFO: 'console.show.info',
- CONSOLE_SHOW_FIND: 'console.show.find',
- CONSOLE_HIDE: 'console.hide',
-
- FOLLOW_START: 'follow.start',
- FOLLOW_REQUEST_COUNT_TARGETS: 'follow.request.count.targets',
- FOLLOW_RESPONSE_COUNT_TARGETS: 'follow.response.count.targets',
- FOLLOW_CREATE_HINTS: 'follow.create.hints',
- FOLLOW_SHOW_HINTS: 'follow.update.hints',
- FOLLOW_REMOVE_HINTS: 'follow.remove.hints',
- FOLLOW_ACTIVATE: 'follow.activate',
- FOLLOW_KEY_PRESS: 'follow.key.press',
-
- MARK_SET_GLOBAL: 'mark.set.global',
- MARK_JUMP_GLOBAL: 'mark.jump.global',
-
- TAB_SCROLL_TO: 'tab.scroll.to',
-
- FIND_NEXT: 'find.next',
- FIND_PREV: 'find.prev',
- FIND_GET_KEYWORD: 'find.get.keyword',
- FIND_SET_KEYWORD: 'find.set.keyword',
-
- ADDON_ENABLED_QUERY: 'addon.enabled.query',
- ADDON_ENABLED_RESPONSE: 'addon.enabled.response',
- ADDON_TOGGLE_ENABLED: 'addon.toggle.enabled',
-
- OPEN_URL: 'open.url',
-
- SETTINGS_CHANGED: 'settings.changed',
- SETTINGS_QUERY: 'settings.query',
-
- WINDOW_TOP_MESSAGE: 'window.top.message',
- CONSOLE_FRAME_MESSAGE: 'console.frame.message',
-
- onWebMessage,
- onBackgroundMessage,
- onMessage,
+// eslint-disable-next-line complexity
+export const valueOf = (o: any): Message => {
+ switch (o.type) {
+ case CONSOLE_UNFOCUS:
+ case CONSOLE_ENTER_COMMAND:
+ case CONSOLE_ENTER_FIND:
+ case CONSOLE_QUERY_COMPLETIONS:
+ case CONSOLE_SHOW_COMMAND:
+ case CONSOLE_SHOW_ERROR:
+ case CONSOLE_SHOW_INFO:
+ case CONSOLE_SHOW_FIND:
+ case CONSOLE_HIDE:
+ case FOLLOW_START:
+ case FOLLOW_REQUEST_COUNT_TARGETS:
+ case FOLLOW_RESPONSE_COUNT_TARGETS:
+ case FOLLOW_CREATE_HINTS:
+ case FOLLOW_SHOW_HINTS:
+ case FOLLOW_REMOVE_HINTS:
+ case FOLLOW_ACTIVATE:
+ case FOLLOW_KEY_PRESS:
+ case MARK_SET_GLOBAL:
+ case MARK_JUMP_GLOBAL:
+ case TAB_SCROLL_TO:
+ case FIND_NEXT:
+ case FIND_PREV:
+ case FIND_GET_KEYWORD:
+ case FIND_SET_KEYWORD:
+ case ADDON_ENABLED_QUERY:
+ case ADDON_ENABLED_RESPONSE:
+ case ADDON_TOGGLE_ENABLED:
+ case OPEN_URL:
+ case SETTINGS_CHANGED:
+ case SETTINGS_QUERY:
+ case CONSOLE_FRAME_MESSAGE:
+ return o;
+ }
+ throw new Error('unknown operation type: ' + o.type);
};
diff --git a/src/shared/operations.ts b/src/shared/operations.ts
index d59723e..cc22f75 100644
--- a/src/shared/operations.ts
+++ b/src/shared/operations.ts
@@ -1,80 +1,447 @@
-const operations: { [key: string]: string } = {
- // Hide console, or cancel some user actions
- CANCEL: 'cancel',
-
- // Addons
- ADDON_ENABLE: 'addon.enable',
- ADDON_DISABLE: 'addon.disable',
- ADDON_TOGGLE_ENABLED: 'addon.toggle.enabled',
-
- // Command
- COMMAND_SHOW: 'command.show',
- COMMAND_SHOW_OPEN: 'command.show.open',
- COMMAND_SHOW_TABOPEN: 'command.show.tabopen',
- COMMAND_SHOW_WINOPEN: 'command.show.winopen',
- COMMAND_SHOW_BUFFER: 'command.show.buffer',
- COMMAND_SHOW_ADDBOOKMARK: 'command.show.addbookmark',
-
- // Scrolls
- SCROLL_VERTICALLY: 'scroll.vertically',
- SCROLL_HORIZONALLY: 'scroll.horizonally',
- SCROLL_PAGES: 'scroll.pages',
- SCROLL_TOP: 'scroll.top',
- SCROLL_BOTTOM: 'scroll.bottom',
- SCROLL_HOME: 'scroll.home',
- SCROLL_END: 'scroll.end',
-
- // Follows
- FOLLOW_START: 'follow.start',
-
- // Navigations
- NAVIGATE_HISTORY_PREV: 'navigate.history.prev',
- NAVIGATE_HISTORY_NEXT: 'navigate.history.next',
- NAVIGATE_LINK_PREV: 'navigate.link.prev',
- NAVIGATE_LINK_NEXT: 'navigate.link.next',
- NAVIGATE_PARENT: 'navigate.parent',
- NAVIGATE_ROOT: 'navigate.root',
-
- // Focus
- FOCUS_INPUT: 'focus.input',
-
- // Page
- PAGE_SOURCE: 'page.source',
- PAGE_HOME: 'page.home',
-
- // Tabs
- TAB_CLOSE: 'tabs.close',
- TAB_CLOSE_FORCE: 'tabs.close.force',
- TAB_CLOSE_RIGHT: 'tabs.close.right',
- TAB_REOPEN: 'tabs.reopen',
- TAB_PREV: 'tabs.prev',
- 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',
- TAB_TOGGLE_PINNED: 'tabs.pin.toggle',
- TAB_DUPLICATE: 'tabs.duplicate',
-
- // Zooms
- ZOOM_IN: 'zoom.in',
- ZOOM_OUT: 'zoom.out',
- ZOOM_NEUTRAL: 'zoom.neutral',
-
- // Url yank/paste
- URLS_YANK: 'urls.yank',
- URLS_PASTE: 'urls.paste',
-
- // Find
- FIND_START: 'find.start',
- FIND_NEXT: 'find.next',
- FIND_PREV: 'find.prev',
-
- // Mark
- MARK_SET_PREFIX: 'mark.set.prefix',
- MARK_JUMP_PREFIX: 'mark.jump.prefix',
+// Hide console; or cancel some user actions
+export const CANCEL = 'cancel';
+
+// Addons
+export const ADDON_ENABLE = 'addon.enable';
+export const ADDON_DISABLE = 'addon.disable';
+export const ADDON_TOGGLE_ENABLED = 'addon.toggle.enabled';
+
+// Command
+export const COMMAND_SHOW = 'command.show';
+export const COMMAND_SHOW_OPEN = 'command.show.open';
+export const COMMAND_SHOW_TABOPEN = 'command.show.tabopen';
+export const COMMAND_SHOW_WINOPEN = 'command.show.winopen';
+export const COMMAND_SHOW_BUFFER = 'command.show.buffer';
+export const COMMAND_SHOW_ADDBOOKMARK = 'command.show.addbookmark';
+
+// Scrolls
+export const SCROLL_VERTICALLY = 'scroll.vertically';
+export const SCROLL_HORIZONALLY = 'scroll.horizonally';
+export const SCROLL_PAGES = 'scroll.pages';
+export const SCROLL_TOP = 'scroll.top';
+export const SCROLL_BOTTOM = 'scroll.bottom';
+export const SCROLL_HOME = 'scroll.home';
+export const SCROLL_END = 'scroll.end';
+
+// Follows
+export const FOLLOW_START = 'follow.start';
+
+// Navigations
+export const NAVIGATE_HISTORY_PREV = 'navigate.history.prev';
+export const NAVIGATE_HISTORY_NEXT = 'navigate.history.next';
+export const NAVIGATE_LINK_PREV = 'navigate.link.prev';
+export const NAVIGATE_LINK_NEXT = 'navigate.link.next';
+export const NAVIGATE_PARENT = 'navigate.parent';
+export const NAVIGATE_ROOT = 'navigate.root';
+
+// Focus
+export const FOCUS_INPUT = 'focus.input';
+
+// Page
+export const PAGE_SOURCE = 'page.source';
+export const PAGE_HOME = 'page.home';
+
+// Tabs
+export const TAB_CLOSE = 'tabs.close';
+export const TAB_CLOSE_FORCE = 'tabs.close.force';
+export const TAB_CLOSE_RIGHT = 'tabs.close.right';
+export const TAB_REOPEN = 'tabs.reopen';
+export const TAB_PREV = 'tabs.prev';
+export const TAB_NEXT = 'tabs.next';
+export const TAB_FIRST = 'tabs.first';
+export const TAB_LAST = 'tabs.last';
+export const TAB_PREV_SEL = 'tabs.prevsel';
+export const TAB_RELOAD = 'tabs.reload';
+export const TAB_PIN = 'tabs.pin';
+export const TAB_UNPIN = 'tabs.unpin';
+export const TAB_TOGGLE_PINNED = 'tabs.pin.toggle';
+export const TAB_DUPLICATE = 'tabs.duplicate';
+
+// Zooms
+export const ZOOM_IN = 'zoom.in';
+export const ZOOM_OUT = 'zoom.out';
+export const ZOOM_NEUTRAL = 'zoom.neutral';
+
+// Url yank/paste
+export const URLS_YANK = 'urls.yank';
+export const URLS_PASTE = 'urls.paste';
+
+// Find
+export const FIND_START = 'find.start';
+export const FIND_NEXT = 'find.next';
+export const FIND_PREV = 'find.prev';
+
+// Mark
+export const MARK_SET_PREFIX = 'mark.set.prefix';
+export const MARK_JUMP_PREFIX = 'mark.jump.prefix';
+
+export interface CancelOperation {
+ type: typeof CANCEL;
+}
+
+export interface AddonEnableOperation {
+ type: typeof ADDON_ENABLE;
+}
+
+export interface AddonDisableOperation {
+ type: typeof ADDON_DISABLE;
+}
+
+export interface AddonToggleEnabledOperation {
+ type: typeof ADDON_TOGGLE_ENABLED;
+}
+
+export interface CommandShowOperation {
+ type: typeof COMMAND_SHOW;
+}
+
+export interface CommandShowOpenOperation {
+ type: typeof COMMAND_SHOW_OPEN;
+ alter: boolean;
+}
+
+export interface CommandShowTabopenOperation {
+ type: typeof COMMAND_SHOW_TABOPEN;
+ alter: boolean;
+}
+
+export interface CommandShowWinopenOperation {
+ type: typeof COMMAND_SHOW_WINOPEN;
+ alter: boolean;
+}
+
+export interface CommandShowBufferOperation {
+ type: typeof COMMAND_SHOW_BUFFER;
+}
+
+export interface CommandShowAddbookmarkOperation {
+ type: typeof COMMAND_SHOW_ADDBOOKMARK;
+ alter: boolean;
+}
+
+export interface ScrollVerticallyOperation {
+ type: typeof SCROLL_VERTICALLY;
+ count: number;
+}
+
+export interface ScrollHorizonallyOperation {
+ type: typeof SCROLL_HORIZONALLY;
+ count: number;
+}
+
+export interface ScrollPagesOperation {
+ type: typeof SCROLL_PAGES;
+ count: number;
+}
+
+export interface ScrollTopOperation {
+ type: typeof SCROLL_TOP;
+}
+
+export interface ScrollBottomOperation {
+ type: typeof SCROLL_BOTTOM;
+}
+
+export interface ScrollHomeOperation {
+ type: typeof SCROLL_HOME;
+}
+
+export interface ScrollEndOperation {
+ type: typeof SCROLL_END;
+}
+
+export interface FollowStartOperation {
+ type: typeof FOLLOW_START;
+ newTab: boolean;
+ background: boolean;
+}
+
+export interface NavigateHistoryPrevOperation {
+ type: typeof NAVIGATE_HISTORY_PREV;
+}
+
+export interface NavigateHistoryNextOperation {
+ type: typeof NAVIGATE_HISTORY_NEXT;
+}
+
+export interface NavigateLinkPrevOperation {
+ type: typeof NAVIGATE_LINK_PREV;
+}
+
+export interface NavigateLinkNextOperation {
+ type: typeof NAVIGATE_LINK_NEXT;
+}
+
+export interface NavigateParentOperation {
+ type: typeof NAVIGATE_PARENT;
+}
+
+export interface NavigateRootOperation {
+ type: typeof NAVIGATE_ROOT;
+}
+
+export interface FocusInputOperation {
+ type: typeof FOCUS_INPUT;
+}
+
+export interface PageSourceOperation {
+ type: typeof PAGE_SOURCE;
+}
+
+export interface PageHomeOperation {
+ type: typeof PAGE_HOME;
+ newTab: boolean;
+}
+
+export interface TabCloseOperation {
+ type: typeof TAB_CLOSE;
+}
+
+export interface TabCloseForceOperation {
+ type: typeof TAB_CLOSE_FORCE;
+}
+
+export interface TabCloseRightOperation {
+ type: typeof TAB_CLOSE_RIGHT;
+}
+
+export interface TabReopenOperation {
+ type: typeof TAB_REOPEN;
+}
+
+export interface TabPrevOperation {
+ type: typeof TAB_PREV;
+}
+
+export interface TabNextOperation {
+ type: typeof TAB_NEXT;
+}
+
+export interface TabFirstOperation {
+ type: typeof TAB_FIRST;
+}
+
+export interface TabLastOperation {
+ type: typeof TAB_LAST;
+}
+
+export interface TabPrevSelOperation {
+ type: typeof TAB_PREV_SEL;
+}
+
+export interface TabReloadOperation {
+ type: typeof TAB_RELOAD;
+ cache: boolean;
+}
+
+export interface TabPinOperation {
+ type: typeof TAB_PIN;
+}
+
+export interface TabUnpinOperation {
+ type: typeof TAB_UNPIN;
+}
+
+export interface TabTogglePinnedOperation {
+ type: typeof TAB_TOGGLE_PINNED;
+}
+
+export interface TabDuplicateOperation {
+ type: typeof TAB_DUPLICATE;
+}
+
+export interface ZoomInOperation {
+ type: typeof ZOOM_IN;
+}
+
+export interface ZoomOutOperation {
+ type: typeof ZOOM_OUT;
+}
+
+export interface ZoomNeutralOperation {
+ type: typeof ZOOM_NEUTRAL;
+}
+
+export interface UrlsYankOperation {
+ type: typeof URLS_YANK;
+}
+
+export interface UrlsPasteOperation {
+ type: typeof URLS_PASTE;
+ newTab: boolean;
+}
+
+export interface FindStartOperation {
+ type: typeof FIND_START;
+}
+
+export interface FindNextOperation {
+ type: typeof FIND_NEXT;
+}
+
+export interface FindPrevOperation {
+ type: typeof FIND_PREV;
+}
+
+export interface MarkSetPrefixOperation {
+ type: typeof MARK_SET_PREFIX;
+}
+
+export interface MarkJumpPrefixOperation {
+ type: typeof MARK_JUMP_PREFIX;
+}
+
+export type Operation =
+ CancelOperation |
+ AddonEnableOperation |
+ AddonDisableOperation |
+ AddonToggleEnabledOperation |
+ CommandShowOperation |
+ CommandShowOpenOperation |
+ CommandShowTabopenOperation |
+ CommandShowWinopenOperation |
+ CommandShowBufferOperation |
+ CommandShowAddbookmarkOperation |
+ ScrollVerticallyOperation |
+ ScrollHorizonallyOperation |
+ ScrollPagesOperation |
+ ScrollTopOperation |
+ ScrollBottomOperation |
+ ScrollHomeOperation |
+ ScrollEndOperation |
+ FollowStartOperation |
+ NavigateHistoryPrevOperation |
+ NavigateHistoryNextOperation |
+ NavigateLinkPrevOperation |
+ NavigateLinkNextOperation |
+ NavigateParentOperation |
+ NavigateRootOperation |
+ FocusInputOperation |
+ PageSourceOperation |
+ PageHomeOperation |
+ TabCloseOperation |
+ TabCloseForceOperation |
+ TabCloseRightOperation |
+ TabReopenOperation |
+ TabPrevOperation |
+ TabNextOperation |
+ TabFirstOperation |
+ TabLastOperation |
+ TabPrevSelOperation |
+ TabReloadOperation |
+ TabPinOperation |
+ TabUnpinOperation |
+ TabTogglePinnedOperation |
+ TabDuplicateOperation |
+ ZoomInOperation |
+ ZoomOutOperation |
+ ZoomNeutralOperation |
+ UrlsYankOperation |
+ UrlsPasteOperation |
+ FindStartOperation |
+ FindNextOperation |
+ FindPrevOperation |
+ MarkSetPrefixOperation |
+ MarkJumpPrefixOperation;
+
+const assertOptionalBoolean = (obj: any, name: string) => {
+ if (Object.prototype.hasOwnProperty.call(obj, name) &&
+ typeof obj[name] !== 'boolean') {
+ throw new TypeError(`Not a boolean parameter '${name}'`);
+ }
+};
+
+const assertRequiredNumber = (obj: any, name: string) => {
+ if (!Object.prototype.hasOwnProperty.call(obj, name) ||
+ typeof obj[name] !== 'number') {
+ throw new TypeError(`Missing number parameter '${name}`);
+ }
};
-export default operations;
+// eslint-disable-next-line complexity, max-lines-per-function
+export const valueOf = (o: any): Operation => {
+ if (!Object.prototype.hasOwnProperty.call(o, 'type')) {
+ throw new TypeError(`missing 'type' field`);
+ }
+ switch (o.type) {
+ case COMMAND_SHOW_OPEN:
+ case COMMAND_SHOW_TABOPEN:
+ case COMMAND_SHOW_WINOPEN:
+ case COMMAND_SHOW_ADDBOOKMARK:
+ assertOptionalBoolean(o, 'alter');
+ return { type: o.type, alter: Boolean(o.alter) };
+ case SCROLL_VERTICALLY:
+ case SCROLL_HORIZONALLY:
+ case SCROLL_PAGES:
+ assertRequiredNumber(o, 'count');
+ return { type: o.type, count: Number(o.count) };
+ case FOLLOW_START:
+ assertOptionalBoolean(o, 'newTab');
+ assertOptionalBoolean(o, 'background');
+ return {
+ type: FOLLOW_START,
+ newTab: Boolean(typeof o.newTab === undefined ? false : o.newTab),
+ background: Boolean(typeof o.background === undefined ? true : o.background), // eslint-disable-line max-len
+ };
+ case PAGE_HOME:
+ assertOptionalBoolean(o, 'newTab');
+ return {
+ type: PAGE_HOME,
+ newTab: Boolean(typeof o.newTab === undefined ? false : o.newTab),
+ };
+ case TAB_RELOAD:
+ assertOptionalBoolean(o, 'cache');
+ return {
+ type: TAB_RELOAD,
+ cache: Boolean(typeof o.cache === undefined ? false : o.cache),
+ };
+ case URLS_PASTE:
+ assertOptionalBoolean(o, 'newTab');
+ return {
+ type: URLS_PASTE,
+ newTab: Boolean(typeof o.newTab === undefined ? false : o.newTab),
+ };
+ case CANCEL:
+ case ADDON_ENABLE:
+ case ADDON_DISABLE:
+ case ADDON_TOGGLE_ENABLED:
+ case COMMAND_SHOW:
+ case COMMAND_SHOW_BUFFER:
+ case SCROLL_TOP:
+ case SCROLL_BOTTOM:
+ case SCROLL_HOME:
+ case SCROLL_END:
+ case NAVIGATE_HISTORY_PREV:
+ case NAVIGATE_HISTORY_NEXT:
+ case NAVIGATE_LINK_PREV:
+ case NAVIGATE_LINK_NEXT:
+ case NAVIGATE_PARENT:
+ case NAVIGATE_ROOT:
+ case FOCUS_INPUT:
+ case PAGE_SOURCE:
+ case TAB_CLOSE:
+ case TAB_CLOSE_FORCE:
+ case TAB_CLOSE_RIGHT:
+ case TAB_REOPEN:
+ case TAB_PREV:
+ case TAB_NEXT:
+ case TAB_FIRST:
+ case TAB_LAST:
+ case TAB_PREV_SEL:
+ case TAB_PIN:
+ case TAB_UNPIN:
+ case TAB_TOGGLE_PINNED:
+ case TAB_DUPLICATE:
+ case ZOOM_IN:
+ case ZOOM_OUT:
+ case ZOOM_NEUTRAL:
+ case URLS_YANK:
+ case FIND_START:
+ case FIND_NEXT:
+ case FIND_PREV:
+ case MARK_SET_PREFIX:
+ case MARK_JUMP_PREFIX:
+ return { type: o.type };
+ }
+ throw new Error('unknown operation type: ' + o.type);
+};
diff --git a/src/shared/settings/validator.ts b/src/shared/settings/validator.ts
index 0483931..71cc466 100644
--- a/src/shared/settings/validator.ts
+++ b/src/shared/settings/validator.ts
@@ -1,4 +1,4 @@
-import operations from '../operations';
+import * as operations from '../operations';
import * as properties from './properties';
const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist', 'properties'];
diff --git a/src/shared/utils/keys.ts b/src/shared/utils/keys.ts
index d9abef7..e9b0365 100644
--- a/src/shared/utils/keys.ts
+++ b/src/shared/utils/keys.ts
@@ -1,4 +1,4 @@
-interface Key {
+export interface Key {
key: string;
shiftKey: boolean | undefined;
ctrlKey: boolean | undefined;
diff --git a/test/content/actions/follow-controller.test.ts b/test/content/actions/follow-controller.test.ts
index 718a90a..a4b1710 100644
--- a/test/content/actions/follow-controller.test.ts
+++ b/test/content/actions/follow-controller.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import * as followControllerActions from 'content/actions/follow-controller';
describe('follow-controller actions', () => {
diff --git a/test/content/actions/input.test.ts b/test/content/actions/input.test.ts
index fe9db5f..33238a5 100644
--- a/test/content/actions/input.test.ts
+++ b/test/content/actions/input.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import * as inputActions from 'content/actions/input';
describe("input actions", () => {
diff --git a/test/content/actions/mark.test.ts b/test/content/actions/mark.test.ts
index adbf06b..6c6d59e 100644
--- a/test/content/actions/mark.test.ts
+++ b/test/content/actions/mark.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import * as markActions from 'content/actions/mark';
describe('mark actions', () => {
diff --git a/test/content/actions/setting.test.ts b/test/content/actions/setting.test.ts
index 10f6807..0721d5d 100644
--- a/test/content/actions/setting.test.ts
+++ b/test/content/actions/setting.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import * as settingActions from 'content/actions/setting';
describe("setting actions", () => {
diff --git a/test/content/components/common/input.test.ts b/test/content/components/common/input.test.ts
index 2ba5507..f3a943c 100644
--- a/test/content/components/common/input.test.ts
+++ b/test/content/components/common/input.test.ts
@@ -21,12 +21,14 @@ describe('InputComponent', () => {
++b;
}
});
- component.onKeyDown({ key: 'a' });
- component.onKeyDown({ key: 'b' });
- component.onKeyPress({ key: 'a' });
- component.onKeyUp({ key: 'a' });
- component.onKeyPress({ key: 'b' });
- component.onKeyUp({ key: 'b' });
+
+ let elem = document.body;
+ component.onKeyDown({ key: 'a', target: elem });
+ component.onKeyDown({ key: 'b', target: elem });
+ component.onKeyPress({ key: 'a', target: elem });
+ component.onKeyUp({ key: 'a', target: elem });
+ component.onKeyPress({ key: 'b', target: elem });
+ component.onKeyUp({ key: 'b', target: elem });
expect(a).is.equals(1);
expect(b).is.equals(1);
diff --git a/test/content/reducers/addon.test.ts b/test/content/reducers/addon.test.ts
index d4eb845..fb05244 100644
--- a/test/content/reducers/addon.test.ts
+++ b/test/content/reducers/addon.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import addonReducer from 'content/reducers/addon';
describe("addon reducer", () => {
diff --git a/test/content/reducers/find.test.ts b/test/content/reducers/find.test.ts
index a8c30d7..66a2c67 100644
--- a/test/content/reducers/find.test.ts
+++ b/test/content/reducers/find.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import findReducer from 'content/reducers/find';
describe("find reducer", () => {
diff --git a/test/content/reducers/follow-controller.test.ts b/test/content/reducers/follow-controller.test.ts
index 8a4c2d4..39f326c 100644
--- a/test/content/reducers/follow-controller.test.ts
+++ b/test/content/reducers/follow-controller.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import followControllerReducer from 'content/reducers/follow-controller';
describe('follow-controller reducer', () => {
diff --git a/test/content/reducers/input.test.ts b/test/content/reducers/input.test.ts
index 0011943..f892201 100644
--- a/test/content/reducers/input.test.ts
+++ b/test/content/reducers/input.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import inputReducer from 'content/reducers/input';
describe("input reducer", () => {
diff --git a/test/content/reducers/mark.test.ts b/test/content/reducers/mark.test.ts
index 76efbf7..1a51c3e 100644
--- a/test/content/reducers/mark.test.ts
+++ b/test/content/reducers/mark.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import reducer from 'content/reducers/mark';
describe("mark reducer", () => {
diff --git a/test/content/reducers/setting.test.ts b/test/content/reducers/setting.test.ts
index 4e4c095..226fc58 100644
--- a/test/content/reducers/setting.test.ts
+++ b/test/content/reducers/setting.test.ts
@@ -1,4 +1,4 @@
-import actions from 'content/actions';
+import * as actions from 'content/actions';
import settingReducer from 'content/reducers/setting';
describe("content setting reducer", () => {
diff --git a/test/shared/operations.test.ts b/test/shared/operations.test.ts
new file mode 100644
index 0000000..42a3eed
--- /dev/null
+++ b/test/shared/operations.test.ts
@@ -0,0 +1,41 @@
+import * as operations from 'shared/operations';
+
+describe('operations', () => {
+ describe('#valueOf', () => {
+ it('returns an Operation', () => {
+ let op: operations.Operation = operations.valueOf({
+ type: operations.SCROLL_VERTICALLY,
+ count: 10,
+ });
+ expect(op.type).to.equal(operations.SCROLL_VERTICALLY);
+ expect(op.count).to.equal(10);
+ });
+
+ it('throws an Error on missing required parameter', () => {
+ expect(() => operations.valueOf({
+ type: operations.SCROLL_VERTICALLY,
+ })).to.throw(TypeError);
+ });
+
+ it('fills default valus of optional parameter', () => {
+ let op: operations.Operation = operations.valueOf({
+ type: operations.COMMAND_SHOW_OPEN,
+ });
+
+ expect(op.type).to.equal(operations.COMMAND_SHOW_OPEN)
+ expect(op.alter).to.be.false;
+ });
+
+ it('throws an Error on mismatch of parameter', () => {
+ expect(() => operations.valueOf({
+ type: operations.SCROLL_VERTICALLY,
+ count: '10',
+ })).to.throw(TypeError);
+
+ expect(() => valueOf({
+ type: operations.COMMAND_SHOW_OPEN,
+ alter: 'true',
+ })).to.throw(TypeError);
+ });
+ });
+})
diff --git a/tsconfig.json b/tsconfig.json
index 575601b..b61ee23 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,11 +2,11 @@
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
+ "lib": ["es6", "dom", "es2017"],
"allowJs": true,
"checkJs": true,
+ "noEmit": true,
"jsx": "react",
- "declaration": true,
- "declarationMap": true,
"sourceMap": true,
"outDir": "./build",
"removeComments": true,
@@ -29,5 +29,8 @@
"esModuleInterop": true,
"typeRoots": ["node_modules/@types", "node_modules/web-ext-types"]
- }
+ },
+ "include": [
+ "src"
+ ]
}
--
cgit v1.2.3
From b002d70070a1b691b635220bc694c48df36faca5 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka
Date: Mon, 6 May 2019 22:17:01 +0900
Subject: src/content
---
.../repositories/BrowserSettingRepository.ts | 16 +++++++
src/background/usecases/MarkUseCase.ts | 17 ++++----
src/background/usecases/VersionUseCase.ts | 2 +-
src/background/usecases/filters.ts | 6 ++-
src/console/components/Console.tsx | 51 ++++++++++------------
src/console/components/console/Input.tsx | 16 +++----
src/console/components/console/Message.tsx | 2 +-
src/console/reducers/index.ts | 2 +-
src/content/Mark.ts | 6 +++
src/content/actions/find.ts | 18 +++++++-
src/content/actions/index.ts | 3 +-
src/content/actions/input.ts | 3 +-
src/content/components/common/index.ts | 2 +-
src/content/components/common/mark.ts | 41 +++++++++--------
src/content/index.ts | 2 +-
src/content/reducers/input.ts | 3 +-
src/content/reducers/mark.ts | 6 +--
src/content/site-style.ts | 2 +-
test/content/reducers/setting.test.ts | 1 -
19 files changed, 119 insertions(+), 80 deletions(-)
create mode 100644 src/content/Mark.ts
(limited to 'src/console')
diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts
index 48c72a5..33b35dd 100644
--- a/src/background/repositories/BrowserSettingRepository.ts
+++ b/src/background/repositories/BrowserSettingRepository.ts
@@ -1,5 +1,21 @@
import * as urls from '../../shared/urls';
+declare namespace browser.browserSettings.homepageOverride {
+
+ type BrowserSettings = {
+ value: string;
+ levelOfControl: LevelOfControlType;
+ };
+
+ type LevelOfControlType =
+ 'not_controllable' |
+ 'controlled_by_other_extensions' |
+ 'controllable_by_this_extension' |
+ 'controlled_by_this_extension';
+
+ function get(param: object): Promise;
+}
+
export default class BrowserSettingRepository {
async getHomepageUrls(): Promise {
let { value } = await browser.browserSettings.homepageOverride.get({});
diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts
index 8b544aa..e376c55 100644
--- a/src/background/usecases/MarkUseCase.ts
+++ b/src/background/usecases/MarkUseCase.ts
@@ -21,7 +21,7 @@ export default class MarkUseCase {
async setGlobal(key: string, x: number, y: number): Promise {
let tab = await this.tabPresenter.getCurrent();
- let mark = { tabId: tab.id, url: tab.url, x, y };
+ let mark = { tabId: tab.id as number, url: tab.url as string, x, y };
return this.markRepository.setMark(key, mark);
}
@@ -33,15 +33,14 @@ export default class MarkUseCase {
return this.consoleClient.showError(
current.id as number, 'Mark is not set');
}
-
- return this.contentMessageClient.scrollTo(
- mark.tabId, mark.x, mark.y
- ).then(() => {
+ try {
+ await this.contentMessageClient.scrollTo(mark.tabId, mark.x, mark.y);
return this.tabPresenter.select(mark.tabId);
- }).catch(async() => {
+ } catch (e) {
let tab = await this.tabPresenter.create(mark.url);
- let mark2 = { tabId: tab.id, url: mark.url, x: mark.x, y: mark.y };
- return this.markRepository.setMark(key, mark2);
- });
+ return this.markRepository.setMark(key, {
+ tabId: tab.id as number, url: mark.url, x: mark.x, y: mark.y,
+ });
+ }
}
}
diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts
index 3a3cc2e..8154eba 100644
--- a/src/background/usecases/VersionUseCase.ts
+++ b/src/background/usecases/VersionUseCase.ts
@@ -1,4 +1,3 @@
-import manifest from '../../../manifest.json';
import TabPresenter from '../presenters/TabPresenter';
import NotifyPresenter from '../presenters/NotifyPresenter';
@@ -13,6 +12,7 @@ export default class VersionUseCase {
}
notify(): Promise {
+ let manifest = browser.runtime.getManifest();
let title = `Vim Vixen ${manifest.version} has been installed`;
let message = 'Click here to see release notes';
let url = this.releaseNoteUrl(manifest.version);
diff --git a/src/background/usecases/filters.ts b/src/background/usecases/filters.ts
index 44eb56f..84a42fb 100644
--- a/src/background/usecases/filters.ts
+++ b/src/background/usecases/filters.ts
@@ -40,7 +40,8 @@ const filterByPathname = (items: Item[], min: number): Item[] => {
let pathname = url.origin + url.pathname;
if (!hash[pathname]) {
hash[pathname] = item;
- } else if (hash[pathname].url.length > item.url.length) {
+ } else if ((hash[pathname].url as string).length >
+ (item.url as string).length) {
hash[pathname] = item;
}
}
@@ -57,7 +58,8 @@ const filterByOrigin = (items: Item[], min: number): Item[] => {
let origin = new URL(item.url as string).origin;
if (!hash[origin]) {
hash[origin] = item;
- } else if (hash[origin].url.length > item.url.length) {
+ } else if ((hash[origin].url as string).length >
+ (item.url as string).length) {
hash[origin] = item;
}
}
diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx
index 09c0f50..3274047 100644
--- a/src/console/components/Console.tsx
+++ b/src/console/components/Console.tsx
@@ -5,23 +5,23 @@ import Input from './console/Input';
import Completion from './console/Completion';
import Message from './console/Message';
import * as consoleActions from '../../console/actions/console';
+import { State as AppState } from '../reducers';
const COMPLETION_MAX_ITEMS = 33;
-interface Props {
- mode?: string;
- consoleText?: string;
- messageText?: string;
- children?: string;
+type StateProps = ReturnType;
+interface DispatchProps {
+ dispatch: (action: any) => void,
}
+type Props = StateProps & DispatchProps
class Console extends React.Component {
- private input: HTMLInputElement | null;
+ private input: React.RefObject;
constructor(props: Props) {
super(props);
- this.input = null;
+ this.input = React.createRef();
}
onBlur() {
@@ -34,7 +34,7 @@ class Console extends React.Component {
e.stopPropagation();
e.preventDefault();
- let value = e.target.value;
+ let value = (e.target as HTMLInputElement).value;
if (this.props.mode === 'command') {
return this.props.dispatch(consoleActions.enterCommand(value));
} else if (this.props.mode === 'find') {
@@ -55,15 +55,12 @@ class Console extends React.Component {
}
onKeyDown(e: React.KeyboardEvent) {
- if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) {
- this.props.dispatch(consoleActions.hideCommand());
- }
- switch (e.keyCode) {
- case KeyboardEvent.DOM_VK_ESCAPE:
+ switch (e.key) {
+ case 'Escape':
return this.props.dispatch(consoleActions.hideCommand());
- case KeyboardEvent.DOM_VK_RETURN:
+ case 'Enter':
return this.doEnter(e);
- case KeyboardEvent.DOM_VK_TAB:
+ case 'Tab':
if (e.shiftKey) {
this.props.dispatch(consoleActions.completionPrev());
} else {
@@ -72,22 +69,22 @@ class Console extends React.Component {
e.stopPropagation();
e.preventDefault();
break;
- case KeyboardEvent.DOM_VK_OPEN_BRACKET:
+ case '[':
if (e.ctrlKey) {
return this.props.dispatch(consoleActions.hideCommand());
}
break;
- case KeyboardEvent.DOM_VK_M:
+ case 'm':
if (e.ctrlKey) {
return this.doEnter(e);
}
break;
- case KeyboardEvent.DOM_VK_N:
+ case 'n':
if (e.ctrlKey) {
this.selectNext(e);
}
break;
- case KeyboardEvent.DOM_VK_P:
+ case 'p':
if (e.ctrlKey) {
this.selectPrev(e);
}
@@ -105,9 +102,6 @@ class Console extends React.Component {
componentDidUpdate(prevProps: Props) {
- if (!this.input) {
- return;
- }
if (prevProps.mode !== 'command' && this.props.mode === 'command') {
this.props.dispatch(
consoleActions.getCompletions(this.props.consoleText));
@@ -128,7 +122,7 @@ class Console extends React.Component {
select={this.props.select}
/>
{ this.input = c; }}
+ ref={this.input}
mode={this.props.mode}
onBlur={this.onBlur.bind(this)}
onKeyDown={this.onKeyDown.bind(this)}
@@ -148,11 +142,14 @@ class Console extends React.Component {
focus() {
window.focus();
- if (this.input) {
- this.input.focus();
+ if (this.input.current) {
+ this.input.current.focus();
}
}
}
-const mapStateToProps = (state: any) => state;
-export default connect(mapStateToProps)(Console);
+const mapStateToProps = (state: AppState) => ({ ...state });
+
+export default connect(
+ mapStateToProps,
+)(Console);
diff --git a/src/console/components/console/Input.tsx b/src/console/components/console/Input.tsx
index d0348bd..54ea251 100644
--- a/src/console/components/console/Input.tsx
+++ b/src/console/components/console/Input.tsx
@@ -3,23 +3,23 @@ import React from 'react';
interface Props {
mode: string;
value: string;
- onBlur: (e: React.FocusEvent) => void;
- onKeyDown: (e: React.KeyboardEvent) => void;
- onChange: (e: React.ChangeEvent) => void;
+ onBlur: (e: React.FocusEvent) => void;
+ onKeyDown: (e: React.KeyboardEvent) => void;
+ onChange: (e: React.ChangeEvent) => void;
}
class Input extends React.Component {
- private input: HTMLInputElement | null;
+ private input: React.RefObject;
constructor(props: Props) {
super(props);
- this.input = null;
+ this.input = React.createRef();
}
focus() {
- if (this.input) {
- this.input.focus();
+ if (this.input.current) {
+ this.input.current.focus();
}
}
@@ -38,7 +38,7 @@ class Input extends React.Component {
{ this.input = c; }}
+ ref={this.input}
onBlur={this.props.onBlur}
onKeyDown={this.props.onKeyDown}
onChange={this.props.onChange}
diff --git a/src/console/components/console/Message.tsx b/src/console/components/console/Message.tsx
index 07a929e..9fa2788 100644
--- a/src/console/components/console/Message.tsx
+++ b/src/console/components/console/Message.tsx
@@ -2,7 +2,7 @@ import React from 'react';
interface Props {
mode: string;
- children: string[];
+ children: string;
}
const Message = (props: Props) => {
diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts
index 37ed715..b6be483 100644
--- a/src/console/reducers/index.ts
+++ b/src/console/reducers/index.ts
@@ -1,6 +1,6 @@
import * as actions from '../actions';
-interface State {
+export interface State {
mode: string;
messageText: string;
consoleText: string;
diff --git a/src/content/Mark.ts b/src/content/Mark.ts
new file mode 100644
index 0000000..f1282fc
--- /dev/null
+++ b/src/content/Mark.ts
@@ -0,0 +1,6 @@
+export default interface Mark {
+ x: number;
+ y: number;
+ // eslint-disable-next-line semi
+}
+
diff --git a/src/content/actions/find.ts b/src/content/actions/find.ts
index 6dd2ae6..53e03ae 100644
--- a/src/content/actions/find.ts
+++ b/src/content/actions/find.ts
@@ -9,6 +9,20 @@ import * as messages from '../../shared/messages';
import * as actions from './index';
import * as consoleFrames from '../console-frames';
+interface MyWindow extends Window {
+ find(
+ aString: string,
+ aCaseSensitive?: boolean,
+ aBackwards?: boolean,
+ aWrapAround?: boolean,
+ aWholeWord?: boolean,
+ aSearchInFrames?: boolean,
+ aShowDialog?: boolean): boolean;
+}
+
+// eslint-disable-next-line no-var, vars-on-top, init-declarations
+declare var window: MyWindow;
+
const find = (str: string, backwards: boolean): boolean => {
let caseSensitive = false;
let wrapScan = true;
@@ -18,7 +32,7 @@ const find = (str: string, backwards: boolean): boolean => {
// because of same origin policy
// eslint-disable-next-line no-extra-parens
- let found = (window).find(str, caseSensitive, backwards, wrapScan);
+ let found = window.find(str, caseSensitive, backwards, wrapScan);
if (found) {
return found;
}
@@ -28,7 +42,7 @@ const find = (str: string, backwards: boolean): boolean => {
}
// eslint-disable-next-line no-extra-parens
- return (window).find(str, caseSensitive, backwards, wrapScan);
+ return window.find(str, caseSensitive, backwards, wrapScan);
};
// eslint-disable-next-line max-statements
diff --git a/src/content/actions/index.ts b/src/content/actions/index.ts
index a259211..8aa9c23 100644
--- a/src/content/actions/index.ts
+++ b/src/content/actions/index.ts
@@ -1,5 +1,6 @@
import Redux from 'redux';
import Settings from '../../shared/Settings';
+import * as keyUtils from '../../shared/utils/keys';
// Enable/disable
export const ADDON_SET_ENABLED = 'addon.set.enabled';
@@ -51,7 +52,7 @@ export interface SettingSetAction extends Redux.Action {
export interface InputKeyPressAction extends Redux.Action {
type: typeof INPUT_KEY_PRESS;
- key: string;
+ key: keyUtils.Key;
}
export interface InputClearKeysAction extends Redux.Action {
diff --git a/src/content/actions/input.ts b/src/content/actions/input.ts
index 21c912e..1df6452 100644
--- a/src/content/actions/input.ts
+++ b/src/content/actions/input.ts
@@ -1,6 +1,7 @@
import * as actions from './index';
+import * as keyUtils from '../../shared/utils/keys';
-const keyPress = (key: string): actions.InputAction => {
+const keyPress = (key: keyUtils.Key): actions.InputAction => {
return {
type: actions.INPUT_KEY_PRESS,
key,
diff --git a/src/content/components/common/index.ts b/src/content/components/common/index.ts
index 8bd697f..5b097b6 100644
--- a/src/content/components/common/index.ts
+++ b/src/content/components/common/index.ts
@@ -18,7 +18,7 @@ export default class Common {
constructor(win: Window, store: any) {
const input = new InputComponent(win.document.body);
const follow = new FollowComponent(win);
- const mark = new MarkComponent(win.document.body, store);
+ const mark = new MarkComponent(store);
const keymapper = new KeymapperComponent(store);
input.onKey((key: keys.Key) => follow.key(key));
diff --git a/src/content/components/common/mark.ts b/src/content/components/common/mark.ts
index 686116c..1237385 100644
--- a/src/content/components/common/mark.ts
+++ b/src/content/components/common/mark.ts
@@ -1,27 +1,30 @@
import * as markActions from '../../actions/mark';
import * as scrolls from '../..//scrolls';
import * as consoleFrames from '../..//console-frames';
+import * as keyUtils from '../../../shared/utils/keys';
+import Mark from '../../Mark';
-const cancelKey = (key): boolean => {
- return key.key === 'Esc' || key.key === '[' && key.ctrlKey;
+const cancelKey = (key: keyUtils.Key): boolean => {
+ return key.key === 'Esc' || key.key === '[' && Boolean(key.ctrlKey);
};
-const globalKey = (key) => {
+const globalKey = (key: string): boolean => {
return (/^[A-Z0-9]$/).test(key);
};
export default class MarkComponent {
- constructor(body, store) {
- this.body = body;
+ private store: any;
+
+ constructor(store: any) {
this.store = store;
}
// eslint-disable-next-line max-statements
- key(key) {
- let { mark: markStage, setting } = this.store.getState();
+ key(key: keyUtils.Key) {
+ let { mark: markState, setting } = this.store.getState();
let smoothscroll = setting.properties.smoothscroll;
- if (!markStage.setMode && !markStage.jumpMode) {
+ if (!markState.setMode && !markState.jumpMode) {
return false;
}
@@ -32,26 +35,30 @@ export default class MarkComponent {
if (key.ctrlKey || key.metaKey || key.altKey) {
consoleFrames.postError('Unknown mark');
- } else if (globalKey(key.key) && markStage.setMode) {
+ } else if (globalKey(key.key) && markState.setMode) {
this.doSetGlobal(key);
- } else if (globalKey(key.key) && markStage.jumpMode) {
+ } else if (globalKey(key.key) && markState.jumpMode) {
this.doJumpGlobal(key);
- } else if (markStage.setMode) {
+ } else if (markState.setMode) {
this.doSet(key);
- } else if (markStage.jumpMode) {
- this.doJump(markStage.marks, key, smoothscroll);
+ } else if (markState.jumpMode) {
+ this.doJump(markState.marks, key, smoothscroll);
}
this.store.dispatch(markActions.cancel());
return true;
}
- doSet(key) {
+ doSet(key: keyUtils.Key) {
let { x, y } = scrolls.getScroll();
this.store.dispatch(markActions.setLocal(key.key, x, y));
}
- doJump(marks, key, smoothscroll) {
+ doJump(
+ marks: { [key: string]: Mark },
+ key: keyUtils.Key,
+ smoothscroll: boolean,
+ ) {
if (!marks[key.key]) {
consoleFrames.postError('Mark is not set');
return;
@@ -61,12 +68,12 @@ export default class MarkComponent {
scrolls.scrollTo(x, y, smoothscroll);
}
- doSetGlobal(key) {
+ doSetGlobal(key: keyUtils.Key) {
let { x, y } = scrolls.getScroll();
this.store.dispatch(markActions.setGlobal(key.key, x, y));
}
- doJumpGlobal(key) {
+ doJumpGlobal(key: keyUtils.Key) {
this.store.dispatch(markActions.jumpGlobal(key.key));
}
}
diff --git a/src/content/index.ts b/src/content/index.ts
index 309f27f..9d791fc 100644
--- a/src/content/index.ts
+++ b/src/content/index.ts
@@ -12,5 +12,5 @@ if (window.self === window.top) {
}
let style = window.document.createElement('style');
-style.textContent = consoleFrameStyle.default;
+style.textContent = consoleFrameStyle;
window.document.head.appendChild(style);
diff --git a/src/content/reducers/input.ts b/src/content/reducers/input.ts
index 6257e49..35b9075 100644
--- a/src/content/reducers/input.ts
+++ b/src/content/reducers/input.ts
@@ -1,7 +1,8 @@
import * as actions from '../actions';
+import * as keyUtils from '../../shared/utils/keys';
export interface State {
- keys: string[];
+ keys: keyUtils.Key[],
}
const defaultState: State = {
diff --git a/src/content/reducers/mark.ts b/src/content/reducers/mark.ts
index e78b7b9..7409938 100644
--- a/src/content/reducers/mark.ts
+++ b/src/content/reducers/mark.ts
@@ -1,10 +1,6 @@
+import Mark from '../Mark';
import * as actions from '../actions';
-interface Mark {
- x: number;
- y: number;
-}
-
export interface State {
setMode: boolean;
jumpMode: boolean;
diff --git a/src/content/site-style.ts b/src/content/site-style.ts
index e7a82a5..0c335fc 100644
--- a/src/content/site-style.ts
+++ b/src/content/site-style.ts
@@ -1,4 +1,4 @@
-exports.default = `
+export default `
.vimvixen-console-frame {
margin: 0;
padding: 0;
diff --git a/test/content/reducers/setting.test.ts b/test/content/reducers/setting.test.ts
index fe23006..9b332aa 100644
--- a/test/content/reducers/setting.test.ts
+++ b/test/content/reducers/setting.test.ts
@@ -20,7 +20,6 @@ describe("content setting reducer", () => {
}
}
let state = settingReducer(undefined, action);
- console.log(JSON.stringify(state.keymaps));
expect(state.keymaps).to.have.deep.all.members([
{ key: [{ key: 'z', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
{ key: 'z', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }],
--
cgit v1.2.3