From 86410c4bc7b3dad824586a7116713318287a6d0e Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Fri, 27 Sep 2019 21:11:24 +0200 Subject: add disablewebsecurity option --- src/components/services/content/ServiceWebview.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/components/services/content') diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index 7252c695f..07bd17d9c 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js @@ -41,6 +41,7 @@ class ServiceWebview extends Component { }} onUpdateTargetUrl={this.updateTargetUrl} useragent={service.userAgent} + disablewebsecurity={service.recipe.disablewebsecurity} allowpopups /> ); -- cgit v1.2.3-70-g09d2 From f8fbaad43522b91374eaed5e3df6fe47bc94862f Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Tue, 1 Oct 2019 21:51:34 +0200 Subject: feat(Custom Websites): Add simple browser controls --- src/components/services/content/ServiceView.js | 16 +- src/features/webControls/components/WebControls.js | 190 +++++++++++++++++++++ .../webControls/containers/WebControlsScreen.js | 128 ++++++++++++++ 3 files changed, 329 insertions(+), 5 deletions(-) create mode 100644 src/features/webControls/components/WebControls.js create mode 100644 src/features/webControls/containers/WebControlsScreen.js (limited to 'src/components/services/content') diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index f65f51346..e8df58a1e 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js @@ -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} /> ) : ( - + <> + {service.recipe.id === 'franz-custom-website' && ( + + )} + + )} )} 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 @@ +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 ( +
+ + + + + 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} + /> +
+ ); + } +} + +export 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 @@ +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 ( + 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, +}; -- cgit v1.2.3-70-g09d2