mirror of
https://github.com/d07RiV/diabloweb.git
synced 2026-06-03 21:41:38 +00:00
updates
This commit is contained in:
@@ -72,7 +72,9 @@ module.exports = {
|
|||||||
appBuild: resolveApp('build'),
|
appBuild: resolveApp('build'),
|
||||||
appPublic: resolveApp('public'),
|
appPublic: resolveApp('public'),
|
||||||
appHtml: resolveApp('public/index.html'),
|
appHtml: resolveApp('public/index.html'),
|
||||||
|
appHtmlStorage: resolveApp('public/storage.html'),
|
||||||
appIndexJs: resolveModule(resolveApp, 'src/index'),
|
appIndexJs: resolveModule(resolveApp, 'src/index'),
|
||||||
|
appStorageJs: resolveModule(resolveApp, 'src/storage'),
|
||||||
appPackageJson: resolveApp('package.json'),
|
appPackageJson: resolveApp('package.json'),
|
||||||
appSrc: resolveApp('src'),
|
appSrc: resolveApp('src'),
|
||||||
appTsConfig: resolveApp('tsconfig.json'),
|
appTsConfig: resolveApp('tsconfig.json'),
|
||||||
|
|||||||
@@ -128,25 +128,28 @@ module.exports = function(webpackEnv) {
|
|||||||
: isEnvDevelopment && 'cheap-module-source-map',
|
: isEnvDevelopment && 'cheap-module-source-map',
|
||||||
// These are the "entry points" to our application.
|
// These are the "entry points" to our application.
|
||||||
// This means they will be the "root" imports that are included in JS bundle.
|
// This means they will be the "root" imports that are included in JS bundle.
|
||||||
entry: [
|
entry: {
|
||||||
// Include an alternative client for WebpackDevServer. A client's job is to
|
main: [
|
||||||
// connect to WebpackDevServer by a socket and get notified about changes.
|
// Include an alternative client for WebpackDevServer. A client's job is to
|
||||||
// When you save a file, the client will either apply hot updates (in case
|
// connect to WebpackDevServer by a socket and get notified about changes.
|
||||||
// of CSS changes), or refresh the page (in case of JS changes). When you
|
// When you save a file, the client will either apply hot updates (in case
|
||||||
// make a syntax error, this client will display a syntax error overlay.
|
// of CSS changes), or refresh the page (in case of JS changes). When you
|
||||||
// Note: instead of the default WebpackDevServer client, we use a custom one
|
// make a syntax error, this client will display a syntax error overlay.
|
||||||
// to bring better experience for Create React App users. You can replace
|
// Note: instead of the default WebpackDevServer client, we use a custom one
|
||||||
// the line below with these two lines if you prefer the stock client:
|
// to bring better experience for Create React App users. You can replace
|
||||||
// require.resolve('webpack-dev-server/client') + '?/',
|
// the line below with these two lines if you prefer the stock client:
|
||||||
// require.resolve('webpack/hot/dev-server'),
|
// require.resolve('webpack-dev-server/client') + '?/',
|
||||||
isEnvDevelopment &&
|
// require.resolve('webpack/hot/dev-server'),
|
||||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
isEnvDevelopment &&
|
||||||
// Finally, this is your app's code:
|
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||||
paths.appIndexJs,
|
// Finally, this is your app's code:
|
||||||
// We include the app code last so that if there is a runtime error during
|
paths.appIndexJs,
|
||||||
// initialization, it doesn't blow up the WebpackDevServer client, and
|
// We include the app code last so that if there is a runtime error during
|
||||||
// changing JS code would still trigger a refresh.
|
// initialization, it doesn't blow up the WebpackDevServer client, and
|
||||||
].filter(Boolean),
|
// changing JS code would still trigger a refresh.
|
||||||
|
].filter(Boolean),
|
||||||
|
storage: paths.appStorageJs,
|
||||||
|
},
|
||||||
output: {
|
output: {
|
||||||
// The build folder.
|
// The build folder.
|
||||||
path: isEnvProduction ? paths.appBuild : undefined,
|
path: isEnvProduction ? paths.appBuild : undefined,
|
||||||
@@ -500,6 +503,7 @@ module.exports = function(webpackEnv) {
|
|||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
inject: true,
|
inject: true,
|
||||||
|
chunks: ['main'],
|
||||||
template: paths.appHtml,
|
template: paths.appHtml,
|
||||||
},
|
},
|
||||||
isEnvProduction
|
isEnvProduction
|
||||||
@@ -520,6 +524,33 @@ module.exports = function(webpackEnv) {
|
|||||||
: undefined
|
: undefined
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
new HtmlWebpackPlugin(
|
||||||
|
Object.assign(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
inject: true,
|
||||||
|
chunks: ['storage'],
|
||||||
|
filename: 'storage.html',
|
||||||
|
template: paths.appHtmlStorage,
|
||||||
|
},
|
||||||
|
isEnvProduction
|
||||||
|
? {
|
||||||
|
minify: {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
useShortDoctype: true,
|
||||||
|
removeEmptyAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
keepClosingSlash: true,
|
||||||
|
minifyJS: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyURLs: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
)
|
||||||
|
),
|
||||||
// Inlines the webpack runtime script. This script is too small to warrant
|
// Inlines the webpack runtime script. This script is too small to warrant
|
||||||
// a network request.
|
// a network request.
|
||||||
isEnvProduction &&
|
isEnvProduction &&
|
||||||
|
|||||||
5992
package-lock.json
generated
5992
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -64,7 +64,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node scripts/start.js",
|
"start": "node scripts/start.js",
|
||||||
"build": "node scripts/build.js",
|
"build": "node scripts/build.js",
|
||||||
"test": "node scripts/test.js"
|
"test": "node scripts/test.js",
|
||||||
|
"deploy": "gh-pages -d build"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": "react-app"
|
"extends": "react-app"
|
||||||
@@ -131,8 +132,10 @@
|
|||||||
"react-app"
|
"react-app"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"homepage": "https://d07riv.github.io/diabloweb",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"exports-loader": "^0.7.0",
|
"exports-loader": "^0.7.0",
|
||||||
|
"gh-pages": "^2.0.1",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^4.12.0",
|
||||||
"worker-loader": "^2.0.0"
|
"worker-loader": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
public/icon-192.png
Normal file
BIN
public/icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
public/icon-512.png
Normal file
BIN
public/icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -6,10 +6,20 @@
|
|||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
"sizes": "64x64 32x32 24x24 16x16",
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
"type": "image/x-icon"
|
"type": "image/x-icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icon-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icon-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"start_url": ".",
|
"start_url": ".",
|
||||||
"display": "standalone",
|
"display": "fullscreen",
|
||||||
"theme_color": "#000000",
|
"theme_color": "#ffffff",
|
||||||
"background_color": "#ffffff"
|
"background_color": "#000000"
|
||||||
}
|
}
|
||||||
|
|||||||
9
public/storage.html
Normal file
9
public/storage.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>DIABLO Connector</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
src/App.js
35
src/App.js
@@ -46,7 +46,7 @@ class App extends React.Component {
|
|||||||
touchMods = [false, false, false, false, false, false];
|
touchMods = [false, false, false, false, false, false];
|
||||||
touchBelt = [-1, -1, -1, -1, -1, -1];
|
touchBelt = [-1, -1, -1, -1, -1, -1];
|
||||||
|
|
||||||
fs = create_fs(this);
|
fs = create_fs(true);
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -344,6 +344,11 @@ class App extends React.Component {
|
|||||||
this.touchButton = touchOther;
|
this.touchButton = touchOther;
|
||||||
if (touchOther) {
|
if (touchOther) {
|
||||||
this.setTouchMod(touchOther.index, true);
|
this.setTouchMod(touchOther.index, true);
|
||||||
|
if (touchOther.index === TOUCH_MOVE) {
|
||||||
|
this.setTouchMod(TOUCH_RMB, false);
|
||||||
|
} else if (touchOther.index === TOUCH_RMB) {
|
||||||
|
this.setTouchMod(TOUCH_MOVE, false);
|
||||||
|
}
|
||||||
delete this.panPos;
|
delete this.panPos;
|
||||||
} else if (touches.length === 2) {
|
} else if (touches.length === 2) {
|
||||||
const x = (touches[1].clientX + touches[0].clientX) / 2, y = (touches[1].clientY + touches[0].clientY) / 2;
|
const x = (touches[1].clientX + touches[0].clientX) / 2, y = (touches[1].clientY + touches[0].clientY) / 2;
|
||||||
@@ -406,6 +411,10 @@ class App extends React.Component {
|
|||||||
const {x, y} = this.mousePos(prevTc);
|
const {x, y} = this.mousePos(prevTc);
|
||||||
this.game("DApi_Mouse", 2, 1, this.eventMods(e), x, y);
|
this.game("DApi_Mouse", 2, 1, this.eventMods(e), x, y);
|
||||||
this.game("DApi_Mouse", 2, 2, this.eventMods(e), x, y);
|
this.game("DApi_Mouse", 2, 2, this.eventMods(e), x, y);
|
||||||
|
|
||||||
|
if (this.touchMods[TOUCH_RMB] && (!this.touchButton || this.touchButton.index !== TOUCH_RMB)) {
|
||||||
|
this.setTouchButton(TOUCH_RMB, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!document.fullscreenElement) {
|
if (!document.fullscreenElement) {
|
||||||
this.element.requestFullscreen();
|
this.element.requestFullscreen();
|
||||||
@@ -469,22 +478,20 @@ class App extends React.Component {
|
|||||||
This is a web port of the original Diablo game, based on source code reconstructed by
|
This is a web port of the original Diablo game, based on source code reconstructed by
|
||||||
GalaXyHaXz and devilution team: <Link href="https://github.com/diasurgical/devilution">https://github.com/diasurgical/devilution</Link>
|
GalaXyHaXz and devilution team: <Link href="https://github.com/diasurgical/devilution">https://github.com/diasurgical/devilution</Link>
|
||||||
</p>
|
</p>
|
||||||
<form>
|
<p>
|
||||||
|
If you own the original game, you can drop the original DIABDAT.MPQ onto this page or click the button below to start playing.
|
||||||
|
The game can be purchased from <Link href="https://www.gog.com/game/diablo">GoG</Link>.
|
||||||
|
</p>
|
||||||
|
{!has_spawn && (
|
||||||
<p>
|
<p>
|
||||||
If you own the original game, you can drop the original DIABDAT.MPQ onto this page (or <label htmlFor="loadFile" className="link" onClick={this.download}>click here</label>)
|
Or you can play the shareware version for free (50MB download).
|
||||||
to start playing. The game can be purchased from <Link href="https://www.gog.com/game/diablo">GoG</Link>.
|
|
||||||
</p>
|
|
||||||
<input accept=".mpq" type="file" id="loadFile" style={{display: "none"}} onChange={this.parseFile}/>
|
|
||||||
</form>
|
|
||||||
{has_spawn ? (
|
|
||||||
<span className="startButton" onClick={() => this.start()}>Play Shareware</span>
|
|
||||||
) : (
|
|
||||||
<p>
|
|
||||||
Or you can download and play the shareware version instead (50MB download). <i>The site has lately been under too much stress due to users downloading the shareware
|
|
||||||
package, so instead you will need to <a href="https://d07riv.github.io/diabloweb/public/spawn.mpq">download it from GitHub</a>, then drop it on the page (or upload
|
|
||||||
by <label htmlFor="loadFile" className="link" onClick={this.download}>clicking here</label>).</i>
|
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
<form>
|
||||||
|
<label htmlFor="loadFile" className="startButton">Select MPQ</label>
|
||||||
|
<input accept=".mpq" type="file" id="loadFile" style={{display: "none"}} onChange={this.parseFile}/>
|
||||||
|
</form>
|
||||||
|
<span className="startButton" onClick={() => this.start()}>Play Shareware</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ body, #root, .App {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
background: #000;
|
background: #000;
|
||||||
p {
|
p {
|
||||||
margin: 12px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
.startButton {
|
.startButton {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -88,6 +88,8 @@ body, #root, .App {
|
|||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
padding: 4px 18px;
|
padding: 4px 18px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-top: 6px;
|
||||||
|
width: 90%;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #111;
|
background-color: #111;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
const SpawnSize = 50274091;
|
const SpawnSize = 50274091;
|
||||||
|
|
||||||
@@ -12,13 +12,12 @@ export default async function load_spawn(api, fs) {
|
|||||||
file = null;
|
file = null;
|
||||||
}
|
}
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw Error("Invalid spawn.mpq size.");
|
const spawn = await axios.request({
|
||||||
/*const spawn = await axios.request({
|
|
||||||
url: '/spawn.mpq',
|
url: '/spawn.mpq',
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
onDownloadProgress: e => {
|
onDownloadProgress: e => {
|
||||||
if (api.onProgress) {
|
if (api.onProgress) {
|
||||||
api.onProgress({type: 'spawn', loaded: e.loaded, total: e.total || SpawnSize});
|
api.onProgress({text: 'Downloading...', loaded: e.loaded, total: e.total || SpawnSize});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
@@ -30,7 +29,7 @@ export default async function load_spawn(api, fs) {
|
|||||||
}
|
}
|
||||||
const data = new Uint8Array(spawn.data);
|
const data = new Uint8Array(spawn.data);
|
||||||
fs.files.set('spawn.mpq', data);
|
fs.files.set('spawn.mpq', data);
|
||||||
fs.update('spawn.mpq', data);*/
|
fs.update('spawn.mpq', data.slice());
|
||||||
}
|
}
|
||||||
return fs;
|
return fs;
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/fs.js
43
src/fs.js
@@ -1,22 +1,63 @@
|
|||||||
import IdbKvStore from 'idb-kv-store';
|
import IdbKvStore from 'idb-kv-store';
|
||||||
|
|
||||||
export default async function create_fs() {
|
const importStorage = () => new Promise((resolve, reject) => {
|
||||||
|
let done = false;
|
||||||
|
const frame = document.createElement('iframe');
|
||||||
|
window.addEventListener('message', ({data}) => {
|
||||||
|
if (data.method === 'storage' && !done) {
|
||||||
|
done = true;
|
||||||
|
resolve(data.files);
|
||||||
|
frame.contentWindow.postMessage({method: 'clear'}, '*');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
frame.addEventListener('load', () => {
|
||||||
|
frame.contentWindow.postMessage({method: 'transfer'}, '*');
|
||||||
|
});
|
||||||
|
frame.addEventListener('error', () => {
|
||||||
|
if (!done) {
|
||||||
|
done = true;
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
frame.src = "https://diablo.rivsoft.net/storage.html";
|
||||||
|
frame.style.display = "none";
|
||||||
|
document.body.appendChild(frame);
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!done) {
|
||||||
|
done = true;
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default async function create_fs(load) {
|
||||||
try {
|
try {
|
||||||
const store = new IdbKvStore('diablo_fs');
|
const store = new IdbKvStore('diablo_fs');
|
||||||
const files = new Map();
|
const files = new Map();
|
||||||
for (let [name, data] of Object.entries(await store.json())) {
|
for (let [name, data] of Object.entries(await store.json())) {
|
||||||
files.set(name, data);
|
files.set(name, data);
|
||||||
}
|
}
|
||||||
|
if (load) {
|
||||||
|
const files = await importStorage();
|
||||||
|
if (files) {
|
||||||
|
for (let [name, data] of files) {
|
||||||
|
files.set(name, data);
|
||||||
|
store.set(name, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
files,
|
files,
|
||||||
update: (name, data) => store.set(name, data),
|
update: (name, data) => store.set(name, data),
|
||||||
delete: name => store.remove(name),
|
delete: name => store.remove(name),
|
||||||
|
clear: () => store.clear(),
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
files: new Map(),
|
files: new Map(),
|
||||||
update: () => Promise.resolve(),
|
update: () => Promise.resolve(),
|
||||||
delete: () => Promise.resolve(),
|
delete: () => Promise.resolve(),
|
||||||
|
clear: () => Promise.resolve(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './reset.css';
|
import './reset.css';
|
||||||
|
import * as serviceWorker from './serviceWorker';
|
||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.getElementById('root'));
|
ReactDOM.render(<App />, document.getElementById('root'));
|
||||||
|
|
||||||
|
serviceWorker.register();
|
||||||
|
|||||||
135
src/serviceWorker.js
Normal file
135
src/serviceWorker.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// This optional code is used to register a service worker.
|
||||||
|
// register() is not called by default.
|
||||||
|
|
||||||
|
// This lets the app load faster on subsequent visits in production, and gives
|
||||||
|
// it offline capabilities. However, it also means that developers (and users)
|
||||||
|
// will only see deployed updates on subsequent visits to a page, after all the
|
||||||
|
// existing tabs open on the page have been closed, since previously cached
|
||||||
|
// resources are updated in the background.
|
||||||
|
|
||||||
|
// To learn more about the benefits of this model and instructions on how to
|
||||||
|
// opt-in, read https://bit.ly/CRA-PWA
|
||||||
|
|
||||||
|
const isLocalhost = Boolean(
|
||||||
|
window.location.hostname === 'localhost' ||
|
||||||
|
// [::1] is the IPv6 localhost address.
|
||||||
|
window.location.hostname === '[::1]' ||
|
||||||
|
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||||
|
window.location.hostname.match(
|
||||||
|
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export function register(config) {
|
||||||
|
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||||
|
// The URL constructor is available in all browsers that support SW.
|
||||||
|
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||||
|
if (publicUrl.origin !== window.location.origin) {
|
||||||
|
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||||
|
// from what our page is served on. This might happen if a CDN is used to
|
||||||
|
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||||
|
|
||||||
|
if (isLocalhost) {
|
||||||
|
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||||
|
checkValidServiceWorker(swUrl, config);
|
||||||
|
|
||||||
|
// Add some additional logging to localhost, pointing developers to the
|
||||||
|
// service worker/PWA documentation.
|
||||||
|
navigator.serviceWorker.ready.then(() => {
|
||||||
|
console.log(
|
||||||
|
'This web app is being served cache-first by a service ' +
|
||||||
|
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Is not localhost. Just register service worker
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerValidSW(swUrl, config) {
|
||||||
|
navigator.serviceWorker
|
||||||
|
.register(swUrl)
|
||||||
|
.then(registration => {
|
||||||
|
registration.onupdatefound = () => {
|
||||||
|
const installingWorker = registration.installing;
|
||||||
|
if (installingWorker == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
installingWorker.onstatechange = () => {
|
||||||
|
if (installingWorker.state === 'installed') {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
// At this point, the updated precached content has been fetched,
|
||||||
|
// but the previous service worker will still serve the older
|
||||||
|
// content until all client tabs are closed.
|
||||||
|
console.log(
|
||||||
|
'New content is available and will be used when all ' +
|
||||||
|
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onUpdate) {
|
||||||
|
config.onUpdate(registration);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// At this point, everything has been precached.
|
||||||
|
// It's the perfect time to display a
|
||||||
|
// "Content is cached for offline use." message.
|
||||||
|
console.log('Content is cached for offline use.');
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onSuccess) {
|
||||||
|
config.onSuccess(registration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error during service worker registration:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkValidServiceWorker(swUrl, config) {
|
||||||
|
// Check if the service worker can be found. If it can't reload the page.
|
||||||
|
fetch(swUrl)
|
||||||
|
.then(response => {
|
||||||
|
// Ensure service worker exists, and that we really are getting a JS file.
|
||||||
|
const contentType = response.headers.get('content-type');
|
||||||
|
if (
|
||||||
|
response.status === 404 ||
|
||||||
|
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||||
|
) {
|
||||||
|
// No service worker found. Probably a different app. Reload the page.
|
||||||
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
|
registration.unregister().then(() => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Service worker found. Proceed as normal.
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log(
|
||||||
|
'No internet connection found. App is running in offline mode.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unregister() {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
|
registration.unregister();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/storage.js
Normal file
12
src/storage.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import create_fs from './fs';
|
||||||
|
|
||||||
|
const fs = create_fs();
|
||||||
|
window.addEventListener('message', ({data, source}) => {
|
||||||
|
if (data.method === 'transfer') {
|
||||||
|
fs.then(({files}) => {
|
||||||
|
source.postMessage({method: 'storage', files}, '*');
|
||||||
|
});
|
||||||
|
} else if (data.method === 'clear') {
|
||||||
|
fs.then(({clear}) => clear());
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user