vs.
@@ -172,8 +175,8 @@
-
-
+
+
diff --git a/js/pacosako.js b/js/pacosako.js
index 655ebc9..32e3967 100644
--- a/js/pacosako.js
+++ b/js/pacosako.js
@@ -573,7 +573,30 @@ class Game {
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({
past: this._moves,
future: this._redo,
diff --git a/js/pacosako_ui.js b/js/pacosako_ui.js
index 276d271..2d7aca7 100644
--- a/js/pacosako_ui.js
+++ b/js/pacosako_ui.js
@@ -23,6 +23,9 @@ import {Workbox, messageSW} from 'workbox-window';
import {ResizeSensor, ElementQueries} from 'css-element-queries';
ElementQueries.listen();
+import {Buffer} from 'buffer';
+import pako from 'pako';
+
/* "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';
@@ -408,6 +411,14 @@ $(function (){
function setCurrentGame(game, animate) {
currentGame = game;
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(){
@@ -583,7 +594,12 @@ $(function (){
function player(side) {
return (side === PS.LIGHT ? 'light' : 'dark');
}
+
const gameId = $('#cb_board').data('gameId');
+ if (gameId === 'private') {
+ return;
+ }
+
const lightName = $('#cb_light_name').val();
const darkName = $('#cb_dark_name').val();
const turns = currentGame.turns;
@@ -646,38 +662,47 @@ $(function (){
$('#cb_light_name').val('');
$('#cb_dark_name').val('');
- cancelGameCallback = IO.onGameUpdate(newId, function(data/*, gameId*/) {
- updateQueue.idle.then(() => {
- 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 (newId === 'private') {
+ cancelGameCallback = function() {};
+ } else {
+ cancelGameCallback = IO.onGameUpdate(newId, function(data/*, gameId*/) {
+ updateQueue.idle.then(() => {
+ 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)) {
- debug('got board', newGame.moves);
- setCurrentGame(newGame, newGame.moves.length > currentGame.moves.length);
+ if (!deepEqual(newState, oldState)) {
+ debug('got board', newGame.moves);
+ setCurrentGame(newGame, newGame.moves.length > currentGame.moves.length);
+ }
+ } catch (err) {
+ debug('Error parsing board data', err);
}
- } 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);
}
-
- 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);
- }
+ });
});
- });
- const notifyList = $('#cb_notify').data('gameList');
- const doNotify = notifyList.includes('*') || notifyList.includes(newId);
- setNotifyChecked(doNotify);
- if (doNotify) {
- requestNotify();
+ const notifyList = $('#cb_notify').data('gameList');
+ const doNotify = notifyList.includes('*') || notifyList.includes(newId);
+ setNotifyChecked(doNotify);
+ if (doNotify) {
+ requestNotify();
+ }
+
+ /* Ensure that the selected game is in the list (for new games). */
+ if ($('#game_tile_' + newId).length < 1) {
+ updateSelectGameMeta({}, newId);
+ }
}
const reverseList = $('#cb_reverse').data('gameList');
@@ -685,11 +710,6 @@ $(function (){
$('#cb_reverse').prop('checked', 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. */
const oldGameTile = $('#game_tile_' + gameId);
if (oldGameTile.length >= 1) {
@@ -1273,8 +1293,6 @@ $(function (){
selectBox.setContent(gameSelectContent);
}
- IO.onMetaUpdate(updateSelectGameMeta);
-
const lastNotifyState = {};
function notifyForGame(meta, gameId) {
@@ -1343,20 +1361,39 @@ $(function (){
}
}
- IO.onMetaUpdate(notifyForGame);
-
- window.onpopstate = function(/*event*/){
+ window.onhashchange = function(/*event*/){
const foundId = location.hash.match(/^#\/([0-9a-f]{16}\b)/);
if (foundId) {
switchGameId(foundId[1]);
}
};
- const foundId = location.hash.match(/^#\/([0-9a-f]{16}\b)/);
- if (foundId) {
- switchGameId(foundId[1]);
+ const foundPrivate = location.hash.match(/^#\/private((\/(.*)?)?)$/);
+ if (foundPrivate) {
+ 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 {
- 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() {
diff --git a/package.json b/package.json
index 131bc38..310f624 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"lodash": "^4.17.15",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
+ "pako": "^1.0.11",
"svgo": "^1.3.2",
"svgo-loader": "^2.2.1",
"webpack": "^4.43.0",