aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorLibravatar vantezzen <hello@vantezzen.io>2019-10-02 13:57:24 +0200
committerLibravatar vantezzen <hello@vantezzen.io>2019-10-02 13:57:24 +0200
commit53c16e91b58d0abe3cde88acd05fddbdfc3c683c (patch)
tree6b3394aabdedc070f6b9e179457627b435b69ad9 /src/features
parentFix Ferdi Lock not corrently locking (diff)
parentfix(Spell check): Fix spell checker to initialize without loaded dictionary (diff)
downloadferdium-app-53c16e91b58d0abe3cde88acd05fddbdfc3c683c.tar.gz
ferdium-app-53c16e91b58d0abe3cde88acd05fddbdfc3c683c.tar.zst
ferdium-app-53c16e91b58d0abe3cde88acd05fddbdfc3c683c.zip
Merge branch 'release/5.4.0' of https://github.com/meetfranz/franz into franz-5.4.0
Diffstat (limited to 'src/features')
-rw-r--r--src/features/todos/components/TodosWebview.js3
-rw-r--r--src/features/todos/store.js4
-rw-r--r--src/features/webControls/components/WebControls.js190
-rw-r--r--src/features/webControls/containers/WebControlsScreen.js128
4 files changed, 322 insertions, 3 deletions
diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.js
index c252aff90..35c102220 100644
--- a/src/features/todos/components/TodosWebview.js
+++ b/src/features/todos/components/TodosWebview.js
@@ -37,9 +37,6 @@ const styles = theme => ({
37 37
38 transform: ({ isVisible, width }) => `translateX(${isVisible ? 0 : width}px)`, 38 transform: ({ isVisible, width }) => `translateX(${isVisible ? 0 : width}px)`,
39 39
40 '&:hover $closeTodosButton': {
41 opacity: 1,
42 },
43 '& webview': { 40 '& webview': {
44 height: '100%', 41 height: '100%',
45 }, 42 },
diff --git a/src/features/todos/store.js b/src/features/todos/store.js
index d507237d1..a05203a04 100644
--- a/src/features/todos/store.js
+++ b/src/features/todos/store.js
@@ -162,6 +162,10 @@ export default class TodoStore extends FeatureStore {
162 theme: isDarkThemeActive ? ThemeType.dark : ThemeType.default, 162 theme: isDarkThemeActive ? ThemeType.dark : ThemeType.default,
163 }, 163 },
164 }); 164 });
165
166 this.webview.addEventListener('new-window', ({ url }) => {
167 this.actions.app.openExternalUrl({ url });
168 });
165 }; 169 };
166 170
167 _goToService = ({ url, serviceId }) => { 171 _goToService = ({ url, serviceId }) => {
diff --git a/src/features/webControls/components/WebControls.js b/src/features/webControls/components/WebControls.js
new file mode 100644
index 000000000..03f601a17
--- /dev/null
+++ b/src/features/webControls/components/WebControls.js
@@ -0,0 +1,190 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss';
5import { Icon } from '@meetfranz/ui';
6
7import {
8 mdiReload, mdiArrowRight, mdiArrowLeft, mdiHomeOutline,
9} from '@mdi/js';
10
11const styles = theme => ({
12 root: {
13 background: theme.colorBackground,
14 position: 'relative',
15 borderLeft: [1, 'solid', theme.todos.todosLayer.borderLeftColor],
16 zIndex: 300,
17 height: 50,
18 display: 'flex',
19 flexDirection: 'row',
20 alignItems: 'center',
21 padding: [0, 20],
22
23 '& + div': {
24 height: 'calc(100% - 50px)',
25 },
26 },
27 button: {
28 width: 30,
29 height: 50,
30 transition: 'opacity 0.25s',
31
32 '&:hover': {
33 opacity: 0.8,
34 },
35
36 '&:disabled': {
37 opacity: 0.5,
38 },
39 },
40 icon: {
41 width: '20px !important',
42 height: 20,
43 marginTop: 5,
44 },
45 input: {
46 marginBottom: 0,
47 height: 'auto',
48 marginLeft: 10,
49 flex: 1,
50 border: 0,
51 padding: [4, 10],
52 borderRadius: theme.borderRadius,
53 background: theme.inputBackground,
54 color: theme.inputColor,
55 },
56 inputButton: {
57 color: theme.colorText,
58 },
59});
60
61@injectSheet(styles) @observer
62class WebControls extends Component {
63 static propTypes = {
64 classes: PropTypes.object.isRequired,
65 goHome: PropTypes.func.isRequired,
66 canGoBack: PropTypes.bool.isRequired,
67 goBack: PropTypes.func.isRequired,
68 canGoForward: PropTypes.bool.isRequired,
69 goForward: PropTypes.func.isRequired,
70 reload: PropTypes.func.isRequired,
71 url: PropTypes.string.isRequired,
72 navigate: PropTypes.func.isRequired,
73 }
74
75 static getDerivedStateFromProps(props, state) {
76 const { url } = props;
77 const { editUrl } = state;
78
79 if (!editUrl) {
80 return {
81 inputUrl: url,
82 editUrl: state.editUrl,
83 };
84 }
85 }
86
87 inputRef = React.createRef();
88
89 state = {
90 inputUrl: '',
91 editUrl: false,
92 }
93
94 render() {
95 const {
96 classes,
97 goHome,
98 canGoBack,
99 goBack,
100 canGoForward,
101 goForward,
102 reload,
103 url,
104 navigate,
105 } = this.props;
106
107 const {
108 inputUrl,
109 editUrl,
110 } = this.state;
111
112 return (
113 <div className={classes.root}>
114 <button
115 onClick={goHome}
116 type="button"
117 className={classes.button}
118 >
119 <Icon
120 icon={mdiHomeOutline}
121 className={classes.icon}
122 />
123 </button>
124 <button
125 onClick={goBack}
126 type="button"
127 className={classes.button}
128 disabled={!canGoBack}
129 >
130 <Icon
131 icon={mdiArrowLeft}
132 className={classes.icon}
133 />
134 </button>
135 <button
136 onClick={goForward}
137 type="button"
138 className={classes.button}
139 disabled={!canGoForward}
140 >
141 <Icon
142 icon={mdiArrowRight}
143 className={classes.icon}
144 />
145 </button>
146 <button
147 onClick={reload}
148 type="button"
149 className={classes.button}
150 >
151 <Icon
152 icon={mdiReload}
153 className={classes.icon}
154 />
155 </button>
156 <input
157 value={editUrl ? inputUrl : url}
158 className={classes.input}
159 onChange={event => this.setState({
160 inputUrl: event.target.value,
161 })}
162 onFocus={(event) => {
163 event.target.select();
164 this.setState({
165 editUrl: true,
166 });
167 }}
168 onKeyDown={(event) => {
169 if (event.key === 'Enter') {
170 this.setState({
171 editUrl: false,
172 });
173 navigate(inputUrl);
174 this.inputRef.current.blur();
175 } else if (event.key === 'Escape') {
176 this.setState({
177 editUrl: false,
178 inputUrl: url,
179 });
180 event.target.blur();
181 }
182 }}
183 ref={this.inputRef}
184 />
185 </div>
186 );
187 }
188}
189
190export default WebControls;
diff --git a/src/features/webControls/containers/WebControlsScreen.js b/src/features/webControls/containers/WebControlsScreen.js
new file mode 100644
index 000000000..1452d5a3d
--- /dev/null
+++ b/src/features/webControls/containers/WebControlsScreen.js
@@ -0,0 +1,128 @@
1import React, { Component } from 'react';
2import { observer, inject } from 'mobx-react';
3import PropTypes from 'prop-types';
4
5import { autorun, observable } from 'mobx';
6import WebControls from '../components/WebControls';
7import ServicesStore from '../../../stores/ServicesStore';
8import Service from '../../../models/Service';
9
10const URL_EVENTS = [
11 'load-commit',
12 // 'dom-ready',
13 'will-navigate',
14 'did-navigate',
15 'did-navigate-in-page',
16];
17
18@inject('stores', 'actions') @observer
19class WebControlsScreen extends Component {
20 @observable url = '';
21
22 @observable canGoBack = false;
23
24 @observable canGoForward = false;
25
26 webview = null;
27
28 autorunDisposer = null;
29
30 componentDidMount() {
31 const { service } = this.props;
32
33 this.autorunDisposer = autorun(() => {
34 if (service.isAttached) {
35 this.webview = service.webview;
36
37 URL_EVENTS.forEach((event) => {
38 this.webview.addEventListener(event, (e) => {
39 if (!e.isMainFrame) return;
40
41 this.url = e.url;
42 this.canGoBack = this.webview.canGoBack();
43 this.canGoForward = this.webview.canGoForward();
44 });
45 });
46 }
47 });
48 }
49
50 componentWillUnmount() {
51 this.autorunDisposer();
52 }
53
54 goHome() {
55 const { reloadActive } = this.props.actions.service;
56
57 if (!this.webview) return;
58
59 reloadActive();
60 }
61
62 reload() {
63 if (!this.webview) return;
64
65 this.webview.reload();
66 }
67
68 goBack() {
69 if (!this.webview) return;
70
71 this.webview.goBack();
72 }
73
74 goForward() {
75 if (!this.webview) return;
76
77 this.webview.goForward();
78 }
79
80 navigate(newUrl) {
81 if (!this.webview) return;
82
83 let url = newUrl;
84
85 try {
86 url = new URL(url).toString();
87 } catch (err) {
88 // eslint-disable-next-line no-useless-escape
89 if (url.match(/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9\-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$/)) {
90 url = `http://${url}`;
91 } else {
92 url = `https://www.google.com/search?query=${url}`;
93 }
94 }
95
96 this.webview.loadURL(url);
97 this.url = url;
98 }
99
100 render() {
101 return (
102 <WebControls
103 goHome={() => this.goHome()}
104 reload={() => this.reload()}
105 canGoBack={this.canGoBack}
106 goBack={() => this.goBack()}
107 canGoForward={this.canGoForward}
108 goForward={() => this.goForward()}
109 navigate={url => this.navigate(url)}
110 url={this.url}
111 />
112 );
113 }
114}
115
116export default WebControlsScreen;
117
118WebControlsScreen.wrappedComponent.propTypes = {
119 service: PropTypes.instanceOf(Service).isRequired,
120 stores: PropTypes.shape({
121 services: PropTypes.instanceOf(ServicesStore).isRequired,
122 }).isRequired,
123 actions: PropTypes.shape({
124 service: PropTypes.shape({
125 reloadActive: PropTypes.func.isRequired,
126 }).isRequired,
127 }).isRequired,
128};