diff options
author | muhamedsalih-tw <104364298+muhamedsalih-tw@users.noreply.github.com> | 2022-10-31 15:30:24 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-31 10:00:24 +0000 |
commit | 25d54a5c5de02a2bbbbbf3b222be9f0630570a6b (patch) | |
tree | cd34ab7cc3444735ce7527b9c15ddf0aef0ff63a /src/features/webControls | |
parent | 6.2.1-nightly.34 [skip ci] (diff) | |
download | ferdium-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/webControls')
-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 @@ | |||
1 | import { createRef, Component } from 'react'; | 1 | import { createRef, Component, ReactElement, RefObject } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | 2 | import { observer } from 'mobx-react'; |
4 | import injectSheet from 'react-jss'; | 3 | import withStyles, { WithStylesProps } from 'react-jss'; |
5 | import { defineMessages, injectIntl } from 'react-intl'; | 4 | import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl'; |
6 | |||
7 | import { | 5 | import { |
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 | |||
15 | import Icon from '../../../components/ui/icon'; | 12 | import Icon from '../../../components/ui/icon'; |
16 | 13 | ||
17 | const messages = defineMessages({ | 14 | const messages = defineMessages({ |
@@ -37,11 +34,10 @@ const messages = defineMessages({ | |||
37 | }, | 34 | }, |
38 | }); | 35 | }); |
39 | 36 | ||
40 | let buttonTransition = 'none'; | 37 | const buttonTransition = |
41 | 38 | window && window.matchMedia('(prefers-reduced-motion: no-preference)') | |
42 | if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) { | 39 | ? 'opacity 0.25s' |
43 | buttonTransition = 'opacity 0.25s'; | 40 | : 'none'; |
44 | } | ||
45 | 41 | ||
46 | const styles = theme => ({ | 42 | const styles = theme => ({ |
47 | root: { | 43 | root: { |
@@ -94,40 +90,44 @@ const styles = theme => ({ | |||
94 | }, | 90 | }, |
95 | }); | 91 | }); |
96 | 92 | ||
97 | class WebControls extends Component { | 93 | interface 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 | }; | 105 | interface IState { |
110 | 106 | inputUrl: string; | |
111 | static getDerivedStateFromProps(props, state) { | 107 | editUrl: boolean; |
112 | const { url } = props; | 108 | } |
109 | |||
110 | @observer | ||
111 | class 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 | ||
239 | export default injectIntl( | 240 | export 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 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { observer, inject } from 'mobx-react'; | 2 | import { observer, inject } from 'mobx-react'; |
3 | import PropTypes from 'prop-types'; | 3 | import { |
4 | 4 | autorun, | |
5 | import { autorun, action, makeObservable, observable } from 'mobx'; | 5 | action, |
6 | makeObservable, | ||
7 | observable, | ||
8 | IReactionDisposer, | ||
9 | } from 'mobx'; | ||
10 | import ElectronWebView from 'react-electron-web-view'; | ||
6 | import WebControls from '../components/WebControls'; | 11 | import WebControls from '../components/WebControls'; |
7 | import ServicesStore from '../../../stores/ServicesStore'; | ||
8 | import Service from '../../../models/Service'; | 12 | import Service from '../../../models/Service'; |
9 | import { SEARCH_ENGINE_URLS } from '../../../config'; | 13 | import { SEARCH_ENGINE_URLS } from '../../../config'; |
10 | import AppStore from '../../../stores/AppStore'; | 14 | import { StoresProps } from '../../../@types/ferdium-components.types'; |
11 | 15 | ||
12 | const URL_EVENTS = [ | 16 | const 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 | ||
19 | class WebControlsScreen extends Component { | 23 | interface IProps extends Partial<StoresProps> { |
24 | service: Service; | ||
25 | } | ||
26 | |||
27 | @inject('stores', 'actions') | ||
28 | @observer | ||
29 | class 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 | ||
140 | export default inject('stores', 'actions')(observer(WebControlsScreen)); | 163 | export default WebControlsScreen; |
141 | |||
142 | WebControlsScreen.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 | }; | ||