Adding URL handling

This commit is contained in:
Jeff Avallone 2018-02-19 17:29:08 -05:00
parent 50d05c423d
commit aa278fb193
7 changed files with 111 additions and 18 deletions

View File

@ -160,6 +160,7 @@
"style-loader": "^0.20.1", "style-loader": "^0.20.1",
"svg-react-loader": "^0.4.5", "svg-react-loader": "^0.4.5",
"uglifyjs-webpack-plugin": "^1.1.8", "uglifyjs-webpack-plugin": "^1.1.8",
"url-search-params": "^0.10.0",
"webpack": "^3.10.0", "webpack": "^3.10.0",
"webpack-merge": "^4.1.1", "webpack-merge": "^4.1.1",
"webpack-node-externals": "^1.6.0", "webpack-node-externals": "^1.6.0",

View File

@ -5,7 +5,6 @@ exports[`App rendering 1`] = `
<Translate(Form) <Translate(Form)
downloadUrls={Array []} downloadUrls={Array []}
onSubmit={[Function]} onSubmit={[Function]}
permalinkUrl="#permalink"
syntaxes={ syntaxes={
Object { Object {
"js": "JavaScript", "js": "JavaScript",

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { translate } from 'react-i18next'; import { translate } from 'react-i18next';
import URLSearchParams from 'url-search-params';
import style from './style.css'; import style from './style.css';
@ -14,6 +15,15 @@ class App extends React.PureComponent {
syntaxes syntaxes
} }
componentDidMount() {
window.addEventListener('hashchange', this.handleHashChange);
this.handleHashChange();
}
componentWillUnmount() {
window.removeEventListener('hashchange', this.handleHashChange);
}
setSvgUrl(element) { setSvgUrl(element) {
try { try {
const type = 'image/svg+xml'; const type = 'image/svg+xml';
@ -68,9 +78,40 @@ class App extends React.PureComponent {
} }
handleSubmit = ({expr, syntax}) => { handleSubmit = ({expr, syntax}) => {
if (expr) {
const params = new URLSearchParams({ syntax, expr });
document.location.hash = params.toString();
}
}
handleHashChange = () => {
const query = document.location.hash.slice(1);
const params = new URLSearchParams(query);
const { expr, syntax } = (() => {
if (params.get('syntax')) {
return {
syntax: params.get('syntax'),
expr: params.get('expr')
};
} else {
// Assuming old-style URL
return {
syntax: 'js',
expr: query
};
}
})();
if (!expr) {
return;
}
console.log(syntax, expr); // eslint-disable-line no-console console.log(syntax, expr); // eslint-disable-line no-console
this.setState({ this.setState({
image: demoImage image: demoImage,
permalinkUrl: document.location.toString(),
syntax,
expr
}, async () => { }, async () => {
await this.image.doReflow(); await this.image.doReflow();
this.setSvgUrl(this.image.svg); this.setSvgUrl(this.image.svg);
@ -81,7 +122,7 @@ class App extends React.PureComponent {
imageRef = image => this.image = image imageRef = image => this.image = image
render() { render() {
const { svgUrl, pngUrl, syntaxes, image } = this.state; const { svgUrl, pngUrl, permalinkUrl, syntax, expr, syntaxes, image } = this.state;
const downloadUrls = [ const downloadUrls = [
svgUrl, svgUrl,
pngUrl pngUrl
@ -91,7 +132,9 @@ class App extends React.PureComponent {
<Form <Form
syntaxes={ syntaxes } syntaxes={ syntaxes }
downloadUrls={ downloadUrls } downloadUrls={ downloadUrls }
permalinkUrl="#permalink" permalinkUrl={ permalinkUrl }
syntax={ syntax }
expr={ expr }
onSubmit={ this.handleSubmit }/> onSubmit={ this.handleSubmit }/>
<Message type="error" heading="Sample Error"> <Message type="error" heading="Sample Error">
<p>Sample error message</p> <p>Sample error message</p>

View File

@ -9,6 +9,8 @@ exports[`Form rendering 1`] = `
> >
<textarea <textarea
autoFocus={true} autoFocus={true}
name="expr"
onChange={[Function]}
onKeyPress={[Function]} onKeyPress={[Function]}
placeholder="translate(Enter regular expression to display)" placeholder="translate(Enter regular expression to display)"
/> />
@ -22,7 +24,11 @@ exports[`Form rendering 1`] = `
<div <div
className="select" className="select"
> >
<select> <select
name="syntax"
onChange={[Function]}
value="js"
>
<option <option
key="js" key="js"
value="js" value="js"
@ -54,6 +60,8 @@ exports[`Form rendering with download URLs 1`] = `
> >
<textarea <textarea
autoFocus={true} autoFocus={true}
name="expr"
onChange={[Function]}
onKeyPress={[Function]} onKeyPress={[Function]}
placeholder="translate(Enter regular expression to display)" placeholder="translate(Enter regular expression to display)"
/> />
@ -67,7 +75,11 @@ exports[`Form rendering with download URLs 1`] = `
<div <div
className="select" className="select"
> >
<select> <select
name="syntax"
onChange={[Function]}
value="js"
>
<option <option
key="js" key="js"
value="js" value="js"
@ -124,6 +136,8 @@ exports[`Form rendering with permalink URL 1`] = `
> >
<textarea <textarea
autoFocus={true} autoFocus={true}
name="expr"
onChange={[Function]}
onKeyPress={[Function]} onKeyPress={[Function]}
placeholder="translate(Enter regular expression to display)" placeholder="translate(Enter regular expression to display)"
/> />
@ -137,7 +151,11 @@ exports[`Form rendering with permalink URL 1`] = `
<div <div
className="select" className="select"
> >
<select> <select
name="syntax"
onChange={[Function]}
value="js"
>
<option <option
key="js" key="js"
value="js" value="js"

View File

@ -8,12 +8,34 @@ import ExpandIcon from 'feather-icons/dist/icons/chevrons-down.svg';
import style from './style.css'; import style from './style.css';
class Form extends React.Component { class Form extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
syntax: props.syntax || Object.keys(props.syntaxes)[0],
expr: props.expr
};
}
componentWillReceiveProps(next) {
if (this.props.expr !== next.expr) {
this.setState({
expr: next.expr
});
}
if (this.props.syntax !== next.syntax) {
this.setState({
syntax: next.syntax
});
}
}
handleSubmit = event => { handleSubmit = event => {
event.preventDefault(); event.preventDefault();
this.props.onSubmit.call(this, { this.props.onSubmit.call(this, {
expr: this.textarea.value, expr: this.state.expr,
syntax: this.syntax.value syntax: this.state.syntax
}); });
} }
@ -23,9 +45,7 @@ class Form extends React.Component {
} }
} }
textareaRef = textarea => this.textarea = textarea handleChange = event => this.setState({ [event.target.name]: event.target.value })
syntaxRef = syntax => this.syntax = syntax
permalinkAction() { permalinkAction() {
const { permalinkUrl } = this.props; const { permalinkUrl } = this.props;
@ -55,17 +75,23 @@ class Form extends React.Component {
render() { render() {
const { syntaxes, t } = this.props; const { syntaxes, t } = this.props;
const { expr, syntax } = this.state;
return <div className={ style.form }> return <div className={ style.form }>
<form onSubmit={ this.handleSubmit }> <form onSubmit={ this.handleSubmit }>
<textarea <textarea
ref={ this.textareaRef } name="expr"
value={ expr }
onKeyPress={ this.handleKeyPress } onKeyPress={ this.handleKeyPress }
onChange={ this.handleChange }
autoFocus autoFocus
placeholder={ t('Enter regular expression to display') }></textarea> placeholder={ t('Enter regular expression to display') }></textarea>
<button type="submit"><Trans>Display</Trans></button> <button type="submit"><Trans>Display</Trans></button>
<div className={ style.select }> <div className={ style.select }>
<select ref={ this.syntaxRef }> <select
name="syntax"
value={ syntax }
onChange={ this.handleChange }>
{ Object.keys(syntaxes).map(id => ( { Object.keys(syntaxes).map(id => (
<option value={ id } key={ id }>{ syntaxes[id] }</option> <option value={ id } key={ id }>{ syntaxes[id] }</option>
)) } )) }
@ -83,6 +109,8 @@ class Form extends React.Component {
} }
Form.propTypes = { Form.propTypes = {
expr: PropTypes.string,
syntax: PropTypes.string,
syntaxes: PropTypes.object, syntaxes: PropTypes.object,
onSubmit: PropTypes.func, onSubmit: PropTypes.func,
permalinkUrl: PropTypes.string, permalinkUrl: PropTypes.string,

View File

@ -50,13 +50,13 @@ describe('Form', () => {
const onSubmit = jest.fn(); const onSubmit = jest.fn();
const component = build({ onSubmit }); const component = build({ onSubmit });
const eventObj = { preventDefault: jest.fn() }; const eventObj = { preventDefault: jest.fn() };
component.find(Form).instance().textarea.value = 'Test textarea value'; component.find(Form).instance().setState({ syntax: 'test', expr: 'Test expression' });
component.find('form').simulate('submit', eventObj); component.find('form').simulate('submit', eventObj);
expect(eventObj.preventDefault).toHaveBeenCalled(); expect(eventObj.preventDefault).toHaveBeenCalled();
expect(onSubmit).toHaveBeenCalledWith({ expect(onSubmit).toHaveBeenCalledWith({
expr: 'Test textarea value', expr: 'Test expression',
syntax: 'js' syntax: 'test'
}); });
}); });

View File

@ -8132,6 +8132,10 @@ url-regex@^3.0.0:
dependencies: dependencies:
ip-regex "^1.0.1" ip-regex "^1.0.1"
url-search-params@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/url-search-params/-/url-search-params-0.10.0.tgz#d428c1fa9d78d5c5a3feb634147873890f4adcf0"
url@^0.11.0: url@^0.11.0:
version "0.11.0" version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"