Skip to content
Permalink
Browse files

feat(Custom Websites): Add simple browser controls

  • Loading branch information...
adlk committed Oct 1, 2019
1 parent 9f4f3e7 commit f8fbaad43522b91374eaed5e3df6fe47bc94862f
@@ -12,6 +12,7 @@ import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler';
import ServiceDisabled from './ServiceDisabled';
import ServiceRestricted from './ServiceRestricted';
import ServiceWebview from './ServiceWebview';
import WebControlsScreen from '../../../features/webControls/containers/WebControlsScreen';

export default @observer class ServiceView extends Component {
static propTypes = {
@@ -137,11 +138,16 @@ export default @observer class ServiceView extends Component {
type={service.restrictionType}
/>
) : (
<ServiceWebview
service={service}
setWebviewReference={setWebviewReference}
detachService={detachService}
/>
<>
{service.recipe.id === 'franz-custom-website' && (
<WebControlsScreen service={service} />
)}
<ServiceWebview
service={service}
setWebviewReference={setWebviewReference}
detachService={detachService}
/>
</>
)}
</>
)}
@@ -0,0 +1,190 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { observer } from 'mobx-react';
import injectSheet from 'react-jss';
import { Icon } from '@meetfranz/ui';

import {
mdiReload, mdiArrowRight, mdiArrowLeft, mdiHomeOutline,
} from '@mdi/js';

const styles = theme => ({
root: {
background: theme.colorBackground,
position: 'relative',
borderLeft: [1, 'solid', theme.todos.todosLayer.borderLeftColor],
zIndex: 300,
height: 50,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
padding: [0, 20],

'& + div': {
height: 'calc(100% - 50px)',
},
},
button: {
width: 30,
height: 50,
transition: 'opacity 0.25s',

'&:hover': {
opacity: 0.8,
},

'&:disabled': {
opacity: 0.5,
},
},
icon: {
width: '20px !important',
height: 20,
marginTop: 5,
},
input: {
marginBottom: 0,
height: 'auto',
marginLeft: 10,
flex: 1,
border: 0,
padding: [4, 10],
borderRadius: theme.borderRadius,
background: theme.inputBackground,
color: theme.inputColor,
},
inputButton: {
color: theme.colorText,
},
});

@injectSheet(styles) @observer
class WebControls extends Component {
static propTypes = {
classes: PropTypes.object.isRequired,
goHome: PropTypes.func.isRequired,
canGoBack: PropTypes.bool.isRequired,
goBack: PropTypes.func.isRequired,
canGoForward: PropTypes.bool.isRequired,
goForward: PropTypes.func.isRequired,
reload: PropTypes.func.isRequired,
url: PropTypes.string.isRequired,
navigate: PropTypes.func.isRequired,
}

static getDerivedStateFromProps(props, state) {
const { url } = props;
const { editUrl } = state;

if (!editUrl) {
return {
inputUrl: url,
editUrl: state.editUrl,
};
}
}

inputRef = React.createRef();

state = {
inputUrl: '',
editUrl: false,
}

render() {
const {
classes,
goHome,
canGoBack,
goBack,
canGoForward,
goForward,
reload,
url,
navigate,
} = this.props;

const {
inputUrl,
editUrl,
} = this.state;

return (
<div className={classes.root}>
<button
onClick={goHome}
type="button"
className={classes.button}
>
<Icon
icon={mdiHomeOutline}
className={classes.icon}
/>
</button>
<button
onClick={goBack}
type="button"
className={classes.button}
disabled={!canGoBack}
>
<Icon
icon={mdiArrowLeft}
className={classes.icon}
/>
</button>
<button
onClick={goForward}
type="button"
className={classes.button}
disabled={!canGoForward}
>
<Icon
icon={mdiArrowRight}
className={classes.icon}
/>
</button>
<button
onClick={reload}
type="button"
className={classes.button}
>
<Icon
icon={mdiReload}
className={classes.icon}
/>
</button>
<input
value={editUrl ? inputUrl : url}
className={classes.input}
onChange={event => this.setState({
inputUrl: event.target.value,
})}
onFocus={(event) => {
event.target.select();
this.setState({
editUrl: true,
});
}}
onKeyDown={(event) => {
if (event.key === 'Enter') {
this.setState({
editUrl: false,
});
navigate(inputUrl);
this.inputRef.current.blur();
} else if (event.key === 'Escape') {
this.setState({
editUrl: false,
inputUrl: url,
});
event.target.blur();
}
}}
ref={this.inputRef}
/>
</div>
);
}
}

export default WebControls;
@@ -0,0 +1,128 @@
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
import PropTypes from 'prop-types';

import { autorun, observable } from 'mobx';
import WebControls from '../components/WebControls';
import ServicesStore from '../../../stores/ServicesStore';
import Service from '../../../models/Service';

const URL_EVENTS = [
'load-commit',
// 'dom-ready',
'will-navigate',
'did-navigate',
'did-navigate-in-page',
];

@inject('stores', 'actions') @observer
class WebControlsScreen extends Component {
@observable url = '';

@observable canGoBack = false;

@observable canGoForward = false;

webview = null;

autorunDisposer = null;

componentDidMount() {
const { service } = this.props;

this.autorunDisposer = autorun(() => {
if (service.isAttached) {
this.webview = service.webview;

URL_EVENTS.forEach((event) => {
this.webview.addEventListener(event, (e) => {
if (!e.isMainFrame) return;

this.url = e.url;
this.canGoBack = this.webview.canGoBack();
this.canGoForward = this.webview.canGoForward();
});
});
}
});
}

componentWillUnmount() {
this.autorunDisposer();
}

goHome() {
const { reloadActive } = this.props.actions.service;

if (!this.webview) return;

reloadActive();
}

reload() {
if (!this.webview) return;

this.webview.reload();
}

goBack() {
if (!this.webview) return;

this.webview.goBack();
}

goForward() {
if (!this.webview) return;

this.webview.goForward();
}

navigate(newUrl) {
if (!this.webview) return;

let url = newUrl;

try {
url = new URL(url).toString();
} catch (err) {
// eslint-disable-next-line no-useless-escape
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,})$/)) {
url = `http://${url}`;
} else {
url = `https://www.google.com/search?query=${url}`;
}
}

this.webview.loadURL(url);
this.url = url;
}

render() {
return (
<WebControls
goHome={() => this.goHome()}
reload={() => this.reload()}
canGoBack={this.canGoBack}
goBack={() => this.goBack()}
canGoForward={this.canGoForward}
goForward={() => this.goForward()}
navigate={url => this.navigate(url)}
url={this.url}
/>
);
}
}

export default WebControlsScreen;

WebControlsScreen.wrappedComponent.propTypes = {
service: PropTypes.instanceOf(Service).isRequired,
stores: PropTypes.shape({
services: PropTypes.instanceOf(ServicesStore).isRequired,
}).isRequired,
actions: PropTypes.shape({
service: PropTypes.shape({
reloadActive: PropTypes.func.isRequired,
}).isRequired,
}).isRequired,
};

0 comments on commit f8fbaad

Please sign in to comment.
You can’t perform that action at this time.