Compare commits
27 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
21623b24f0 | |
|
|
d2fe0f47c3 | |
|
|
f5bd481975 | |
|
|
efe995e247 | |
|
|
b553eb434a | |
|
|
4f72d75642 | |
|
|
a829e7224c | |
|
|
23202e7a7b | |
|
|
06c605344f | |
|
|
015447dc57 | |
|
|
59af2e0a29 | |
|
|
8de753aac5 | |
|
|
0febac8b3c | |
|
|
2c1892303e | |
|
|
0df3a7c647 | |
|
|
3bae819cb2 | |
|
|
d020e94ac0 | |
|
|
f2fad336a3 | |
|
|
6495c49022 | |
|
|
6dd6c2e3d6 | |
|
|
04638e650d | |
|
|
d1439b3f09 | |
|
|
994880f454 | |
|
|
9795c83583 | |
|
|
f4318b2464 | |
|
|
fd3a8db71d | |
|
|
994da62aac |
|
|
@ -0,0 +1,21 @@
|
||||||
|
module.exports = {
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"commonjs": true,
|
||||||
|
"jquery": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"globals": {
|
||||||
|
"Atomics": "readonly",
|
||||||
|
"SharedArrayBuffer": "readonly"
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2018,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off",
|
||||||
|
"semi": "warn",
|
||||||
|
}
|
||||||
|
};
|
||||||
123
css/chess.css
123
css/chess.css
|
|
@ -65,7 +65,6 @@ body > #page {
|
||||||
|
|
||||||
#header > h1 {
|
#header > h1 {
|
||||||
font-family: 'Vollkorn', serif;
|
font-family: 'Vollkorn', serif;
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
line-height: 2.4rem;
|
line-height: 2.4rem;
|
||||||
|
|
@ -73,10 +72,13 @@ body > #page {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
padding-top: 0.1rem;
|
padding-top: 0.1rem;
|
||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex: 1 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header > button {
|
#header > button {
|
||||||
width: 4rem;
|
flex: 0 0 auto;
|
||||||
|
width: 2.5rem;
|
||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
|
|
@ -91,6 +93,7 @@ body > #page {
|
||||||
input.image-checkbox {
|
input.image-checkbox {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
@ -107,11 +110,12 @@ input.image-checkbox:focus {
|
||||||
}
|
}
|
||||||
|
|
||||||
#header > .checkbox-container {
|
#header > .checkbox-container {
|
||||||
|
flex: 0 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 4rem;
|
width: 2.5rem;
|
||||||
height: 2.5rem;
|
height: 2.5rem;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
|
|
@ -175,6 +179,7 @@ button#settings, button#cb_choose_game {
|
||||||
#cb_message {
|
#cb_message {
|
||||||
height: 1.2em;
|
height: 1.2em;
|
||||||
margin-bottom: 0.1rem;
|
margin-bottom: 0.1rem;
|
||||||
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#cb_explain_check {
|
#cb_explain_check {
|
||||||
|
|
@ -202,6 +207,33 @@ button#settings, button#cb_choose_game {
|
||||||
color: grey;
|
color: grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cb_times {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
white-space: nowrap;
|
||||||
|
justify-content: stretch;
|
||||||
|
align-items: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 3rem;
|
||||||
|
padding-right: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cb_times.cb-hide-times {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cb_light_time, #cb_dark_time {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cb_light_time {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cb_dark_time {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
#cb_names {
|
#cb_names {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -239,6 +271,16 @@ button#settings, button#cb_choose_game {
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cb_names.cb-light-turn::before {
|
||||||
|
filter: drop-shadow(0 0 5px blue);
|
||||||
|
-webkit-filter: drop-shadow(0 0 5px blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#cb_names.cb-light-won::before {
|
||||||
|
filter: drop-shadow(0 0 5px darkviolet);
|
||||||
|
-webkit-filter: drop-shadow(0 0 5px darkviolet);
|
||||||
|
}
|
||||||
|
|
||||||
#cb_names::after {
|
#cb_names::after {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
|
|
@ -252,6 +294,16 @@ button#settings, button#cb_choose_game {
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cb_names.cb-dark-turn::after {
|
||||||
|
filter: drop-shadow(0 0 5px blue);
|
||||||
|
-webkit-filter: drop-shadow(0 0 5px blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#cb_names.cb-dark-won::after {
|
||||||
|
filter: drop-shadow(0 0 5px darkviolet);
|
||||||
|
-webkit-filter: drop-shadow(0 0 5px darkviolet);
|
||||||
|
}
|
||||||
|
|
||||||
#cb_names .cb-names-vs {
|
#cb_names .cb-names-vs {
|
||||||
padding-left: 0.25em;
|
padding-left: 0.25em;
|
||||||
padding-right: 0.25em;
|
padding-right: 0.25em;
|
||||||
|
|
@ -474,6 +526,43 @@ button#settings, button#cb_choose_game {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cb-private .cb-hide-if-private {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cb-show-if-private {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cb-private .cb-show-if-private {
|
||||||
|
display: initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.hbox {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: stretch;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.private-link {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
margin: 0.1em;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.private-link:visited {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.private-link:hover {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jBox-wrapper.jBox-hasTitle > .jBox-container {
|
||||||
|
padding: 4px; /* same as border-radius */
|
||||||
|
}
|
||||||
|
|
||||||
.jBox-title h2 {
|
.jBox-title h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -520,10 +609,13 @@ button#settings, button#cb_choose_game {
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-tiles {
|
.game-tiles {
|
||||||
max-width: 80vw;
|
width: calc(100vw - 6rem);
|
||||||
max-height: 80vh;
|
max-width: calc(100vw - 6rem);
|
||||||
overflow-y: auto;
|
max-height: calc(100vh - 12rem);
|
||||||
text-align: center;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(15em, auto));
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-tiles > * {
|
.game-tiles > * {
|
||||||
|
|
@ -532,14 +624,14 @@ button#settings, button#cb_choose_game {
|
||||||
|
|
||||||
.game-tile {
|
.game-tile {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 14em;
|
width: 14em;
|
||||||
height: 14em;
|
height: 14em;
|
||||||
box-shadow: 0 0 0 1px black, 5px 5px 3px #00000080;
|
box-shadow: 0 0 0 1px black, 5px 5px 3px #00000080;
|
||||||
margin: 1em;
|
margin: 0.5em;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
border-radius: 6pt;
|
border-radius: 6pt;
|
||||||
background-color: #FFFFF0;
|
background-color: #FFFFF0;
|
||||||
|
|
@ -572,6 +664,7 @@ button#settings, button#cb_choose_game {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
text-shadow: 2px 2px 4px #000000c0;
|
text-shadow: 2px 2px 4px #000000c0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-game-text::before {
|
.new-game-text::before {
|
||||||
|
|
@ -694,19 +787,19 @@ button#settings, button#cb_choose_game {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-tile {
|
.game-tiles {
|
||||||
font-size: calc(12in * 0.015);
|
font-size: calc(12in * 0.014);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (min-width: 6in) and (max-width: 12in) {
|
@media only screen and (min-width: 6in) and (max-width: 12in) {
|
||||||
.game-tile {
|
.game-tiles {
|
||||||
font-size: 1.5vw;
|
font-size: 1.4vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 6in) {
|
@media only screen and (max-width: 6in) {
|
||||||
.game-tile {
|
.game-tiles {
|
||||||
font-size: calc(6in * 0.015);
|
font-size: calc(6in * 0.014);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
22
index.html
22
index.html
|
|
@ -1,3 +1,4 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
@ -17,10 +18,10 @@
|
||||||
<div id="board_ui">
|
<div id="board_ui">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<button id="settings" title="Settings" type="button"><span class="fas fa-cog"></span></button>
|
<button id="settings" title="Settings" type="button"><span class="fas fa-cog"></span></button>
|
||||||
<button id="cb_choose_game" title="Choose Game" type="button"><span class="fas fa-list"></span></button>
|
<button id="cb_choose_game" title="Choose Game" type="button" class="cb-hide-if-private"><span class="fas fa-list"></span></button>
|
||||||
<h1>Paco Ŝako</h1>
|
<h1>Paco Ŝako<span class="cb-show-if-private" style="display: none"> - Private Mode</span></h1>
|
||||||
<div class="checkbox-container"><input id="cb_reverse" title="Reverse Board" type="checkbox" autocomplete="off" class="image-checkbox fas fa-sync"></div>
|
<div class="checkbox-container"><input id="cb_reverse" title="Reverse Board" type="checkbox" autocomplete="off" class="image-checkbox fas fa-sync"></div>
|
||||||
<div class="checkbox-container"><input id="cb_notify" title="Notify" type="checkbox" autocomplete="off" class="image-checkbox fas fa-bell-slash"></div>
|
<div class="checkbox-container cb-hide-if-private"><input id="cb_notify" title="Notify" type="checkbox" autocomplete="off" class="image-checkbox fas fa-bell-slash"></div>
|
||||||
<button id="help" title="Help" type="button"><span class="fas fa-question-circle"></span></button>
|
<button id="help" title="Help" type="button"><span class="fas fa-question-circle"></span></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -149,7 +150,10 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id="cb_status">
|
<div id="cb_status">
|
||||||
<div id="cb_message"></div>
|
<div class="hbox">
|
||||||
|
<div id="cb_message"></div>
|
||||||
|
<div class="cb-hide-if-private"><a class="private-link" target="_blank" title="Open Private Copy"><span class="fas fa-copy"></span></a></div>
|
||||||
|
</div>
|
||||||
<div id="cb_explain_check"></div>
|
<div id="cb_explain_check"></div>
|
||||||
<div id="cb_scrollable">
|
<div id="cb_scrollable">
|
||||||
<div id="cb_history">
|
<div id="cb_history">
|
||||||
|
|
@ -157,13 +161,17 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="cb_names">
|
<div id="cb_names" class="cb-hide-if-private">
|
||||||
<div id="cb_names_text">
|
<div id="cb_names_text">
|
||||||
<input id="cb_light_name" autocomplete="off" placeholder="Light">
|
<input id="cb_light_name" autocomplete="off" placeholder="Light">
|
||||||
<span class="cb-names-vs">vs.</span>
|
<span class="cb-names-vs">vs.</span>
|
||||||
<input id="cb_dark_name" autocomplete="off" placeholder="Dark">
|
<input id="cb_dark_name" autocomplete="off" placeholder="Dark">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="cb_times" class="cb-hide-if-private">
|
||||||
|
<div id="cb_light_time">0:00:00</div>
|
||||||
|
<div id="cb_dark_time">0:00:00</div>
|
||||||
|
</div>
|
||||||
<div id="cb_navigate">
|
<div id="cb_navigate">
|
||||||
<button id="cb_undo" title="Undo" type="button" disabled="true"><span class="fas fa-undo"></span></button>
|
<button id="cb_undo" title="Undo" type="button" disabled="true"><span class="fas fa-undo"></span></button>
|
||||||
<button id="cb_redo" title="Redo" type="button" disabled="true"><span class="fas fa-redo"></span></button>
|
<button id="cb_redo" title="Redo" type="button" disabled="true"><span class="fas fa-redo"></span></button>
|
||||||
|
|
@ -172,8 +180,8 @@
|
||||||
<div class="nav-spacer"></div>
|
<div class="nav-spacer"></div>
|
||||||
<button id="cb_nav_first" title="View First Turn" type="button" disabled="true"><span class="fas fa-fast-backward"></span></button>
|
<button id="cb_nav_first" title="View First Turn" type="button" disabled="true"><span class="fas fa-fast-backward"></span></button>
|
||||||
<button id="cb_nav_prev_turn" title="View Prior Turn" type="button" disabled="true"><span class="fas fa-backward"></span></button>
|
<button id="cb_nav_prev_turn" title="View Prior Turn" type="button" disabled="true"><span class="fas fa-backward"></span></button>
|
||||||
<button id="cb_nav_prev_state" title="View Prior State" type="button" disabled="true"><span class="fas fa-play fa-flip-horizontal"></span></button>
|
<button id="cb_nav_prev_state" title="View Prior Move" type="button" disabled="true"><span class="fas fa-play fa-flip-horizontal"></span></button>
|
||||||
<button id="cb_nav_next_state" title="View Next State" type="button" disabled="true"><span class="fas fa-play"></span></button>
|
<button id="cb_nav_next_state" title="View Next Move" type="button" disabled="true"><span class="fas fa-play"></span></button>
|
||||||
<button id="cb_nav_next_turn" title="View Next Turn" type="button" disabled="true"><span class="fas fa-forward"></span></button>
|
<button id="cb_nav_next_turn" title="View Next Turn" type="button" disabled="true"><span class="fas fa-forward"></span></button>
|
||||||
<button id="cb_nav_last" title="View Current Move" type="button" disabled="true"><span class="fas fa-fast-forward"></span></button>
|
<button id="cb_nav_last" title="View Current Move" type="button" disabled="true"><span class="fas fa-fast-forward"></span></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
1
index.js
1
index.js
|
|
@ -1,5 +1,6 @@
|
||||||
import './css/chess.css';
|
import './css/chess.css';
|
||||||
import './css/theme/pacosako.css';
|
import './css/theme/pacosako.css';
|
||||||
|
import './css/theme/traditional.css';
|
||||||
|
|
||||||
import '@fortawesome/fontawesome-free/css/fontawesome.css';
|
import '@fortawesome/fontawesome-free/css/fontawesome.css';
|
||||||
import '@fortawesome/fontawesome-free/css/solid.css';
|
import '@fortawesome/fontawesome-free/css/solid.css';
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,9 @@ export class Iterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
flatMap(f) {
|
flatMap(f) {
|
||||||
|
if (typeof f === 'undefined') {
|
||||||
|
f = identity;
|
||||||
|
}
|
||||||
const next = this.next;
|
const next = this.next;
|
||||||
let innerNext;
|
let innerNext;
|
||||||
|
|
||||||
|
|
@ -108,7 +111,8 @@ export class Iterator {
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
const iter = y.value.__proto__[Symbol.iterator].call(y.value);
|
const mapped = f(z.value);
|
||||||
|
const iter = mapped.__proto__[Symbol.iterator].call(mapped);
|
||||||
innerNext = iter.next.bind(iter);
|
innerNext = iter.next.bind(iter);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -194,6 +198,6 @@ export class Iterator {
|
||||||
strictlyIncludes(x) {
|
strictlyIncludes(x) {
|
||||||
return this.some(function matches(y) { return y === x; });
|
return this.some(function matches(y) { return y === x; });
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Iterator;
|
export default Iterator;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import {Iterator} from './iterator.js';
|
import {Iterator} from './iterator.js';
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
|
||||||
/* Game states */
|
/* Game states */
|
||||||
const PLAYING = 'playing';
|
const PLAYING = 'playing';
|
||||||
|
|
@ -271,7 +272,7 @@ class Board {
|
||||||
|
|
||||||
function testFunction(getPiece, match) {
|
function testFunction(getPiece, match) {
|
||||||
if (match === undefined) {
|
if (match === undefined) {
|
||||||
return function(here) { return true; }
|
return function(/*here*/) { return true; };
|
||||||
} else if (match === false) {
|
} else if (match === false) {
|
||||||
return function(here) { return getPiece(here) === EMPTY; };
|
return function(here) { return getPiece(here) === EMPTY; };
|
||||||
} else if (match === true) {
|
} else if (match === true) {
|
||||||
|
|
@ -286,7 +287,7 @@ class Board {
|
||||||
const test = function(here) { return testSide(here) && testOther(here); };
|
const test = function(here) { return testSide(here) && testOther(here); };
|
||||||
|
|
||||||
if (this._phantom && this._phantom.side === side) {
|
if (this._phantom && this._phantom.side === side) {
|
||||||
const getPhantom = (here) => this._phantom.type;
|
const getPhantom = (/*here*/) => this._phantom.type;
|
||||||
const testPhantom = testFunction(getPhantom, type);
|
const testPhantom = testFunction(getPhantom, type);
|
||||||
if (testPhantom(PHANTOM)) {
|
if (testPhantom(PHANTOM)) {
|
||||||
yield this._phantom.from;
|
yield this._phantom.from;
|
||||||
|
|
@ -315,8 +316,8 @@ const KNIGHT_DIR =
|
||||||
[-1, -2], [ 1, -2]];
|
[-1, -2], [ 1, -2]];
|
||||||
|
|
||||||
const NBSP = '\u00a0'; /* non-breaking space */
|
const NBSP = '\u00a0'; /* non-breaking space */
|
||||||
const SHY = '\u00ad' /* soft hyphen */
|
const SHY = '\u00ad'; /* soft hyphen */
|
||||||
const ZWSP = '\u200b'; /* zero-width space */
|
/* const ZWSP = '\u200b'; */ /* zero-width space */
|
||||||
|
|
||||||
function addHistory(game) {
|
function addHistory(game) {
|
||||||
const prior = game._undo;
|
const prior = game._undo;
|
||||||
|
|
@ -572,7 +573,30 @@ class Game {
|
||||||
return this._version;
|
return this._version;
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON(style) {
|
||||||
|
function shrinkMove(move) {
|
||||||
|
if (move.resign) {
|
||||||
|
return { side: move.side, resign: true };
|
||||||
|
} else if (move.phantom) {
|
||||||
|
return { side: move.side, phantom: true, to: move.to };
|
||||||
|
} else {
|
||||||
|
return { side: move.side, from: move.from, to: move.to };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style === 'minify') {
|
||||||
|
/* Just the fields that are used by the constructor to replay the game */
|
||||||
|
/* Omits metadata and extra annotation fields */
|
||||||
|
const state = { past: [], future: [], version: this._version };
|
||||||
|
for (const move of this._moves) {
|
||||||
|
state.past.push(shrinkMove(move));
|
||||||
|
}
|
||||||
|
for (const move of this._redo) {
|
||||||
|
state.future.push(shrinkMove(move));
|
||||||
|
}
|
||||||
|
return JSON.stringify(state);
|
||||||
|
}
|
||||||
|
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
past: this._moves,
|
past: this._moves,
|
||||||
future: this._redo,
|
future: this._redo,
|
||||||
|
|
@ -748,8 +772,6 @@ class Game {
|
||||||
/* if a piece has few moves (king, pawn, knight) then just enumerate them */
|
/* if a piece has few moves (king, pawn, knight) then just enumerate them */
|
||||||
/* if movement is more extensive (bishop, rook, queen) then we can do better */
|
/* if movement is more extensive (bishop, rook, queen) then we can do better */
|
||||||
if (type === BISHOP || type === ROOK || type === QUEEN) {
|
if (type === BISHOP || type === ROOK || type === QUEEN) {
|
||||||
const ortho = (type === ROOK || type === QUEEN);
|
|
||||||
const diag = (type === BISHOP || type === QUEEN);
|
|
||||||
const fromIndex = squareIndex(fromSquare);
|
const fromIndex = squareIndex(fromSquare);
|
||||||
const toIndex = squareIndex(to);
|
const toIndex = squareIndex(to);
|
||||||
const rowsDiff = (toIndex >>> 3) - (fromIndex >>> 3);
|
const rowsDiff = (toIndex >>> 3) - (fromIndex >>> 3);
|
||||||
|
|
@ -833,7 +855,7 @@ class Game {
|
||||||
try {
|
try {
|
||||||
sim.move(from, king);
|
sim.move(from, king);
|
||||||
check = diffHistory(this, sim) || true;
|
check = diffHistory(this, sim) || true;
|
||||||
} catch(err) {}
|
} catch(err) {/*ignore*/}
|
||||||
}
|
}
|
||||||
return recordCheck(this, check);
|
return recordCheck(this, check);
|
||||||
}
|
}
|
||||||
|
|
@ -889,7 +911,7 @@ class Game {
|
||||||
try {
|
try {
|
||||||
game2.move(PHANTOM, king);
|
game2.move(PHANTOM, king);
|
||||||
check = diffHistory(this, game2) || true;
|
check = diffHistory(this, game2) || true;
|
||||||
} catch(err) {}
|
} catch(err) {/*ignore*/}
|
||||||
}
|
}
|
||||||
return recordCheck(this, check);
|
return recordCheck(this, check);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ const meta = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const stateListeners = {};
|
const stateListeners = {};
|
||||||
const stateNextId = 1;
|
let stateNextId = 1;
|
||||||
|
|
||||||
/* One-time request, no caching or polling */
|
/* One-time request, no caching or polling */
|
||||||
function getGameState(gameId, retries) {
|
function getGameState(gameId, retries) {
|
||||||
|
|
@ -37,7 +37,7 @@ function getGameState(gameId, retries) {
|
||||||
url: `${API_BASE}/game/${gameId}`,
|
url: `${API_BASE}/game/${gameId}`,
|
||||||
cache: false,
|
cache: false,
|
||||||
timeout: SHORT_TIMEOUT,
|
timeout: SHORT_TIMEOUT,
|
||||||
}).done((data, textStatus, jqXHR) => {
|
}).done((data/*, textStatus, jqXHR*/) => {
|
||||||
resolve(data);
|
resolve(data);
|
||||||
}).fail((jqXHR, textStatus, errorThrown) => {
|
}).fail((jqXHR, textStatus, errorThrown) => {
|
||||||
if ((!jqXHR.status || jqXHR.status < 400 || jqXHR.status > 499) && retries > 0) {
|
if ((!jqXHR.status || jqXHR.status < 400 || jqXHR.status > 499) && retries > 0) {
|
||||||
|
|
@ -63,7 +63,7 @@ function getGameMeta(gameId, retries) {
|
||||||
url: `${API_BASE}/meta/${gameId}`,
|
url: `${API_BASE}/meta/${gameId}`,
|
||||||
cache: false,
|
cache: false,
|
||||||
timeout: SHORT_TIMEOUT,
|
timeout: SHORT_TIMEOUT,
|
||||||
}).done((data, textStatus, jqXHR) => {
|
}).done((data/*, textStatus, jqXHR*/) => {
|
||||||
resolve(data);
|
resolve(data);
|
||||||
}).fail((jqXHR, textStatus, errorThrown) => {
|
}).fail((jqXHR, textStatus, errorThrown) => {
|
||||||
if ((!jqXHR.status || jqXHR.status < 400 || jqXHR.status > 499) && retries > 0) {
|
if ((!jqXHR.status || jqXHR.status < 400 || jqXHR.status > 499) && retries > 0) {
|
||||||
|
|
@ -106,7 +106,7 @@ function onGameUpdate(gameId, callback) {
|
||||||
stopGamePoll(gameId);
|
stopGamePoll(gameId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCachedGame(gameId) {
|
function getCachedGame(gameId) {
|
||||||
|
|
@ -150,7 +150,7 @@ function onMetaUpdate(callback) {
|
||||||
stopMetaPoll();
|
stopMetaPoll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendUpdate(gameId, data, retries) {
|
function sendUpdate(gameId, data, retries) {
|
||||||
|
|
@ -306,7 +306,7 @@ function startGamePoll(gameId, afterTime) {
|
||||||
setConnectionState(game, 'polling');
|
setConnectionState(game, 'polling');
|
||||||
startGamePoll(gameId, afterTime);
|
startGamePoll(gameId, afterTime);
|
||||||
}
|
}
|
||||||
}).fail((jqXHR, textStatus, errorThrown) => {
|
}).fail((/*jqXHR, textStatus, errorThrown*/) => {
|
||||||
if (game.currentRequest === thisRequest) {
|
if (game.currentRequest === thisRequest) {
|
||||||
setConnectionState(game, 'failed');
|
setConnectionState(game, 'failed');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -370,9 +370,9 @@ function startMetaPoll(afterTime) {
|
||||||
const thisRequest = meta.currentRequest = $.ajax({
|
const thisRequest = meta.currentRequest = $.ajax({
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
url: `${API_BASE}/games${!afterTime ? '' : `/poll/${afterTime}`}`,
|
url: `${API_BASE}/games${(afterTime === undefined) ? '' : `/poll/${afterTime}`}`,
|
||||||
cache: false,
|
cache: false,
|
||||||
timeout: afterTime ? LONG_TIMEOUT : SHORT_TIMEOUT,
|
timeout: (afterTime === undefined) ? SHORT_TIMEOUT : LONG_TIMEOUT,
|
||||||
}).done((data, textStatus, jqXHR) => {
|
}).done((data, textStatus, jqXHR) => {
|
||||||
if (meta.currentRequest === thisRequest) {
|
if (meta.currentRequest === thisRequest) {
|
||||||
meta.currentRequest = null;
|
meta.currentRequest = null;
|
||||||
|
|
@ -383,7 +383,7 @@ function startMetaPoll(afterTime) {
|
||||||
setConnectionState('polling');
|
setConnectionState('polling');
|
||||||
startMetaPoll(afterTime);
|
startMetaPoll(afterTime);
|
||||||
}
|
}
|
||||||
}).fail((jqXHR, textStatus, errorThrown) => {
|
}).fail((/*jqXHR, textStatus, errorThrown*/) => {
|
||||||
if (meta.currentRequest === thisRequest) {
|
if (meta.currentRequest === thisRequest) {
|
||||||
setConnectionState('failed');
|
setConnectionState('failed');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import deepEqual from 'deep-equal';
|
||||||
import 'webpack-jquery-ui/draggable';
|
import 'webpack-jquery-ui/draggable';
|
||||||
import 'webpack-jquery-ui/droppable';
|
import 'webpack-jquery-ui/droppable';
|
||||||
import 'webpack-jquery-ui/selectmenu';
|
import 'webpack-jquery-ui/selectmenu';
|
||||||
import 'webpack-jquery-ui/fold-effect';
|
import 'webpack-jquery-ui/clip-effect';
|
||||||
import 'webpack-jquery-ui/css';
|
import 'webpack-jquery-ui/css';
|
||||||
|
|
||||||
import 'jquery-ui-touch-punch';
|
import 'jquery-ui-touch-punch';
|
||||||
|
|
@ -23,6 +23,10 @@ import {Workbox, messageSW} from 'workbox-window';
|
||||||
import {ResizeSensor, ElementQueries} from 'css-element-queries';
|
import {ResizeSensor, ElementQueries} from 'css-element-queries';
|
||||||
ElementQueries.listen();
|
ElementQueries.listen();
|
||||||
|
|
||||||
|
import {Buffer} from 'buffer';
|
||||||
|
import pako from 'pako';
|
||||||
|
import {sprintf} from 'sprintf-js';
|
||||||
|
|
||||||
/* "Waterdrop" by Porphyr (freesound.org/people/Porphyr) / CC BY 3.0 (creativecommons.org/licenses/by/3.0) */
|
/* "Waterdrop" by Porphyr (freesound.org/people/Porphyr) / CC BY 3.0 (creativecommons.org/licenses/by/3.0) */
|
||||||
import Waterdrop from '../mp3/191678__porphyr__waterdrop.mp3';
|
import Waterdrop from '../mp3/191678__porphyr__waterdrop.mp3';
|
||||||
|
|
||||||
|
|
@ -97,7 +101,7 @@ $(function (){
|
||||||
square.hide().appendTo('body').droppable({
|
square.hide().appendTo('body').droppable({
|
||||||
accept: '.cb-piece',
|
accept: '.cb-piece',
|
||||||
disabled: true,
|
disabled: true,
|
||||||
deactivate: function(ev, ui){
|
deactivate: function(/*ev, ui*/) {
|
||||||
$(this).droppable('disable');
|
$(this).droppable('disable');
|
||||||
},
|
},
|
||||||
drop: squareDropDestination,
|
drop: squareDropDestination,
|
||||||
|
|
@ -105,7 +109,7 @@ $(function (){
|
||||||
}
|
}
|
||||||
return square;
|
return square;
|
||||||
} else if (where.match(/^[a-h][1-8]$/)) {
|
} else if (where.match(/^[a-h][1-8]$/)) {
|
||||||
return $('#cb_' + where).first()
|
return $('#cb_' + where).first();
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +143,6 @@ $(function (){
|
||||||
|
|
||||||
function pieceStartMove(piece, event) {
|
function pieceStartMove(piece, event) {
|
||||||
const side = piece.data('side');
|
const side = piece.data('side');
|
||||||
const type = piece.data('type');
|
|
||||||
const from = piece.data('location');
|
const from = piece.data('location');
|
||||||
const legals = currentGame.legalMoves(side, from);
|
const legals = currentGame.legalMoves(side, from);
|
||||||
for (const there of legals) {
|
for (const there of legals) {
|
||||||
|
|
@ -148,7 +151,7 @@ $(function (){
|
||||||
}
|
}
|
||||||
|
|
||||||
const square = cbSquare(there);
|
const square = cbSquare(there);
|
||||||
square.addClass('cb-legal')
|
square.addClass('cb-legal');
|
||||||
if (event === 'drag') {
|
if (event === 'drag') {
|
||||||
square.droppable('enable');
|
square.droppable('enable');
|
||||||
} else if (event === 'click') {
|
} else if (event === 'click') {
|
||||||
|
|
@ -177,7 +180,7 @@ $(function (){
|
||||||
putState();
|
putState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function squareClickDestination(ev, ui) {
|
function squareClickDestination(/*ev, ui*/) {
|
||||||
let selected = $('#cb_board .cb-selected');
|
let selected = $('#cb_board .cb-selected');
|
||||||
if (selected.length !== 1) {
|
if (selected.length !== 1) {
|
||||||
renderBoard();
|
renderBoard();
|
||||||
|
|
@ -196,11 +199,11 @@ $(function (){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function squareClickUnselect(ev, ui) {
|
function squareClickUnselect(/*ev, ui*/) {
|
||||||
renderBoard();
|
renderBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
function squareClickSelect(ev, ui) {
|
function squareClickSelect(/*ev, ui*/) {
|
||||||
renderBoard();
|
renderBoard();
|
||||||
const clicked = $(this).children('.cb-piece.ui-draggable').not('.ui-draggable-disabled');
|
const clicked = $(this).children('.cb-piece.ui-draggable').not('.ui-draggable-disabled');
|
||||||
clicked.addClass('cb-selected');
|
clicked.addClass('cb-selected');
|
||||||
|
|
@ -214,7 +217,7 @@ $(function (){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function pieceStartDrag(ev, ui) {
|
function pieceStartDrag(/*ev, ui*/) {
|
||||||
const dragged = $(this);
|
const dragged = $(this);
|
||||||
$('#cb_board .cb-selected').removeClass('cb-selected');
|
$('#cb_board .cb-selected').removeClass('cb-selected');
|
||||||
$('#cb_board .cb-legal').removeClass('cb-legal');
|
$('#cb_board .cb-legal').removeClass('cb-legal');
|
||||||
|
|
@ -223,7 +226,7 @@ $(function (){
|
||||||
pieceStartMove(dragged, 'drag');
|
pieceStartMove(dragged, 'drag');
|
||||||
}
|
}
|
||||||
|
|
||||||
function pieceStopDrag(ev, ui) {
|
function pieceStopDrag(/*ev, ui*/) {
|
||||||
const dragged = $(this);
|
const dragged = $(this);
|
||||||
dragged.attr('style', dragged.data('saved-style'));
|
dragged.attr('style', dragged.data('saved-style'));
|
||||||
dragged.removeData('saved-style');
|
dragged.removeData('saved-style');
|
||||||
|
|
@ -252,6 +255,81 @@ $(function (){
|
||||||
return piece;
|
return piece;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updatePlayerTimes() {
|
||||||
|
let lightTime = 0;
|
||||||
|
let darkTime = 0;
|
||||||
|
|
||||||
|
let moveStartTime = undefined;
|
||||||
|
|
||||||
|
for (const move of visibleGame.moves) {
|
||||||
|
if (!move.meta || !Number.isInteger(move.meta.timestamp)) {
|
||||||
|
lightTime = darkTime = undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move.replaced) {
|
||||||
|
/* not the final move in the chain */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start counting when the dark player finishes their first move */
|
||||||
|
if (moveStartTime === undefined) {
|
||||||
|
if (move.side === PS.DARK) {
|
||||||
|
moveStartTime = move.meta.timestamp;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveTime = move.meta.timestamp - moveStartTime;
|
||||||
|
|
||||||
|
if (moveTime > 0) {
|
||||||
|
if (move.side === PS.LIGHT) {
|
||||||
|
lightTime += moveTime;
|
||||||
|
} else {
|
||||||
|
darkTime += moveTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moveStartTime = move.meta.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moveStartTime === undefined) {
|
||||||
|
$('#cb_light_time, #cb_dark_time').text('0:00:00');
|
||||||
|
$('#cb_times').addClass('cb-hide-times');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visibleGame.status === PS.PLAYING) {
|
||||||
|
if (!visibleGame.canRedo) {
|
||||||
|
const currentMoveTime = +new Date() - moveStartTime;
|
||||||
|
if (currentMoveTime > 0) {
|
||||||
|
if (visibleGame.player === PS.LIGHT) {
|
||||||
|
lightTime += currentMoveTime;
|
||||||
|
} else {
|
||||||
|
darkTime += currentMoveTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#cb_times').removeClass('cb-hide-times');
|
||||||
|
|
||||||
|
function formatTime(milliseconds) {
|
||||||
|
let seconds = milliseconds / 1000;
|
||||||
|
const hours = seconds / 3600;
|
||||||
|
seconds %= 3600;
|
||||||
|
const minutes = seconds / 60;
|
||||||
|
seconds %= 60;
|
||||||
|
return sprintf('%d:%02d:%02d', hours, minutes, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#cb_light_time').text(formatTime(lightTime));
|
||||||
|
$('#cb_dark_time').text(formatTime(darkTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(() => { updatePlayerTimes(); }, 250);
|
||||||
|
|
||||||
function renderBoard(animate) {
|
function renderBoard(animate) {
|
||||||
$('#cb_board').removeData('dragging_from');
|
$('#cb_board').removeData('dragging_from');
|
||||||
$('#cb_board .cb-piece').remove();
|
$('#cb_board .cb-piece').remove();
|
||||||
|
|
@ -262,6 +340,8 @@ $(function (){
|
||||||
$('#cb_board .cb-end').removeClass('cb-end');
|
$('#cb_board .cb-end').removeClass('cb-end');
|
||||||
$('#cb_board .cb-legal').removeClass('cb-legal');
|
$('#cb_board .cb-legal').removeClass('cb-legal');
|
||||||
$('#cb_explain_check').text('');
|
$('#cb_explain_check').text('');
|
||||||
|
$('#cb_names').removeClass('cb-light-turn').removeClass('cb-dark-turn');
|
||||||
|
$('#cb_names').removeClass('cb-light-won').removeClass('cb-dark-won');
|
||||||
$('#cb_phantom').remove();
|
$('#cb_phantom').remove();
|
||||||
|
|
||||||
const game = visibleGame;
|
const game = visibleGame;
|
||||||
|
|
@ -340,7 +420,7 @@ $(function (){
|
||||||
pieceStartMove(piece, 'click');
|
pieceStartMove(piece, 'click');
|
||||||
}
|
}
|
||||||
} else if (liveView && playing) {
|
} else if (liveView && playing) {
|
||||||
const pieces = $('#cb_board .' + clss)
|
const pieces = $('#cb_board .' + clss);
|
||||||
pieces.parent().on('click.select', squareClickSelect);
|
pieces.parent().on('click.select', squareClickSelect);
|
||||||
pieces.draggable('enable');
|
pieces.draggable('enable');
|
||||||
}
|
}
|
||||||
|
|
@ -387,6 +467,20 @@ $(function (){
|
||||||
} else {
|
} else {
|
||||||
$('#cb_board').removeClass('cb-live').addClass('cb-archive');
|
$('#cb_board').removeClass('cb-live').addClass('cb-archive');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (game.status === PS.PLAYING) {
|
||||||
|
if (game.player === PS.LIGHT) {
|
||||||
|
$('#cb_names').addClass('cb-light-turn');
|
||||||
|
} else {
|
||||||
|
$('#cb_names').addClass('cb-dark-turn');
|
||||||
|
}
|
||||||
|
} else if (game.winner === PS.LIGHT) {
|
||||||
|
$('#cb_names').addClass('cb-light-won');
|
||||||
|
} else if (game.winner === PS.DARK) {
|
||||||
|
$('#cb_names').addClass('cb-dark-won');
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePlayerTimes();
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyTheme(theme) {
|
function applyTheme(theme) {
|
||||||
|
|
@ -409,6 +503,14 @@ $(function (){
|
||||||
function setCurrentGame(game, animate) {
|
function setCurrentGame(game, animate) {
|
||||||
currentGame = game;
|
currentGame = game;
|
||||||
setVisibleGame(game, animate);
|
setVisibleGame(game, animate);
|
||||||
|
const state = game.toJSON('minify');
|
||||||
|
const deflated = pako.deflate(Buffer.from(state));
|
||||||
|
const encoded = Buffer.from(deflated).toString('base64');
|
||||||
|
if ($('#page').hasClass('cb-private')) {
|
||||||
|
history.replaceState(null, document.title, `#/private/${encoded}`);
|
||||||
|
} else {
|
||||||
|
$('.private-link').attr('href', `#/private/${encoded}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function randomId(){
|
function randomId(){
|
||||||
|
|
@ -463,9 +565,10 @@ $(function (){
|
||||||
head: 0, /* next item to be sent */
|
head: 0, /* next item to be sent */
|
||||||
tail: 0, /* ID to assign to the next update added to the queue */
|
tail: 0, /* ID to assign to the next update added to the queue */
|
||||||
sending: false,
|
sending: false,
|
||||||
|
idle: Promise.resolve(true), /* resolves to true if updates succeeded */
|
||||||
|
signal_idle: function() {},
|
||||||
|
|
||||||
add(gameId, data, modified) {
|
add(gameId, data, modified) {
|
||||||
const wasEmpty = this.isEmpty();
|
|
||||||
data = Object.assign({}, data, { modified });
|
data = Object.assign({}, data, { modified });
|
||||||
|
|
||||||
this[this.tail] = { gameId, data };
|
this[this.tail] = { gameId, data };
|
||||||
|
|
@ -474,6 +577,9 @@ $(function (){
|
||||||
if (!this.sending) {
|
if (!this.sending) {
|
||||||
openNoticeBox('Saving...');
|
openNoticeBox('Saving...');
|
||||||
this.sending = true;
|
this.sending = true;
|
||||||
|
this.idle = new Promise((resolve) => {
|
||||||
|
this.signal_idle = resolve;
|
||||||
|
});
|
||||||
this.sendNext();
|
this.sendNext();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -543,6 +649,7 @@ $(function (){
|
||||||
|
|
||||||
if (queue.isEmpty()) {
|
if (queue.isEmpty()) {
|
||||||
queue.sending = false;
|
queue.sending = false;
|
||||||
|
queue.signal_idle(true);
|
||||||
/* close the Saving... notice*/
|
/* close the Saving... notice*/
|
||||||
noticeBox.close({ ignoreDelay: true });
|
noticeBox.close({ ignoreDelay: true });
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -559,6 +666,7 @@ $(function (){
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.sending = false;
|
queue.sending = false;
|
||||||
|
queue.signal_idle(false);
|
||||||
|
|
||||||
/* force a reset back to the latest server data */
|
/* force a reset back to the latest server data */
|
||||||
if (update.gameId === $('#cb_board').data('gameId')) {
|
if (update.gameId === $('#cb_board').data('gameId')) {
|
||||||
|
|
@ -570,7 +678,6 @@ $(function (){
|
||||||
|
|
||||||
function putState() {
|
function putState() {
|
||||||
const boardElem = $('#cb_board');
|
const boardElem = $('#cb_board');
|
||||||
const gameId = boardElem.data('gameId');
|
|
||||||
notifyLocalMove(currentGame, boardElem.data('gameId'));
|
notifyLocalMove(currentGame, boardElem.data('gameId'));
|
||||||
putMeta({ board: JSON.parse(currentGame.toJSON()) });
|
putMeta({ board: JSON.parse(currentGame.toJSON()) });
|
||||||
}
|
}
|
||||||
|
|
@ -579,7 +686,12 @@ $(function (){
|
||||||
function player(side) {
|
function player(side) {
|
||||||
return (side === PS.LIGHT ? 'light' : 'dark');
|
return (side === PS.LIGHT ? 'light' : 'dark');
|
||||||
}
|
}
|
||||||
|
|
||||||
const gameId = $('#cb_board').data('gameId');
|
const gameId = $('#cb_board').data('gameId');
|
||||||
|
if (gameId === 'private') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const lightName = $('#cb_light_name').val();
|
const lightName = $('#cb_light_name').val();
|
||||||
const darkName = $('#cb_dark_name').val();
|
const darkName = $('#cb_dark_name').val();
|
||||||
const turns = currentGame.turns;
|
const turns = currentGame.turns;
|
||||||
|
|
@ -642,36 +754,49 @@ $(function (){
|
||||||
$('#cb_light_name').val('');
|
$('#cb_light_name').val('');
|
||||||
$('#cb_dark_name').val('');
|
$('#cb_dark_name').val('');
|
||||||
|
|
||||||
cancelGameCallback = IO.onGameUpdate(newId, function(data, gameId) {
|
if (newId === 'private') {
|
||||||
if (data.modified > $('#cb_board').data('modified')) {
|
cancelGameCallback = function() {};
|
||||||
try {
|
} else {
|
||||||
const newGame = new PS.Game(JSON.stringify(data.board));
|
cancelGameCallback = IO.onGameUpdate(newId, function(data/*, gameId*/) {
|
||||||
const newState = JSON.parse(newGame.toJSON());
|
updateQueue.idle.then(() => {
|
||||||
const oldState = JSON.parse(currentGame.toJSON());
|
if (data.modified > $('#cb_board').data('modified')) {
|
||||||
|
try {
|
||||||
|
const newGame = new PS.Game(JSON.stringify(data.board));
|
||||||
|
const newState = JSON.parse(newGame.toJSON());
|
||||||
|
const oldState = JSON.parse(currentGame.toJSON());
|
||||||
|
|
||||||
if (!deepEqual(newState, oldState)) {
|
if (!deepEqual(newState, oldState)) {
|
||||||
debug('got board', newGame.moves);
|
debug('got board', newGame.moves);
|
||||||
setCurrentGame(newGame, newGame.moves.length > currentGame.moves.length);
|
setCurrentGame(newGame, newGame.moves.length > currentGame.moves.length);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
debug('Error parsing board data', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const d = data || {};
|
||||||
|
$('#cb_board').data('lightName', shortenName(String(d.lightName || 'Light')));
|
||||||
|
$('#cb_board').data('darkName', shortenName(String(d.darkName || 'Dark')));
|
||||||
|
$('#cb_light_name').val(String(d.lightName || ''));
|
||||||
|
$('#cb_dark_name').val(String(d.darkName || ''));
|
||||||
|
|
||||||
|
$('#cb_board').data('modified', data.modified);
|
||||||
|
|
||||||
|
updateSelectGameMeta(data, newId);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
});
|
||||||
debug('Error parsing board data', err);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
const d = data || {};
|
const notifyList = $('#cb_notify').data('gameList');
|
||||||
$('#cb_board').data('lightName', shortenName(String(d.lightName || 'Light')));
|
const doNotify = notifyList.includes('*') || notifyList.includes(newId);
|
||||||
$('#cb_board').data('darkName', shortenName(String(d.darkName || 'Dark')));
|
setNotifyChecked(doNotify);
|
||||||
$('#cb_light_name').val(String(d.lightName || ''));
|
if (doNotify) {
|
||||||
$('#cb_dark_name').val(String(d.darkName || ''));
|
requestNotify();
|
||||||
|
|
||||||
$('#cb_board').data('modified', data.modified);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
const notifyList = $('#cb_notify').data('gameList');
|
/* Ensure that the selected game is in the list (for new games). */
|
||||||
const doNotify = notifyList.includes('*') || notifyList.includes(newId);
|
if ($('#game_tile_' + newId).length < 1) {
|
||||||
setNotifyChecked(doNotify);
|
updateSelectGameMeta({}, newId);
|
||||||
if (doNotify) {
|
}
|
||||||
requestNotify();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const reverseList = $('#cb_reverse').data('gameList');
|
const reverseList = $('#cb_reverse').data('gameList');
|
||||||
|
|
@ -679,11 +804,6 @@ $(function (){
|
||||||
$('#cb_reverse').prop('checked', doReverse);
|
$('#cb_reverse').prop('checked', doReverse);
|
||||||
arrangeBoard(doReverse);
|
arrangeBoard(doReverse);
|
||||||
|
|
||||||
/* Ensure that the selected game is in the list (for new games). */
|
|
||||||
if ($('#game_tile_' + newId).length < 1) {
|
|
||||||
updateSelectGameMeta({}, newId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is in case the old tile no longer qualifies to be in the list. */
|
/* This is in case the old tile no longer qualifies to be in the list. */
|
||||||
const oldGameTile = $('#game_tile_' + gameId);
|
const oldGameTile = $('#game_tile_' + gameId);
|
||||||
if (oldGameTile.length >= 1) {
|
if (oldGameTile.length >= 1) {
|
||||||
|
|
@ -714,7 +834,7 @@ $(function (){
|
||||||
const notifyAudio = new Audio(Waterdrop);
|
const notifyAudio = new Audio(Waterdrop);
|
||||||
|
|
||||||
function playNotifySound(){
|
function playNotifySound(){
|
||||||
try { notifyAudio.play(); } catch (err) {}
|
try { notifyAudio.play(); } catch (err) {/*ignore*/}
|
||||||
}
|
}
|
||||||
|
|
||||||
function notify(body) {
|
function notify(body) {
|
||||||
|
|
@ -747,7 +867,7 @@ $(function (){
|
||||||
notification.close();
|
notification.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {}
|
} catch (err) {/*ignore*/}
|
||||||
}
|
}
|
||||||
|
|
||||||
function arrangeBoard(reversed) {
|
function arrangeBoard(reversed) {
|
||||||
|
|
@ -777,33 +897,43 @@ $(function (){
|
||||||
|
|
||||||
Promise.resolve().then(async () => {
|
Promise.resolve().then(async () => {
|
||||||
const wb = new Workbox('sw.js');
|
const wb = new Workbox('sw.js');
|
||||||
|
let latest_sw = null;
|
||||||
|
|
||||||
function showSkipWaitingPrompt(event) {
|
function showSkipWaitingPrompt(event) {
|
||||||
if (confirmBox) {
|
latest_sw = event.sw;
|
||||||
confirmBox.close({ ignoreDelay: true });
|
|
||||||
|
if (!confirmBox) {
|
||||||
|
confirmBox = new jBox('Confirm', {
|
||||||
|
attach: null,
|
||||||
|
content: "A new version is available. Update the page?",
|
||||||
|
confirmButton: `<span class="update-confirm-button">Update</span>`,
|
||||||
|
cancelButton: 'Not now',
|
||||||
|
closeOnConfirm: false,
|
||||||
|
async confirm() {
|
||||||
|
/* The SW should signal us to reload, but do it after 20s regardless. */
|
||||||
|
setTimeout(() => { window.location.reload(); }, 20000);
|
||||||
|
messageSW(latest_sw, {type: 'SKIP_WAITING'});
|
||||||
|
$('.update-confirm-button').text('Updating…');
|
||||||
|
},
|
||||||
|
onClose() {
|
||||||
|
if (confirmBox === this) {
|
||||||
|
confirmBox = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onCloseComplete() {
|
||||||
|
this.destroy();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
confirmBox.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmBox = new jBox('Confirm', {
|
|
||||||
attach: null,
|
|
||||||
content: "A new version is available. Update the page?",
|
|
||||||
confirmButton: `<span class="update-confirm-button">Update</span>`,
|
|
||||||
cancelButton: 'Not now',
|
|
||||||
closeOnConfirm: false,
|
|
||||||
confirm() {
|
|
||||||
/* The SW should signal us to reload, but do it after 20s regardless. */
|
|
||||||
setTimeout(() => { window.location.reload(); }, 20000);
|
|
||||||
messageSW(event.sw, {type: 'SKIP_WAITING'});
|
|
||||||
$('.update-confirm-button').text('Updating…');
|
|
||||||
},
|
|
||||||
onCloseComplete() {
|
|
||||||
this.destroy();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
confirmBox.open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wb.addEventListener('installed', (event) => {
|
function reloadForUpdate(/*event*/) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
wb.addEventListener('installed', (/*event*/) => {
|
||||||
try {
|
try {
|
||||||
if (Notification.permission === 'denied') {
|
if (Notification.permission === 'denied') {
|
||||||
disableNotify();
|
disableNotify();
|
||||||
|
|
@ -813,23 +943,19 @@ $(function (){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
wb.addEventListener('controlling', (event) => {
|
|
||||||
if (event.isUpdate) {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
wb.addEventListener('waiting', showSkipWaitingPrompt);
|
wb.addEventListener('waiting', showSkipWaitingPrompt);
|
||||||
wb.addEventListener('externalwaiting', showSkipWaitingPrompt);
|
wb.addEventListener('externalwaiting', showSkipWaitingPrompt);
|
||||||
|
|
||||||
const registration = await wb.register();
|
wb.addEventListener('controlling', reloadForUpdate);
|
||||||
|
wb.addEventListener('externalactivated', reloadForUpdate);
|
||||||
|
|
||||||
if ('update' in registration) {
|
const registration = await wb.register();
|
||||||
/* Check for updates every 4h without reloading the page. */
|
await registration.ready;
|
||||||
setInterval(() => { registration.update(); }, 4*3600*1000);
|
|
||||||
} else {
|
/* Check for updates every 4h without reloading the page. */
|
||||||
console.log('service worker update method not supported, disabling update checks');
|
setInterval(() => { wb.update(); }, 4*3600*1000);
|
||||||
}
|
|
||||||
|
window.Admin.workbox = wb;
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.error('failed to register the service worker', err);
|
console.error('failed to register the service worker', err);
|
||||||
disableNotify();
|
disableNotify();
|
||||||
|
|
@ -847,7 +973,7 @@ $(function (){
|
||||||
let gameList = undefined;
|
let gameList = undefined;
|
||||||
const gameId = $('#cb_board').data('gameId');
|
const gameId = $('#cb_board').data('gameId');
|
||||||
if (value === 'on') {
|
if (value === 'on') {
|
||||||
gameList = ['*']
|
gameList = ['*'];
|
||||||
} else if (value === null || value === 'off') {
|
} else if (value === null || value === 'off') {
|
||||||
gameList = [];
|
gameList = [];
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -906,7 +1032,7 @@ $(function (){
|
||||||
applyTheme(value);
|
applyTheme(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
$(window).on('storage', function(event){
|
$(window).on('storage', function(event){
|
||||||
fromStorage(event.originalEvent.key, event.originalEvent.newValue);
|
fromStorage(event.originalEvent.key, event.originalEvent.newValue);
|
||||||
|
|
@ -921,7 +1047,7 @@ $(function (){
|
||||||
$('.cb-square').droppable({
|
$('.cb-square').droppable({
|
||||||
accept: '.cb-piece',
|
accept: '.cb-piece',
|
||||||
disabled: true,
|
disabled: true,
|
||||||
deactivate: function(ev, ui){
|
deactivate: function(/*ev, ui*/){
|
||||||
$(this).droppable('disable');
|
$(this).droppable('disable');
|
||||||
},
|
},
|
||||||
drop: squareDropDestination,
|
drop: squareDropDestination,
|
||||||
|
|
@ -1112,6 +1238,7 @@ $(function (){
|
||||||
|
|
||||||
var selectBoxIntervalID = undefined;
|
var selectBoxIntervalID = undefined;
|
||||||
var selectBox = new jBox('Modal', {
|
var selectBox = new jBox('Modal', {
|
||||||
|
title: '<h2>Recent Games</h2>',
|
||||||
content: gameSelectContent,
|
content: gameSelectContent,
|
||||||
blockScroll: false,
|
blockScroll: false,
|
||||||
blockScrollAdjust: false,
|
blockScrollAdjust: false,
|
||||||
|
|
@ -1181,11 +1308,6 @@ $(function (){
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelectGameMeta(data, gameId) {
|
function updateSelectGameMeta(data, gameId) {
|
||||||
data = Object.assign({}, data, {
|
|
||||||
gameId: gameId || data.gameId,
|
|
||||||
timestamp: data.timestamp || +new Date(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof gameId !== 'string' || !gameId.match(/^[0-9a-f]{16}$/)) {
|
if (typeof gameId !== 'string' || !gameId.match(/^[0-9a-f]{16}$/)) {
|
||||||
debug('invalid game ID', gameId);
|
debug('invalid game ID', gameId);
|
||||||
return;
|
return;
|
||||||
|
|
@ -1195,10 +1317,11 @@ $(function (){
|
||||||
const oldTile = $('#game_tile_' + gameId).first();
|
const oldTile = $('#game_tile_' + gameId).first();
|
||||||
|
|
||||||
if (!data.lightName && !data.darkName && !data.moves && gameId !== currentGameId) {
|
if (!data.lightName && !data.darkName && !data.moves && gameId !== currentGameId) {
|
||||||
oldTile.removeAttr('id');
|
|
||||||
if (oldTile.length >= 1) {
|
if (oldTile.length >= 1) {
|
||||||
|
oldTile.removeAttr('id');
|
||||||
oldTile.hide({
|
oldTile.hide({
|
||||||
effect: "fold",
|
effect: "clip",
|
||||||
|
direction: "horizontal",
|
||||||
complete() {
|
complete() {
|
||||||
oldTile.remove();
|
oldTile.remove();
|
||||||
},
|
},
|
||||||
|
|
@ -1207,6 +1330,13 @@ $(function (){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldTile.length && data.modified && oldTile.data('gameMeta').modified >= data.modified) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = Object.assign({ gameId, timestamp: +new Date(), modified: 0 }, data);
|
||||||
|
delete data.board;
|
||||||
|
|
||||||
const tile = oldTile.length ? oldTile :
|
const tile = oldTile.length ? oldTile :
|
||||||
$(`<div class="game-tile existing-game-tile"></div>`).hide();
|
$(`<div class="game-tile existing-game-tile"></div>`).hide();
|
||||||
tile.attr('id', 'game_tile_' + gameId).data('gameMeta', data).empty();
|
tile.attr('id', 'game_tile_' + gameId).data('gameMeta', data).empty();
|
||||||
|
|
@ -1256,13 +1386,14 @@ $(function (){
|
||||||
$(list).appendTo(gameTiles);
|
$(list).appendTo(gameTiles);
|
||||||
updateTileAges();
|
updateTileAges();
|
||||||
|
|
||||||
tile.show("fold");
|
tile.show({
|
||||||
|
effect: "clip",
|
||||||
|
direction: "horizontal",
|
||||||
|
});
|
||||||
|
|
||||||
selectBox.setContent(gameSelectContent);
|
selectBox.setContent(gameSelectContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
IO.onMetaUpdate(updateSelectGameMeta);
|
|
||||||
|
|
||||||
const lastNotifyState = {};
|
const lastNotifyState = {};
|
||||||
|
|
||||||
function notifyForGame(meta, gameId) {
|
function notifyForGame(meta, gameId) {
|
||||||
|
|
@ -1331,20 +1462,39 @@ $(function (){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IO.onMetaUpdate(notifyForGame);
|
window.onhashchange = function(/*event*/){
|
||||||
|
|
||||||
window.onpopstate = function(event){
|
|
||||||
const foundId = location.hash.match(/^#\/([0-9a-f]{16}\b)/);
|
const foundId = location.hash.match(/^#\/([0-9a-f]{16}\b)/);
|
||||||
if (foundId) {
|
if (foundId) {
|
||||||
switchGameId(foundId[1]);
|
switchGameId(foundId[1]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const foundId = location.hash.match(/^#\/([0-9a-f]{16}\b)/);
|
const foundPrivate = location.hash.match(/^#\/private((\/(.*)?)?)$/);
|
||||||
if (foundId) {
|
if (foundPrivate) {
|
||||||
switchGameId(foundId[1]);
|
switchGameId('private');
|
||||||
|
$('#page').addClass('cb-private');
|
||||||
|
let state;
|
||||||
|
try {
|
||||||
|
const decoded = Buffer.from(foundPrivate[1].slice(1), 'base64');
|
||||||
|
const inflated = pako.inflate(decoded);
|
||||||
|
state = JSON.parse(Buffer.from(inflated).toString());
|
||||||
|
} catch(err) {/*ignore*/}
|
||||||
|
if (state) {
|
||||||
|
setCurrentGame(new PS.Game(JSON.stringify(state)));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switchGameId(randomId());
|
const foundId = location.hash.match(/^#\/([0-9a-f]{16}\b)/);
|
||||||
|
if (foundId) {
|
||||||
|
switchGameId(foundId[1]);
|
||||||
|
} else {
|
||||||
|
switchGameId(randomId());
|
||||||
|
}
|
||||||
|
|
||||||
|
IO.onMetaUpdate(async (meta, gameId) => {
|
||||||
|
await updateQueue.idle;
|
||||||
|
updateSelectGameMeta(meta, gameId);
|
||||||
|
notifyForGame(meta, gameId);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustBoardSize() {
|
function adjustBoardSize() {
|
||||||
|
|
@ -1377,6 +1527,7 @@ $(function (){
|
||||||
$('#header').appendTo('#board_ui');
|
$('#header').appendTo('#board_ui');
|
||||||
$('#cb_status').appendTo('#board_ui');
|
$('#cb_status').appendTo('#board_ui');
|
||||||
$('#cb_names').appendTo('#board_ui');
|
$('#cb_names').appendTo('#board_ui');
|
||||||
|
$('#cb_times').appendTo('#board_ui');
|
||||||
$('#cb_navigate').appendTo('#board_ui');
|
$('#cb_navigate').appendTo('#board_ui');
|
||||||
$('#board_ui').appendTo('#page');
|
$('#board_ui').appendTo('#page');
|
||||||
$('#page').removeClass('vertical-layout').addClass('horizontal-layout');
|
$('#page').removeClass('vertical-layout').addClass('horizontal-layout');
|
||||||
|
|
@ -1385,6 +1536,7 @@ $(function (){
|
||||||
$('#cb_container').appendTo('#board_ui');
|
$('#cb_container').appendTo('#board_ui');
|
||||||
$('#cb_status').appendTo('#board_ui');
|
$('#cb_status').appendTo('#board_ui');
|
||||||
$('#cb_names').appendTo('#board_ui');
|
$('#cb_names').appendTo('#board_ui');
|
||||||
|
$('#cb_times').appendTo('#board_ui');
|
||||||
$('#cb_navigate').appendTo('#board_ui');
|
$('#cb_navigate').appendTo('#board_ui');
|
||||||
$('#board_ui').appendTo('#page');
|
$('#board_ui').appendTo('#page');
|
||||||
$('#page').removeClass('horizontal-layout').addClass('vertical-layout');
|
$('#page').removeClass('horizontal-layout').addClass('vertical-layout');
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "paco-sako",
|
"name": "paco-sako",
|
||||||
"version": "0.7.1",
|
"version": "0.8.7",
|
||||||
"description": "Online version of the Paco Ŝako chess variation",
|
"description": "Online version of the Paco Ŝako chess variation",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"game",
|
"game",
|
||||||
|
|
@ -32,29 +32,34 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"buffer": "^6.0.3",
|
||||||
"copy-webpack-plugin": "^5.1.1",
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"copy-webpack-plugin": "^6.4.1",
|
||||||
"css-element-queries": "^1.2.3",
|
"css-element-queries": "^1.2.3",
|
||||||
"deep-equal": "git+https://jessemcdonald.info/gogs/nybble/node-deep-equal",
|
"deep-equal": "git+https://jessemcdonald.info/gogs/nybble/node-deep-equal",
|
||||||
"extract-loader": "^5.0.1",
|
"extract-loader": "^5.0.1",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.5.2",
|
||||||
"jbox": "^1.2.0",
|
"jbox": "^1.2.0",
|
||||||
"jquery-ui-touch-punch": "^0.2.3",
|
"jquery-ui-touch-punch": "^0.2.3",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"mini-css-extract-plugin": "^0.9.0",
|
"mini-css-extract-plugin": "^1.6.2",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
"optimize-css-assets-webpack-plugin": "^6.0.1",
|
||||||
"svgo": "^1.3.2",
|
"pako": "^2.0.4",
|
||||||
"svgo-loader": "^2.2.1",
|
"sprintf-js": "^1.0.3",
|
||||||
"webpack": "^4.43.0",
|
"svgo": "^2.7.0",
|
||||||
"webpack-cli": "^3.3.11",
|
"svgo-loader": "^3.0.0",
|
||||||
|
"webpack": "^4.46.0",
|
||||||
|
"webpack-cli": "^4.8.0",
|
||||||
"webpack-jquery-ui": "^2.0.1",
|
"webpack-jquery-ui": "^2.0.1",
|
||||||
"workbox-precaching": "^5.1.3",
|
"workbox-precaching": "^6.3.0",
|
||||||
"workbox-routing": "^5.1.3",
|
"workbox-routing": "^6.3.0",
|
||||||
"workbox-strategies": "^5.1.3",
|
"workbox-strategies": "^6.3.0",
|
||||||
"workbox-webpack-plugin": "^5.1.3",
|
"workbox-webpack-plugin": "^6.3.0",
|
||||||
"workbox-window": "^5.1.3"
|
"workbox-window": "^6.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"paco-sako-server": "git+https://jessemcdonald.info/gogs/nybble/paco_sako_server"
|
||||||
},
|
},
|
||||||
"dependencies": {},
|
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"paco-sako-server": "git+https://jessemcdonald.info/gogs/nybble/paco_sako_server"
|
"paco-sako-server": "git+https://jessemcdonald.info/gogs/nybble/paco_sako_server"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
4
sw.js
4
sw.js
|
|
@ -14,3 +14,7 @@ addEventListener('message', (event) => {
|
||||||
skipWaiting();
|
skipWaiting();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', (event) => {
|
||||||
|
event.waitUntil(clients.claim());
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,14 @@ module.exports = {
|
||||||
loader: "svgo-loader",
|
loader: "svgo-loader",
|
||||||
options: {
|
options: {
|
||||||
plugins: [
|
plugins: [
|
||||||
{ cleanupIDs: false }
|
{
|
||||||
|
name: "preset-default",
|
||||||
|
params: {
|
||||||
|
overrides: {
|
||||||
|
cleanupIDs: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -88,9 +95,11 @@ module.exports = {
|
||||||
"window.jQuery": "jquery'",
|
"window.jQuery": "jquery'",
|
||||||
"window.$": "jquery"
|
"window.$": "jquery"
|
||||||
}),
|
}),
|
||||||
new CopyPlugin([
|
new CopyPlugin({
|
||||||
{ from: '.htaccess' },
|
patterns: [
|
||||||
]),
|
{ from: '.htaccess' },
|
||||||
|
],
|
||||||
|
}),
|
||||||
new InjectManifest({
|
new InjectManifest({
|
||||||
swSrc: './sw.js',
|
swSrc: './sw.js',
|
||||||
dontCacheBustURLsMatching: /\.[0-9a-f]{16,}\.\w{2,4}$/,
|
dontCacheBustURLsMatching: /\.[0-9a-f]{16,}\.\w{2,4}$/,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue