koffing 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Makefile +21 -0
- package/README.md +75 -26
- package/build/asset-manifest.json +22 -0
- package/build/favicon.png +0 -0
- package/build/index.html +1 -0
- package/build/precache-manifest.5382b78dea2866c8a94cee003da35d84.js +26 -0
- package/build/robots.txt +3 -0
- package/build/service-worker.js +39 -0
- package/build/static/css/main.102b9840.chunk.css +2 -0
- package/build/static/css/main.102b9840.chunk.css.map +1 -0
- package/build/static/js/2.4b3dd85a.chunk.js +3 -0
- package/build/static/js/2.4b3dd85a.chunk.js.LICENSE.txt +67 -0
- package/build/static/js/2.4b3dd85a.chunk.js.map +1 -0
- package/build/static/js/main.07f66bec.chunk.js +2 -0
- package/build/static/js/main.07f66bec.chunk.js.map +1 -0
- package/build/static/js/runtime-main.525bb0ff.js +2 -0
- package/build/static/js/runtime-main.525bb0ff.js.map +1 -0
- package/package.json +42 -31
- package/public/favicon.png +0 -0
- package/public/index.html +30 -0
- package/public/robots.txt +3 -0
- package/src/App.test.js +9 -0
- package/src/components/App.js +18 -0
- package/src/components/AppFooter/AppFooter.css.js +12 -0
- package/src/components/AppFooter/AppFooter.js +31 -0
- package/src/components/AppFooter/index.js +3 -0
- package/src/components/AppHeader/AppHeader.css.js +21 -0
- package/src/components/AppHeader/AppHeader.js +34 -0
- package/src/components/AppHeader/index.js +3 -0
- package/src/components/Board/Board.css.js +21 -0
- package/src/components/Board/Board.js +110 -0
- package/src/components/Board/index.js +3 -0
- package/src/components/BoardInput/BoardInput.css.js +14 -0
- package/src/components/BoardInput/BoardInput.js +36 -0
- package/src/components/BoardInput/index.js +3 -0
- package/src/components/BoardOutput/BoardOutput.css.js +17 -0
- package/src/components/BoardOutput/BoardOutput.js +36 -0
- package/src/components/BoardOutput/index.js +3 -0
- package/src/components/Code/Code.css.js +10 -0
- package/src/components/Code/Code.js +28 -0
- package/src/components/Code/index.js +3 -0
- package/src/components/StyledComponent.js +24 -0
- package/src/components/ThemedApp.js +25 -0
- package/src/core/Koffing.js +71 -0
- package/src/{Pokemon.js → core/Pokemon.js} +9 -2
- package/src/{PokemonTeam.js → core/PokemonTeam.js} +0 -2
- package/src/{PokemonTeamSet.js → core/PokemonTeamSet.js} +0 -2
- package/src/{ShowdownParser.js → core/ShowdownParser.js} +7 -8
- package/src/core/index.js +7 -0
- package/src/img/koffing-shiny.png +0 -0
- package/src/img/koffing.png +0 -0
- package/src/index.css +42 -0
- package/src/index.js +15 -74
- package/src/serviceWorker.js +141 -0
- package/src/setupTests.js +5 -0
- package/src/teams/example.koffing.js +25 -0
- package/src/tools/base64.js +25 -0
- package/src/tools/history.js +17 -0
- package/src/tools/index.js +4 -0
- package/src/variables.json +5 -0
- package/dist/koffing.js +0 -940
- package/dist/koffing.min.js +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {makeStyles} from '@material-ui/core/styles';
|
|
2
|
+
|
|
3
|
+
export default makeStyles((theme) => ({
|
|
4
|
+
root: {
|
|
5
|
+
marginTop: 0,
|
|
6
|
+
overflow: 'hidden'
|
|
7
|
+
},
|
|
8
|
+
textArea: {
|
|
9
|
+
fontFamily: "monospace",
|
|
10
|
+
fontSize: "1em",
|
|
11
|
+
backgroundColor: theme.palette.secondary.main,
|
|
12
|
+
padding: theme.spacing()
|
|
13
|
+
}
|
|
14
|
+
}))
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import TextField from "@material-ui/core/TextField";
|
|
4
|
+
import useStyles from "./BoardInput.css";
|
|
5
|
+
|
|
6
|
+
function BoardInput({value, onChange}) {
|
|
7
|
+
const classes = useStyles();
|
|
8
|
+
|
|
9
|
+
return <TextField
|
|
10
|
+
autoComplete="off"
|
|
11
|
+
autoCorrect="off"
|
|
12
|
+
autoCapitalize="off"
|
|
13
|
+
spellCheck="false"
|
|
14
|
+
multiline
|
|
15
|
+
className={classes.root}
|
|
16
|
+
rows="12"
|
|
17
|
+
rowsMax="24"
|
|
18
|
+
autoFocus={true}
|
|
19
|
+
placeholder="Place here your Showdown teams"
|
|
20
|
+
// defaultValue={exampleTeam}
|
|
21
|
+
fullWidth
|
|
22
|
+
margin="normal"
|
|
23
|
+
value={value}
|
|
24
|
+
inputProps={{
|
|
25
|
+
className: classes.textArea
|
|
26
|
+
}}
|
|
27
|
+
onChange={onChange}
|
|
28
|
+
/>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
BoardInput.propTypes = {
|
|
32
|
+
value: PropTypes.string.isRequired,
|
|
33
|
+
onChange: PropTypes.func
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default BoardInput;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {makeStyles} from '@material-ui/core/styles';
|
|
2
|
+
|
|
3
|
+
export default makeStyles((theme) => ({
|
|
4
|
+
root: {
|
|
5
|
+
padding: theme.spacing() * 2,
|
|
6
|
+
color: theme.palette.text.secondary
|
|
7
|
+
},
|
|
8
|
+
qrContainer: {
|
|
9
|
+
padding: theme.spacing() * 2,
|
|
10
|
+
textAlign: "center",
|
|
11
|
+
backgroundColor: "#dde0f6"
|
|
12
|
+
},
|
|
13
|
+
jsonContainer: {
|
|
14
|
+
padding: theme.spacing() * 2,
|
|
15
|
+
backgroundColor: "#fafafa"
|
|
16
|
+
}
|
|
17
|
+
}))
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import Paper from "@material-ui/core/Paper";
|
|
4
|
+
import QRCode from "qrcode.react";
|
|
5
|
+
import Code from "../Code";
|
|
6
|
+
import useStyles from "./BoardOutput.css";
|
|
7
|
+
import logo from "../../img/koffing.png";
|
|
8
|
+
|
|
9
|
+
const qrIconSettings = {
|
|
10
|
+
src: logo,
|
|
11
|
+
height: 48,
|
|
12
|
+
width: 48,
|
|
13
|
+
excavate: true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function BoardOutput({qrValue, jsonValue}) {
|
|
17
|
+
const classes = useStyles();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Paper className={classes.root} elevation={1}>
|
|
21
|
+
<Paper className={classes.qrContainer}>
|
|
22
|
+
<QRCode value={qrValue} size={320} renderAs="canvas" imageSettings={qrIconSettings}/>
|
|
23
|
+
</Paper>
|
|
24
|
+
<Paper className={classes.jsonContainer}>
|
|
25
|
+
<Code code={jsonValue} language={'json'}/>
|
|
26
|
+
</Paper>
|
|
27
|
+
</Paper>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
BoardOutput.propTypes = {
|
|
32
|
+
qrValue: PropTypes.string.isRequired,
|
|
33
|
+
jsonValue: PropTypes.string.isRequired
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default BoardOutput;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import StyledComponent from "../StyledComponent";
|
|
4
|
+
import styles from "./Code.css";
|
|
5
|
+
|
|
6
|
+
class Code extends StyledComponent {
|
|
7
|
+
static propTypes = Object.assign({}, super.propTypes, {
|
|
8
|
+
language: PropTypes.string.isRequired,
|
|
9
|
+
code: PropTypes.string.isRequired,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
render() {
|
|
13
|
+
const formattedCode = this.props.code;
|
|
14
|
+
const codeClassName = `language-${this.props.language}`;
|
|
15
|
+
const {classes} = this.props;
|
|
16
|
+
return (
|
|
17
|
+
<div className={classes.root}>
|
|
18
|
+
<pre className={classes.pre}>
|
|
19
|
+
<code className={codeClassName}>
|
|
20
|
+
<div dangerouslySetInnerHTML={{__html: formattedCode}}/>
|
|
21
|
+
</code>
|
|
22
|
+
</pre>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default Code.styled(styles);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {Component} from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import {withStyles} from '@material-ui/core/styles';
|
|
4
|
+
// eslint-disable-next-line no-unused-vars
|
|
5
|
+
import {StyledComponentProps} from '@material-ui/styles/withStyles'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @link https://material-ui.com/es/styles/basics/#higher-order-component-api
|
|
9
|
+
*/
|
|
10
|
+
class StyledComponent extends Component {
|
|
11
|
+
static propTypes = {
|
|
12
|
+
classes: PropTypes.object.isRequired
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {object} styles
|
|
17
|
+
* @returns {React.ComponentType<any & StyledComponentProps<T>>}
|
|
18
|
+
*/
|
|
19
|
+
static styled(styles) {
|
|
20
|
+
return withStyles(styles)(this);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default StyledComponent;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {createMuiTheme, MuiThemeProvider} from '@material-ui/core/styles';
|
|
3
|
+
import App from "./App";
|
|
4
|
+
|
|
5
|
+
const theme = createMuiTheme({
|
|
6
|
+
typography: {
|
|
7
|
+
fontFamily: '"Exo 2","Helvetica Neue",Arial,sans-serif',
|
|
8
|
+
},
|
|
9
|
+
palette: {
|
|
10
|
+
primary: {main: '#6B71B8'},
|
|
11
|
+
secondary: {main: '#F6F79D'},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
const ThemedApp = () => (
|
|
17
|
+
<div className="koffing-app-container">
|
|
18
|
+
{/*<CssBaseline/>*//* MUI adds the reset at the end, which is not what we want*/}
|
|
19
|
+
<MuiThemeProvider theme={theme}>
|
|
20
|
+
<App/>
|
|
21
|
+
</MuiThemeProvider>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export default ThemedApp;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import Pokemon from "./Pokemon";
|
|
2
|
+
import PokemonTeam from "./PokemonTeam";
|
|
3
|
+
import PokemonTeamSet from "./PokemonTeamSet";
|
|
4
|
+
import ShowdownParser from "./ShowdownParser";
|
|
5
|
+
|
|
6
|
+
class Koffing {
|
|
7
|
+
/**
|
|
8
|
+
* Converts from Showdown to a PokemonTeamSet object.
|
|
9
|
+
*
|
|
10
|
+
* @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
|
|
11
|
+
* @returns {PokemonTeamSet}
|
|
12
|
+
*/
|
|
13
|
+
static parse(data) {
|
|
14
|
+
if (
|
|
15
|
+
data instanceof PokemonTeamSet
|
|
16
|
+
|| data instanceof PokemonTeam
|
|
17
|
+
|| data instanceof Pokemon
|
|
18
|
+
) {
|
|
19
|
+
return data;
|
|
20
|
+
}
|
|
21
|
+
if (data instanceof ShowdownParser) {
|
|
22
|
+
return data.parse();
|
|
23
|
+
}
|
|
24
|
+
return (new ShowdownParser(data)).parse();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Prettifies and sanitizes the given Showdown code.
|
|
29
|
+
*
|
|
30
|
+
* @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
|
|
31
|
+
* @returns {String}
|
|
32
|
+
*/
|
|
33
|
+
static format(data) {
|
|
34
|
+
return this.parse(data).toShowdown();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Converts from Showdown to JSON code.
|
|
39
|
+
*
|
|
40
|
+
* @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
|
|
41
|
+
* @returns {String}
|
|
42
|
+
*/
|
|
43
|
+
static toJson(data) {
|
|
44
|
+
return this.parse(data).toJson();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Converts from JSON to Showdown code.
|
|
49
|
+
*
|
|
50
|
+
* @param {String|Object|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data JSON code or object
|
|
51
|
+
* @returns {String}
|
|
52
|
+
*/
|
|
53
|
+
static toShowdown(data) {
|
|
54
|
+
if (
|
|
55
|
+
data instanceof PokemonTeamSet
|
|
56
|
+
|| data instanceof PokemonTeam
|
|
57
|
+
|| data instanceof Pokemon
|
|
58
|
+
) {
|
|
59
|
+
return data.toShowdown();
|
|
60
|
+
}
|
|
61
|
+
if (data instanceof ShowdownParser) {
|
|
62
|
+
return data.parse().format();
|
|
63
|
+
}
|
|
64
|
+
if (typeof data === 'string' || data instanceof String) {
|
|
65
|
+
data = JSON.parse(data);
|
|
66
|
+
}
|
|
67
|
+
return PokemonTeamSet.fromObject(JSON.parse(data)).toShowdown();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default Koffing;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
1
|
class Pokemon {
|
|
4
2
|
constructor() {
|
|
5
3
|
/**
|
|
@@ -34,6 +32,10 @@ class Pokemon {
|
|
|
34
32
|
* @type {Number}
|
|
35
33
|
*/
|
|
36
34
|
this.happiness = undefined;
|
|
35
|
+
/**
|
|
36
|
+
* @type {String}
|
|
37
|
+
*/
|
|
38
|
+
this.teratype = undefined;
|
|
37
39
|
/**
|
|
38
40
|
* @type {String}
|
|
39
41
|
*/
|
|
@@ -66,6 +68,7 @@ class Pokemon {
|
|
|
66
68
|
p.level = obj.level;
|
|
67
69
|
p.shiny = obj.shiny;
|
|
68
70
|
p.happiness = obj.happiness;
|
|
71
|
+
p.teratype = obj.teratype;
|
|
69
72
|
p.nature = obj.nature;
|
|
70
73
|
p.evs = obj.evs;
|
|
71
74
|
p.ivs = obj.ivs;
|
|
@@ -119,6 +122,10 @@ class Pokemon {
|
|
|
119
122
|
if (!isNaN(this.happiness)) {
|
|
120
123
|
str += `Happiness: ${this.happiness}\n`;
|
|
121
124
|
}
|
|
125
|
+
|
|
126
|
+
if (this.teratype) {
|
|
127
|
+
str += `Tera Type: ${this.teratype}\n`;
|
|
128
|
+
}
|
|
122
129
|
|
|
123
130
|
if (this.nature) {
|
|
124
131
|
str += `${this.nature} Nature\n`;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import PokemonTeam from "PokemonTeam";
|
|
5
|
-
import PokemonTeamSet from "PokemonTeamSet";
|
|
1
|
+
import Pokemon from "./Pokemon";
|
|
2
|
+
import PokemonTeam from "./PokemonTeam";
|
|
3
|
+
import PokemonTeamSet from "./PokemonTeamSet";
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* Ported from Pokemon Showdown Client's exportTeam/importTeam functions.
|
|
@@ -17,7 +15,7 @@ class ShowdownParser {
|
|
|
17
15
|
/**
|
|
18
16
|
* @type {String}
|
|
19
17
|
*/
|
|
20
|
-
this.code = code + "";
|
|
18
|
+
this.code = code.trim() + "";
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
/**
|
|
@@ -190,7 +188,7 @@ class ShowdownParser {
|
|
|
190
188
|
_parseKeyValuePairs(line, pokemon) {
|
|
191
189
|
const rg = ShowdownParser.regexes;
|
|
192
190
|
|
|
193
|
-
return ['ability', 'level', 'shiny', 'happiness', 'nature'].some(
|
|
191
|
+
return ['ability', 'level', 'shiny', 'happiness', 'teratype', 'nature'].some(
|
|
194
192
|
function (key) {
|
|
195
193
|
if (line.match(rg[key])) {
|
|
196
194
|
pokemon[key] = rg[key].exec(line)[1].trim();
|
|
@@ -272,10 +270,11 @@ ShowdownParser.regexes = {
|
|
|
272
270
|
level: /^Level:\s?([0-9]{1,3})$/i,
|
|
273
271
|
shiny: /^Shiny:\s?(Yes|No)$/i,
|
|
274
272
|
happiness: /^Happiness:\s?([0-9]{1,3})$/i,
|
|
273
|
+
teratype: /^Tera Type:\s?(.*)$/i,
|
|
275
274
|
eivs: /^([EI]Vs):\s?(.*)$/i,
|
|
276
275
|
eivs_value: /^([0-9]+)\s+(hp|atk|def|spa|spd|spe)$/i,
|
|
277
276
|
nature: /^(.*)\s+Nature$/,
|
|
278
277
|
move: /^[-~]\s?(.*)$/i
|
|
279
278
|
};
|
|
280
279
|
|
|
281
|
-
export default ShowdownParser;
|
|
280
|
+
export default ShowdownParser;
|
|
Binary file
|
|
Binary file
|
package/src/index.css
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
html {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
-webkit-font-smoothing: antialiased;
|
|
4
|
+
-moz-osx-font-smoothing: grayscale;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
*, *::before, *::after {
|
|
8
|
+
box-sizing: inherit;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
margin: 0;
|
|
13
|
+
background-color: #fafafa;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@media print {
|
|
17
|
+
body {
|
|
18
|
+
background-color: #fff;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
a {
|
|
23
|
+
color: #6B71B8;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.koffing-sprite {
|
|
27
|
+
animation-name: koffing-animation;
|
|
28
|
+
animation-duration: 700ms;
|
|
29
|
+
animation-iteration-count: infinite;
|
|
30
|
+
animation-direction: alternate;
|
|
31
|
+
animation-timing-function: ease-in-out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Standard syntax */
|
|
35
|
+
@keyframes koffing-animation {
|
|
36
|
+
0% {
|
|
37
|
+
transform: translate(0px, 0px);
|
|
38
|
+
}
|
|
39
|
+
100% {
|
|
40
|
+
transform: translate(-2px, -3px);
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,76 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import './index.css';
|
|
4
|
+
import ThemedApp from './components/ThemedApp';
|
|
5
|
+
import * as serviceWorker from './serviceWorker';
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
ReactDOM.render(
|
|
8
|
+
<React.StrictMode>
|
|
9
|
+
<ThemedApp/>
|
|
10
|
+
</React.StrictMode>,
|
|
11
|
+
document.getElementById('root')
|
|
12
|
+
);
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
|
|
13
|
-
* @returns {PokemonTeamSet}
|
|
14
|
-
*/
|
|
15
|
-
static parse(data) {
|
|
16
|
-
if (
|
|
17
|
-
data instanceof PokemonTeamSet
|
|
18
|
-
|| data instanceof PokemonTeam
|
|
19
|
-
|| data instanceof Pokemon
|
|
20
|
-
) {
|
|
21
|
-
return data;
|
|
22
|
-
}
|
|
23
|
-
if (data instanceof ShowdownParser) {
|
|
24
|
-
return data.parse();
|
|
25
|
-
}
|
|
26
|
-
return (new ShowdownParser(data)).parse();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Prettifies and sanitizes the given Showdown code.
|
|
31
|
-
*
|
|
32
|
-
* @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
|
|
33
|
-
* @returns {String}
|
|
34
|
-
*/
|
|
35
|
-
static format(data) {
|
|
36
|
-
return this.parse(data).toShowdown();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Converts from Showdown to JSON code.
|
|
41
|
-
*
|
|
42
|
-
* @param {String|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data Showdown code or object
|
|
43
|
-
* @returns {String}
|
|
44
|
-
*/
|
|
45
|
-
static toJson(data) {
|
|
46
|
-
return this.parse(data).toJson();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Converts from JSON to Showdown code.
|
|
51
|
-
*
|
|
52
|
-
* @param {String|Object|Pokemon|PokemonTeam|PokemonTeamSet|ShowdownParser} data JSON code or object
|
|
53
|
-
* @returns {String}
|
|
54
|
-
*/
|
|
55
|
-
static toShowdown(data) {
|
|
56
|
-
if (
|
|
57
|
-
data instanceof PokemonTeamSet
|
|
58
|
-
|| data instanceof PokemonTeam
|
|
59
|
-
|| data instanceof Pokemon
|
|
60
|
-
) {
|
|
61
|
-
return data.toShowdown();
|
|
62
|
-
}
|
|
63
|
-
if (data instanceof ShowdownParser) {
|
|
64
|
-
return data.parse().format();
|
|
65
|
-
}
|
|
66
|
-
if (typeof value === 'string' || value instanceof String) {
|
|
67
|
-
data = JSON.parse(data);
|
|
68
|
-
}
|
|
69
|
-
return PokemonTeamSet.fromObject(JSON.parse(data)).toShowdown();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export {
|
|
74
|
-
Koffing,
|
|
75
|
-
ShowdownParser
|
|
76
|
-
};
|
|
14
|
+
// If you want your app to work offline and load faster, you can change
|
|
15
|
+
// unregister() to register() below. Note this comes with some pitfalls.
|
|
16
|
+
// Learn more about service workers: https://bit.ly/CRA-PWA
|
|
17
|
+
serviceWorker.unregister();
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// This optional code is used to register a service worker.
|
|
2
|
+
// register() is not called by default.
|
|
3
|
+
|
|
4
|
+
// This lets the app load faster on subsequent visits in production, and gives
|
|
5
|
+
// it offline capabilities. However, it also means that developers (and users)
|
|
6
|
+
// will only see deployed updates on subsequent visits to a page, after all the
|
|
7
|
+
// existing tabs open on the page have been closed, since previously cached
|
|
8
|
+
// teams are updated in the background.
|
|
9
|
+
|
|
10
|
+
// To learn more about the benefits of this model and instructions on how to
|
|
11
|
+
// opt-in, read https://bit.ly/CRA-PWA
|
|
12
|
+
|
|
13
|
+
const isLocalhost = Boolean(
|
|
14
|
+
window.location.hostname === 'localhost' ||
|
|
15
|
+
// [::1] is the IPv6 localhost address.
|
|
16
|
+
window.location.hostname === '[::1]' ||
|
|
17
|
+
// 127.0.0.0/8 are considered localhost for IPv4.
|
|
18
|
+
window.location.hostname.match(
|
|
19
|
+
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export function register(config) {
|
|
24
|
+
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
|
25
|
+
// The URL constructor is available in all browsers that support SW.
|
|
26
|
+
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
|
27
|
+
if (publicUrl.origin !== window.location.origin) {
|
|
28
|
+
// Our service worker won't work if PUBLIC_URL is on a different origin
|
|
29
|
+
// from what our page is served on. This might happen if a CDN is used to
|
|
30
|
+
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
window.addEventListener('load', () => {
|
|
35
|
+
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
|
36
|
+
|
|
37
|
+
if (isLocalhost) {
|
|
38
|
+
// This is running on localhost. Let's check if a service worker still exists or not.
|
|
39
|
+
checkValidServiceWorker(swUrl, config);
|
|
40
|
+
|
|
41
|
+
// Add some additional logging to localhost, pointing developers to the
|
|
42
|
+
// service worker/PWA documentation.
|
|
43
|
+
navigator.serviceWorker.ready.then(() => {
|
|
44
|
+
console.log(
|
|
45
|
+
'This web app is being served cache-first by a service ' +
|
|
46
|
+
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
// Is not localhost. Just register service worker
|
|
51
|
+
registerValidSW(swUrl, config);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function registerValidSW(swUrl, config) {
|
|
58
|
+
navigator.serviceWorker
|
|
59
|
+
.register(swUrl)
|
|
60
|
+
.then(registration => {
|
|
61
|
+
registration.onupdatefound = () => {
|
|
62
|
+
const installingWorker = registration.installing;
|
|
63
|
+
if (installingWorker == null) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
installingWorker.onstatechange = () => {
|
|
67
|
+
if (installingWorker.state === 'installed') {
|
|
68
|
+
if (navigator.serviceWorker.controller) {
|
|
69
|
+
// At this point, the updated precached content has been fetched,
|
|
70
|
+
// but the previous service worker will still serve the older
|
|
71
|
+
// content until all client tabs are closed.
|
|
72
|
+
console.log(
|
|
73
|
+
'New content is available and will be used when all ' +
|
|
74
|
+
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Execute callback
|
|
78
|
+
if (config && config.onUpdate) {
|
|
79
|
+
config.onUpdate(registration);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
// At this point, everything has been precached.
|
|
83
|
+
// It's the perfect time to display a
|
|
84
|
+
// "Content is cached for offline use." message.
|
|
85
|
+
console.log('Content is cached for offline use.');
|
|
86
|
+
|
|
87
|
+
// Execute callback
|
|
88
|
+
if (config && config.onSuccess) {
|
|
89
|
+
config.onSuccess(registration);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
})
|
|
96
|
+
.catch(error => {
|
|
97
|
+
console.error('Error during service worker registration:', error);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function checkValidServiceWorker(swUrl, config) {
|
|
102
|
+
// Check if the service worker can be found. If it can't reload the page.
|
|
103
|
+
fetch(swUrl, {
|
|
104
|
+
headers: { 'Service-Worker': 'script' },
|
|
105
|
+
})
|
|
106
|
+
.then(response => {
|
|
107
|
+
// Ensure service worker exists, and that we really are getting a JS file.
|
|
108
|
+
const contentType = response.headers.get('content-type');
|
|
109
|
+
if (
|
|
110
|
+
response.status === 404 ||
|
|
111
|
+
(contentType != null && contentType.indexOf('javascript') === -1)
|
|
112
|
+
) {
|
|
113
|
+
// No service worker found. Probably a different app. Reload the page.
|
|
114
|
+
navigator.serviceWorker.ready.then(registration => {
|
|
115
|
+
registration.unregister().then(() => {
|
|
116
|
+
window.location.reload();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
// Service worker found. Proceed as normal.
|
|
121
|
+
registerValidSW(swUrl, config);
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
.catch(() => {
|
|
125
|
+
console.log(
|
|
126
|
+
'No internet connection found. App is running in offline mode.'
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function unregister() {
|
|
132
|
+
if ('serviceWorker' in navigator) {
|
|
133
|
+
navigator.serviceWorker.ready
|
|
134
|
+
.then(registration => {
|
|
135
|
+
registration.unregister();
|
|
136
|
+
})
|
|
137
|
+
.catch(error => {
|
|
138
|
+
console.error(error.message);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|