aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorLibravatar muhamedsalih-tw <104364298+muhamedsalih-tw@users.noreply.github.com>2022-10-31 15:30:24 +0530
committerLibravatar GitHub <noreply@github.com>2022-10-31 10:00:24 +0000
commit25d54a5c5de02a2bbbbbf3b222be9f0630570a6b (patch)
treecd34ab7cc3444735ce7527b9c15ddf0aef0ff63a /src/features
parent6.2.1-nightly.34 [skip ci] (diff)
downloadferdium-app-25d54a5c5de02a2bbbbbf3b222be9f0630570a6b.tar.gz
ferdium-app-25d54a5c5de02a2bbbbbf3b222be9f0630570a6b.tar.zst
ferdium-app-25d54a5c5de02a2bbbbbf3b222be9f0630570a6b.zip
Convert web controls & screen to typescript (#722)
Diffstat (limited to 'src/features')
-rw-r--r--src/features/webControls/components/WebControls.tsx (renamed from src/features/webControls/components/WebControls.js)87
-rw-r--r--src/features/webControls/containers/WebControlsScreen.tsx (renamed from src/features/webControls/containers/WebControlsScreen.jsx)124
2 files changed, 112 insertions, 99 deletions
diff --git a/src/features/webControls/components/WebControls.js b/src/features/webControls/components/WebControls.tsx
index 570f2f2dc..ebcd93c9e 100644
--- a/src/features/webControls/components/WebControls.js
+++ b/src/features/webControls/components/WebControls.tsx
@@ -1,9 +1,7 @@
1import { createRef, Component } from 'react'; 1import { createRef, Component, ReactElement, RefObject } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 3import withStyles, { WithStylesProps } from 'react-jss';
5import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
6
7import { 5import {
8 mdiReload, 6 mdiReload,
9 mdiArrowRight, 7 mdiArrowRight,
@@ -11,7 +9,6 @@ import {
11 mdiHomeOutline, 9 mdiHomeOutline,
12 mdiEarth, 10 mdiEarth,
13} from '@mdi/js'; 11} from '@mdi/js';
14
15import Icon from '../../../components/ui/icon'; 12import Icon from '../../../components/ui/icon';
16 13
17const messages = defineMessages({ 14const messages = defineMessages({
@@ -37,11 +34,10 @@ const messages = defineMessages({
37 }, 34 },
38}); 35});
39 36
40let buttonTransition = 'none'; 37const buttonTransition =
41 38 window && window.matchMedia('(prefers-reduced-motion: no-preference)')
42if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) { 39 ? 'opacity 0.25s'
43 buttonTransition = 'opacity 0.25s'; 40 : 'none';
44}
45 41
46const styles = theme => ({ 42const styles = theme => ({
47 root: { 43 root: {
@@ -94,40 +90,44 @@ const styles = theme => ({
94 }, 90 },
95}); 91});
96 92
97class WebControls extends Component { 93interface IProps extends WithStylesProps<typeof styles>, WrappedComponentProps {
98 static propTypes = { 94 goHome: () => void;
99 classes: PropTypes.object.isRequired, 95 canGoBack: boolean;
100 goHome: PropTypes.func.isRequired, 96 goBack: () => void;
101 canGoBack: PropTypes.bool.isRequired, 97 canGoForward: boolean;
102 goBack: PropTypes.func.isRequired, 98 goForward: () => void;
103 canGoForward: PropTypes.bool.isRequired, 99 reload: () => void;
104 goForward: PropTypes.func.isRequired, 100 openInBrowser: () => void;
105 reload: PropTypes.func.isRequired, 101 url: string;
106 openInBrowser: PropTypes.func.isRequired, 102 navigate: (url: string) => void;
107 url: PropTypes.string.isRequired, 103}
108 navigate: PropTypes.func.isRequired, 104
109 }; 105interface IState {
110 106 inputUrl: string;
111 static getDerivedStateFromProps(props, state) { 107 editUrl: boolean;
112 const { url } = props; 108}
109
110@observer
111class WebControls extends Component<IProps, IState> {
112 inputRef: RefObject<HTMLInputElement> = createRef();
113
114 static getDerivedStateFromProps(props, state): IState | null {
115 const { url: inputUrl } = props;
113 const { editUrl } = state; 116 const { editUrl } = state;
114 117
115 if (!editUrl) { 118 return !editUrl ? { inputUrl, editUrl } : null;
116 return {
117 inputUrl: url,
118 editUrl: state.editUrl,
119 };
120 }
121 } 119 }
122 120
123 inputRef = createRef(); 121 constructor(props: IProps) {
122 super(props);
124 123
125 state = { 124 this.state = {
126 inputUrl: '', 125 inputUrl: '',
127 editUrl: false, 126 editUrl: false,
128 }; 127 };
128 }
129 129
130 render() { 130 render(): ReactElement {
131 const { 131 const {
132 classes, 132 classes,
133 goHome, 133 goHome,
@@ -139,12 +139,11 @@ class WebControls extends Component {
139 openInBrowser, 139 openInBrowser,
140 url, 140 url,
141 navigate, 141 navigate,
142 intl,
142 } = this.props; 143 } = this.props;
143 144
144 const { inputUrl, editUrl } = this.state; 145 const { inputUrl, editUrl } = this.state;
145 146
146 const { intl } = this.props;
147
148 return ( 147 return (
149 <div className={classes.root}> 148 <div className={classes.root}>
150 <button 149 <button
@@ -211,12 +210,14 @@ class WebControls extends Component {
211 editUrl: false, 210 editUrl: false,
212 }); 211 });
213 navigate(inputUrl); 212 navigate(inputUrl);
214 this.inputRef.current.blur();
215 } else if (event.key === 'Escape') { 213 } else if (event.key === 'Escape') {
216 this.setState({ 214 this.setState({
217 editUrl: false, 215 editUrl: false,
218 inputUrl: url, 216 inputUrl: url,
219 }); 217 });
218 }
219
220 if (this.inputRef && this.inputRef.current) {
220 this.inputRef.current.blur(); 221 this.inputRef.current.blur();
221 } 222 }
222 }} 223 }}
@@ -237,5 +238,5 @@ class WebControls extends Component {
237} 238}
238 239
239export default injectIntl( 240export default injectIntl(
240 injectSheet(styles, { injectTheme: true })(observer(WebControls)), 241 withStyles(styles, { injectTheme: true })(WebControls),
241); 242);
diff --git a/src/features/webControls/containers/WebControlsScreen.jsx b/src/features/webControls/containers/WebControlsScreen.tsx
index 25e14060d..f6f1cddb8 100644
--- a/src/features/webControls/containers/WebControlsScreen.jsx
+++ b/src/features/webControls/containers/WebControlsScreen.tsx
@@ -1,13 +1,17 @@
1import { Component } from 'react'; 1import { Component, ReactElement } from 'react';
2import { observer, inject } from 'mobx-react'; 2import { observer, inject } from 'mobx-react';
3import PropTypes from 'prop-types'; 3import {
4 4 autorun,
5import { autorun, action, makeObservable, observable } from 'mobx'; 5 action,
6 makeObservable,
7 observable,
8 IReactionDisposer,
9} from 'mobx';
10import ElectronWebView from 'react-electron-web-view';
6import WebControls from '../components/WebControls'; 11import WebControls from '../components/WebControls';
7import ServicesStore from '../../../stores/ServicesStore';
8import Service from '../../../models/Service'; 12import Service from '../../../models/Service';
9import { SEARCH_ENGINE_URLS } from '../../../config'; 13import { SEARCH_ENGINE_URLS } from '../../../config';
10import AppStore from '../../../stores/AppStore'; 14import { StoresProps } from '../../../@types/ferdium-components.types';
11 15
12const URL_EVENTS = [ 16const URL_EVENTS = [
13 'load-commit', 17 'load-commit',
@@ -16,26 +20,22 @@ const URL_EVENTS = [
16 'did-navigate-in-page', 20 'did-navigate-in-page',
17]; 21];
18 22
19class WebControlsScreen extends Component { 23interface IProps extends Partial<StoresProps> {
24 service: Service;
25}
26
27@inject('stores', 'actions')
28@observer
29class WebControlsScreen extends Component<IProps> {
20 @observable url = ''; 30 @observable url = '';
21 31
22 @observable canGoBack = false; 32 @observable canGoBack = false;
23 33
24 @observable canGoForward = false; 34 @observable canGoForward = false;
25 35
26 webview = null; 36 webview: ElectronWebView | null = null;
27
28 autorunDisposer = null;
29 37
30 @action _setUrl(value) { 38 autorunDisposer: IReactionDisposer | null = null;
31 this.url = value;
32 }
33
34 @action _setUrlAndHistory(value) {
35 this._setUrl(value);
36 this.canGoBack = this.webview.canGoBack();
37 this.canGoForward = this.webview.canGoForward();
38 }
39 39
40 constructor(props) { 40 constructor(props) {
41 super(props); 41 super(props);
@@ -43,7 +43,7 @@ class WebControlsScreen extends Component {
43 makeObservable(this); 43 makeObservable(this);
44 } 44 }
45 45
46 componentDidMount() { 46 componentDidMount(): void {
47 const { service } = this.props; 47 const { service } = this.props;
48 48
49 this.autorunDisposer = autorun(() => { 49 this.autorunDisposer = autorun(() => {
@@ -53,8 +53,9 @@ class WebControlsScreen extends Component {
53 53
54 for (const event of URL_EVENTS) { 54 for (const event of URL_EVENTS) {
55 this.webview.addEventListener(event, e => { 55 this.webview.addEventListener(event, e => {
56 if (!e.isMainFrame) return; 56 if (!e.isMainFrame) {
57 57 return;
58 }
58 this._setUrlAndHistory(e.url); 59 this._setUrlAndHistory(e.url);
59 }); 60 });
60 } 61 }
@@ -62,48 +63,69 @@ class WebControlsScreen extends Component {
62 }); 63 });
63 } 64 }
64 65
65 componentWillUnmount() { 66 componentWillUnmount(): void {
66 this.autorunDisposer(); 67 if (this.autorunDisposer) {
68 this.autorunDisposer();
69 }
67 } 70 }
68 71
69 goHome() { 72 @action
70 if (!this.webview) return; 73 _setUrl(value): void {
74 this.url = value;
75 }
76
77 @action
78 _setUrlAndHistory(value): void {
79 this._setUrl(value);
80 this.canGoBack = this.webview.canGoBack();
81 this.canGoForward = this.webview.canGoForward();
82 }
83
84 goHome(): void {
85 if (!this.webview) {
86 return;
87 }
71 this.webview.goToIndex(0); 88 this.webview.goToIndex(0);
72 } 89 }
73 90
74 reload() { 91 reload(): void {
75 if (!this.webview) return; 92 if (!this.webview) {
93 return;
94 }
76 95
77 this.webview.reload(); 96 this.webview.reload();
78 } 97 }
79 98
80 goBack() { 99 goBack(): void {
81 if (!this.webview) return; 100 if (!this.webview) {
101 return;
102 }
82 103
83 this.webview.goBack(); 104 this.webview.goBack();
84 } 105 }
85 106
86 goForward() { 107 goForward(): void {
87 if (!this.webview) return; 108 if (!this.webview) {
109 return;
110 }
88 111
89 this.webview.goForward(); 112 this.webview.goForward();
90 } 113 }
91 114
92 navigate(newUrl) { 115 navigate(url: string): void {
93 if (!this.webview) return; 116 if (!this.webview) {
94 117 return;
95 let url = newUrl; 118 }
96 119
97 try { 120 try {
98 url = new URL(url).toString(); 121 url = new URL(url).toString();
99 } catch { 122 } catch {
100 url = 123 url =
101 // eslint-disable-next-line no-useless-escape 124 /^((?!-))(xn--)?[\da-z][\d_a-z-]{0,61}[\da-z]{0,1}\.(xn--)?([\da-z-]{1,61}|[\da-z-]{1,30}\.[a-z]{2,})$/.test(
102 /^((?!-))(xn--)?[\da-z][\d_a-z-]{0,61}[\da-z]{0,1}\.(xn--)?([\da-z\-]{1,61}|[\da-z-]{1,30}\.[a-z]{2,})$/.test(
103 url, 125 url,
104 ) 126 )
105 ? `http://${url}` 127 ? `http://${url}`
106 : SEARCH_ENGINE_URLS[this.settings.app.searchEngine]({ 128 : SEARCH_ENGINE_URLS[this.props.stores!.settings.app.searchEngine]({
107 searchTerm: url, 129 searchTerm: url,
108 }); 130 });
109 } 131 }
@@ -112,15 +134,16 @@ class WebControlsScreen extends Component {
112 this._setUrl(url); 134 this._setUrl(url);
113 } 135 }
114 136
115 openInBrowser() { 137 openInBrowser(): void {
116 const { openExternalUrl } = this.props.actions.app; 138 const { openExternalUrl } = this.props.actions!.app;
117 139 if (!this.webview) {
118 if (!this.webview) return; 140 return;
141 }
119 142
120 openExternalUrl({ url: this.url }); 143 openExternalUrl({ url: this.url });
121 } 144 }
122 145
123 render() { 146 render(): ReactElement {
124 return ( 147 return (
125 <WebControls 148 <WebControls
126 goHome={() => this.goHome()} 149 goHome={() => this.goHome()}
@@ -137,15 +160,4 @@ class WebControlsScreen extends Component {
137 } 160 }
138} 161}
139 162
140export default inject('stores', 'actions')(observer(WebControlsScreen)); 163export default WebControlsScreen;
141
142WebControlsScreen.propTypes = {
143 service: PropTypes.instanceOf(Service).isRequired,
144 stores: PropTypes.shape({
145 services: PropTypes.instanceOf(ServicesStore).isRequired,
146 }).isRequired,
147 actions: PropTypes.shape({
148 app: PropTypes.instanceOf(AppStore).isRequired,
149 service: PropTypes.instanceOf(ServicesStore).isRequired,
150 }).isRequired,
151};