ssb-chess-mithril 2.0.8 → 2.1.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/README.md +3 -1
- package/package.json +3 -3
- package/ui/game/chat.js +51 -0
- package/ui/game/gameView.js +224 -270
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Correspondence chess built on top of the scuttlebutt platform. More information about scuttlebutt here: https://staltz.com/an-off-grid-social-network.html and [https://www.scuttlebutt.nz/](https://www.scuttlebutt.nz/)
|
|
4
4
|
|
|
5
|
-
It is built to allow it to be integrated into scuttlebutt viewers (such as [patchbay](https://www.github.com/ssbc/patchbay), [patchwork](https://www.github.com/
|
|
5
|
+
It is built to allow it to be integrated into scuttlebutt viewers (such as [patchbay](https://www.github.com/ssbc/patchbay), [patchwork](https://www.github.com/soapdog/patchwork) using [depject](https://github.com/depject/depject) so that they can take care of things like discovering friends to play with, etc.
|
|
6
|
+
|
|
7
|
+
It is currently integrated into this fork of [patchwork](https://github.com/soapdog/patchwork/).
|
|
6
8
|
|
|
7
9
|
### Installation
|
|
8
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssb-chess-mithril",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "An ssb-chess client",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"pull-scroll": "^1.0.9",
|
|
25
25
|
"pull-stream": "^3.6.14",
|
|
26
26
|
"ramda": "^0.25.0",
|
|
27
|
-
"ssb-chess": "4.0.
|
|
28
|
-
"ssb-embedded-chat": "2.0.
|
|
27
|
+
"ssb-chess": "4.0.5",
|
|
28
|
+
"ssb-embedded-chat": "2.0.2"
|
|
29
29
|
}
|
|
30
30
|
}
|
package/ui/game/chat.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
const m = require('mithril')
|
|
3
|
+
const EmbeddedChat = require('ssb-embedded-chat');
|
|
4
|
+
const pull = require('pull-stream')
|
|
5
|
+
|
|
6
|
+
module.exports = function ChatBox(myIdent, dataAccess, situationObservable) {
|
|
7
|
+
return {
|
|
8
|
+
view: () => {
|
|
9
|
+
return m('div', {className: 'ssb-chess-chat'});
|
|
10
|
+
},
|
|
11
|
+
oncreate: function (vNode) {
|
|
12
|
+
const originalSituation = situationObservable();
|
|
13
|
+
this.embeddedChat = makeEmbeddedChat(myIdent, dataAccess, originalSituation);
|
|
14
|
+
vNode.dom.appendChild(this.embeddedChat.getChatboxElement());
|
|
15
|
+
},
|
|
16
|
+
onremove: function() {
|
|
17
|
+
this.embeddedChat.destroy();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function makeEmbeddedChat(myIdent, dataAccess, situation) {
|
|
23
|
+
const config = {
|
|
24
|
+
rootMessageId: situation.gameId,
|
|
25
|
+
chatMessageType: 'chess_chat',
|
|
26
|
+
chatMessageField: 'msg',
|
|
27
|
+
chatboxEnabled: true,
|
|
28
|
+
previousChatId: situation.rematchFrom
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (situation.players[myIdent] != null) {
|
|
32
|
+
config.isPublic = false;
|
|
33
|
+
config.participants = Object.keys(situation.players);
|
|
34
|
+
} else {
|
|
35
|
+
config.isPublic = true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
config.publishPublic = dataAccess.publishPublicChessMessage.bind(dataAccess);
|
|
39
|
+
config.publishPrivate = dataAccess.publishPrivateChessMessage.bind(dataAccess);
|
|
40
|
+
|
|
41
|
+
config.getChatStream = (gameId, live) =>
|
|
42
|
+
pull(dataAccess.allGameMessages(gameId, live), pull.filter(msg => !msg.sync && msg.value && msg.value.content.type == "chess_chat"));
|
|
43
|
+
|
|
44
|
+
config.aboutSelfChangeStream = (since) => dataAccess.aboutSelfChangesUserIds(since);
|
|
45
|
+
|
|
46
|
+
config.getDisplayName = (id, cb) => dataAccess.getPlayerDisplayName(id, cb);
|
|
47
|
+
|
|
48
|
+
const chat = EmbeddedChat(config);
|
|
49
|
+
|
|
50
|
+
return chat;
|
|
51
|
+
}
|
package/ui/game/gameView.js
CHANGED
|
@@ -7,328 +7,282 @@ const computed = require('mutant/computed');
|
|
|
7
7
|
const when = require('mutant/when');
|
|
8
8
|
const { Howl } = require('howler');
|
|
9
9
|
|
|
10
|
-
const EmbeddedChat = require('ssb-embedded-chat');
|
|
11
10
|
const ActionButtons = require('./gameActions');
|
|
12
11
|
const GameHistory = require('./gameHistory');
|
|
13
12
|
const PromotionBox = require('./promote');
|
|
13
|
+
const ChatBox = require('./chat')
|
|
14
14
|
|
|
15
15
|
const PieceGraveyard = require('./PieceGraveyard');
|
|
16
16
|
const NextPreviousButtons = require('./nextGameControl');
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
module.exports = (dataAccess, gameCtrl, observables, settings) => {
|
|
19
|
+
const myIdent = gameCtrl.getMyIdent();
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
const myIdent = gameCtrl.getMyIdent();
|
|
21
|
+
const { situationObservable, gamesWhereMyMove, observableGames } = observables;
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
let chessGround = null;
|
|
24
|
+
const chessGroundObservable = Value();
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
const gameHistory = GameHistory(situationObservable, myIdent);
|
|
27
|
+
const actionButtons = ActionButtons(
|
|
28
|
+
gameCtrl.getMoveCtrl(),
|
|
29
|
+
gameCtrl.getInviteCtrl(),
|
|
30
|
+
myIdent,
|
|
31
|
+
situationObservable,
|
|
32
|
+
);
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
const actionButtons = ActionButtons(
|
|
30
|
-
gameCtrl.getMoveCtrl(),
|
|
31
|
-
gameCtrl.getInviteCtrl(),
|
|
32
|
-
myIdent,
|
|
33
|
-
situationObservable,
|
|
34
|
-
);
|
|
34
|
+
const gameHistoryObs = gameHistory.getMoveSelectedObservable();
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
const pieceGraveOpponent = PieceGraveyard(
|
|
37
|
+
chessGroundObservable,
|
|
38
|
+
situationObservable,
|
|
39
|
+
gameHistoryObs,
|
|
40
|
+
myIdent,
|
|
41
|
+
false,
|
|
42
|
+
);
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const pieceGraveMe = PieceGraveyard(
|
|
45
|
+
chessGroundObservable,
|
|
46
|
+
situationObservable,
|
|
47
|
+
gameHistoryObs,
|
|
48
|
+
myIdent,
|
|
49
|
+
true,
|
|
50
|
+
);
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
chessGroundObservable,
|
|
48
|
-
situationObservable,
|
|
49
|
-
gameHistoryObs,
|
|
50
|
-
myIdent,
|
|
51
|
-
true,
|
|
52
|
-
);
|
|
52
|
+
const nextPrevButtons = NextPreviousButtons(situationObservable, arrowScrollsThroughGameCollection());
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
const rootDir = `${__dirname.replace('/ui/game', '')}/`;
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
const moveSound = new Howl({
|
|
57
|
+
src: [`${rootDir}assets/sounds/Move.mp3`],
|
|
58
|
+
});
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
const captureSound = new Howl({
|
|
61
|
+
src: [`${rootDir}assets/sounds/Capture.mp3`],
|
|
62
|
+
});
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
64
|
+
function arrowScrollsThroughGameCollection() {
|
|
65
|
+
const playerIsPlaying = computed([situationObservable], (situation) => situation.currentPlayerIsInGame());
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
class: 'cg-wrap ssb-chess-board-large',
|
|
87
|
-
id: gameId,
|
|
88
|
-
});
|
|
67
|
+
return when(playerIsPlaying,
|
|
68
|
+
gamesWhereMyMove, observableGames
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function plyToColourToPlay(ply) {
|
|
73
|
+
return ply % 2 === 0 ? 'white' : 'black';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isPromotionMove(cg, dest) {
|
|
77
|
+
return (dest[1] === '8' || dest[1] === '1')
|
|
78
|
+
&& cg.state.pieces[dest]
|
|
79
|
+
&& (cg.state.pieces[dest].role === 'pawn');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function renderBoard(gameId) {
|
|
83
|
+
const chessDom = m('div', {
|
|
84
|
+
class: 'cg-wrap ssb-chess-board-large',
|
|
85
|
+
id: gameId,
|
|
86
|
+
});
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
return m('div', { class: 'ssb-chess-board-area' }, [
|
|
89
|
+
chessDom,
|
|
90
|
+
m(nextPrevButtons)
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function setNotMovable(conf) {
|
|
95
|
+
conf.movable = {};
|
|
96
|
+
conf.movable.color = null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function watchForMoveConfirmation(situation, onConfirm, validMoves) {
|
|
100
|
+
if (!settings.getMoveConfirmation()) {
|
|
101
|
+
// If move confirmation is not enabled, perform the move immediately
|
|
102
|
+
onConfirm();
|
|
103
|
+
return;
|
|
94
104
|
}
|
|
95
105
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
class: 'ssb-chess-chat',
|
|
99
|
-
id: `chat-${gameId}`,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
106
|
+
const confirmedObs = actionButtons.showMoveConfirmation();
|
|
107
|
+
m.redraw();
|
|
102
108
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
const watches = computed(
|
|
110
|
+
[confirmedObs, gameHistory.getMoveSelectedObservable()],
|
|
111
|
+
(confirmed, moveSelected) => ({
|
|
112
|
+
moveConfirmed: confirmed,
|
|
113
|
+
moveSelected,
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
107
116
|
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
// If move confirmation is not enabled, perform the move immediately
|
|
117
|
+
const removeConfirmationListener = watches((value) => {
|
|
118
|
+
if (value.moveConfirmed.confirmed) {
|
|
111
119
|
onConfirm();
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
} else if (value.moveSelected !== 'live' || value.moveConfirmed.confirmed === false) {
|
|
121
|
+
const oldConfig = situationToChessgroundConfig(situation, 'live', validMoves);
|
|
114
122
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const watches = computed(
|
|
119
|
-
[confirmedObs, gameHistory.getMoveSelectedObservable()],
|
|
120
|
-
(confirmed, moveSelected) => ({
|
|
121
|
-
moveConfirmed: confirmed,
|
|
122
|
-
moveSelected,
|
|
123
|
-
}),
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const removeConfirmationListener = watches((value) => {
|
|
127
|
-
if (value.moveConfirmed.confirmed) {
|
|
128
|
-
onConfirm();
|
|
129
|
-
} else if (value.moveSelected !== 'live' || value.moveConfirmed.confirmed === false) {
|
|
130
|
-
const oldConfig = situationToChessgroundConfig(situation, 'live', validMoves);
|
|
131
|
-
|
|
132
|
-
if (value.moveSelected === 'live') {
|
|
133
|
-
chessGround.set(oldConfig);
|
|
134
|
-
}
|
|
123
|
+
if (value.moveSelected === 'live') {
|
|
124
|
+
chessGround.set(oldConfig);
|
|
135
125
|
}
|
|
126
|
+
}
|
|
136
127
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
watchForMoveConfirmation(situation, onConfirmMove, validMoves);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const notMovable = {
|
|
181
|
-
check: false,
|
|
182
|
-
movable: {
|
|
183
|
-
color: null,
|
|
184
|
-
},
|
|
128
|
+
removeConfirmationListener();
|
|
129
|
+
actionButtons.hideMoveConfirmation();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function situationToChessgroundConfig(situation, moveSelected, validMoves) {
|
|
134
|
+
const playerColour = situation.players[myIdent] ? situation.players[myIdent].colour : 'white';
|
|
135
|
+
|
|
136
|
+
const colourToPlay = plyToColourToPlay(situation.ply);
|
|
137
|
+
|
|
138
|
+
const config = {
|
|
139
|
+
fen: situation.fen,
|
|
140
|
+
orientation: playerColour,
|
|
141
|
+
turnColor: colourToPlay,
|
|
142
|
+
ply: situation.ply,
|
|
143
|
+
check: situation.check,
|
|
144
|
+
movable: {
|
|
145
|
+
dests: validMoves,
|
|
146
|
+
free: false,
|
|
147
|
+
color: situation.toMove === myIdent ? playerColour : null,
|
|
148
|
+
events: {
|
|
149
|
+
after: (orig, dest) => {
|
|
150
|
+
if (isPromotionMove(chessGround, dest)) {
|
|
151
|
+
const chessboardDom = document.getElementsByClassName('cg-wrap')[0];
|
|
152
|
+
|
|
153
|
+
PromotionBox(chessboardDom, colourToPlay, dest[0],
|
|
154
|
+
(promotingToPiece) => {
|
|
155
|
+
const onConfirmMove = () => gameCtrl.getMoveCtrl().makeMove(
|
|
156
|
+
situation.gameId,
|
|
157
|
+
orig,
|
|
158
|
+
dest,
|
|
159
|
+
promotingToPiece,
|
|
160
|
+
);
|
|
161
|
+
watchForMoveConfirmation(situation, onConfirmMove);
|
|
162
|
+
}).renderPromotionOptionsOverlay();
|
|
163
|
+
} else {
|
|
164
|
+
const onConfirmMove = () => {
|
|
165
|
+
gameCtrl.getMoveCtrl().makeMove(situation.gameId, orig, dest);
|
|
185
166
|
};
|
|
186
167
|
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
};
|
|
168
|
+
watchForMoveConfirmation(situation, onConfirmMove, validMoves);
|
|
169
|
+
}
|
|
192
170
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
171
|
+
const notMovable = {
|
|
172
|
+
check: false,
|
|
173
|
+
movable: {
|
|
174
|
+
color: null,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
196
177
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
178
|
+
chessGround.set(notMovable);
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
};
|
|
200
183
|
|
|
201
|
-
|
|
184
|
+
if (situation.lastMove) {
|
|
185
|
+
config.lastMove = [situation.lastMove.orig, situation.lastMove.dest];
|
|
202
186
|
}
|
|
203
187
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
newConfig.fen = newSituation.fenHistory[moveNumber];
|
|
207
|
-
|
|
208
|
-
if (moveNumber > 0) {
|
|
209
|
-
newConfig.lastMove = [
|
|
210
|
-
newSituation.origDests[moveNumber - 1].orig,
|
|
211
|
-
newSituation.origDests[moveNumber - 1].dest,
|
|
212
|
-
];
|
|
213
|
-
} else {
|
|
214
|
-
newConfig.lastMove = null;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const colourToPlay = plyToColourToPlay(moveNumber);
|
|
218
|
-
newConfig.turnColor = colourToPlay;
|
|
219
|
-
|
|
220
|
-
newConfig.check = newSituation.isCheckOnMoveNumber(moveNumber);
|
|
188
|
+
if (moveSelected !== 'live') {
|
|
189
|
+
resetConfigToOlderPosition(situation, config, moveSelected);
|
|
221
190
|
}
|
|
222
191
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
rootMessageId: situation.gameId,
|
|
226
|
-
chatMessageType: 'chess_chat',
|
|
227
|
-
chatMessageField: 'msg',
|
|
228
|
-
chatboxEnabled: true,
|
|
229
|
-
previousChatId: situation.rematchFrom
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
if (situation.players[myIdent] != null) {
|
|
233
|
-
config.isPublic = false;
|
|
234
|
-
config.participants = Object.keys(situation.players);
|
|
235
|
-
} else {
|
|
236
|
-
config.isPublic = true;
|
|
237
|
-
}
|
|
192
|
+
return config;
|
|
193
|
+
}
|
|
238
194
|
|
|
239
|
-
|
|
240
|
-
|
|
195
|
+
function resetConfigToOlderPosition(newSituation, newConfig, moveNumber) {
|
|
196
|
+
setNotMovable(newConfig);
|
|
197
|
+
newConfig.fen = newSituation.fenHistory[moveNumber];
|
|
241
198
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
199
|
+
if (moveNumber > 0) {
|
|
200
|
+
newConfig.lastMove = [
|
|
201
|
+
newSituation.origDests[moveNumber - 1].orig,
|
|
202
|
+
newSituation.origDests[moveNumber - 1].dest,
|
|
203
|
+
];
|
|
204
|
+
} else {
|
|
205
|
+
newConfig.lastMove = null;
|
|
206
|
+
}
|
|
248
207
|
|
|
249
|
-
|
|
208
|
+
const colourToPlay = plyToColourToPlay(moveNumber);
|
|
209
|
+
newConfig.turnColor = colourToPlay;
|
|
250
210
|
|
|
251
|
-
|
|
252
|
-
|
|
211
|
+
newConfig.check = newSituation.isCheckOnMoveNumber(moveNumber);
|
|
212
|
+
}
|
|
253
213
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
214
|
+
function playMoveSound(situation, newConfig, cg, moveSelected) {
|
|
215
|
+
if (newConfig.fen !== cg.state.fen && moveSelected !== 0) {
|
|
216
|
+
const pgnMove = moveSelected === 'live' ? situation.pgnMoves[
|
|
217
|
+
situation.pgnMoves.length - 1] : situation.pgnMoves[moveSelected - 1];
|
|
258
218
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
219
|
+
// Hacky way of determining if it's a capture move.
|
|
220
|
+
if (pgnMove.indexOf('x') !== -1) {
|
|
221
|
+
captureSound.play();
|
|
222
|
+
} else {
|
|
223
|
+
moveSound.play();
|
|
265
224
|
}
|
|
266
225
|
}
|
|
226
|
+
}
|
|
267
227
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
view(ctrl) {
|
|
271
|
-
const gameId = atob(ctrl.attrs.gameId);
|
|
272
|
-
|
|
273
|
-
return m('div', {
|
|
274
|
-
class: 'ssb-chess-board-background-blue3 merida ssb-chess-game-layout',
|
|
275
|
-
}, [renderChat(gameId), renderBoard(gameId),
|
|
276
|
-
m('div', { class: 'ssb-chess-history-area' }, [
|
|
277
|
-
m(pieceGraveOpponent),
|
|
278
|
-
m(gameHistory),
|
|
279
|
-
m(actionButtons),
|
|
280
|
-
m(pieceGraveMe)
|
|
281
|
-
])]);
|
|
282
|
-
},
|
|
283
|
-
oncreate(vNode) {
|
|
284
|
-
const gameId = atob(vNode.attrs.gameId);
|
|
285
|
-
const boardDom = document.getElementById(gameId);
|
|
286
|
-
const chatDom = document.getElementById(`chat-${gameId}`);
|
|
287
|
-
|
|
288
|
-
const originalSituation = situationObservable();
|
|
289
|
-
|
|
290
|
-
const config = situationToChessgroundConfig(originalSituation, 'live', {});
|
|
291
|
-
chessGround = Chessground(boardDom, config);
|
|
292
|
-
chessGroundObservable.set(chessGround);
|
|
228
|
+
const Chat = ChatBox(myIdent, dataAccess, situationObservable);
|
|
293
229
|
|
|
294
|
-
|
|
295
|
-
chatDom.appendChild(this.embeddedChat.getChatboxElement());
|
|
230
|
+
return {
|
|
296
231
|
|
|
297
|
-
|
|
298
|
-
|
|
232
|
+
view(ctrl) {
|
|
233
|
+
const gameId = atob(ctrl.attrs.gameId);
|
|
299
234
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
235
|
+
return m('div', {
|
|
236
|
+
class: 'ssb-chess-board-background-blue3 merida ssb-chess-game-layout',
|
|
237
|
+
}, [m(Chat), renderBoard(gameId),
|
|
238
|
+
m('div', { class: 'ssb-chess-history-area' }, [
|
|
239
|
+
m(pieceGraveOpponent),
|
|
240
|
+
m(gameHistory),
|
|
241
|
+
m(actionButtons),
|
|
242
|
+
m(pieceGraveMe)
|
|
243
|
+
])]);
|
|
244
|
+
},
|
|
245
|
+
oncreate(vNode) {
|
|
246
|
+
const gameId = atob(vNode.attrs.gameId);
|
|
247
|
+
const boardDom = document.getElementById(gameId);
|
|
248
|
+
|
|
249
|
+
const originalSituation = situationObservable();
|
|
250
|
+
|
|
251
|
+
const config = situationToChessgroundConfig(originalSituation, 'live', {});
|
|
252
|
+
chessGround = Chessground(boardDom, config);
|
|
253
|
+
chessGroundObservable.set(chessGround);
|
|
254
|
+
|
|
255
|
+
const validMovesObservable = gameCtrl.getMovesFinderCtrl()
|
|
256
|
+
.validMovesForSituationObs(situationObservable);
|
|
257
|
+
|
|
258
|
+
this.removeWatches = watchAll([situationObservable,
|
|
259
|
+
gameHistory.getMoveSelectedObservable(), validMovesObservable],
|
|
260
|
+
(newSituation, moveSelected, validMoves) => {
|
|
261
|
+
const newConfig = situationToChessgroundConfig(newSituation, moveSelected, validMoves);
|
|
262
|
+
|
|
263
|
+
if (settings.getPlaySounds()) {
|
|
264
|
+
playMoveSound(newSituation, newConfig, chessGround, moveSelected);
|
|
265
|
+
}
|
|
311
266
|
|
|
312
|
-
|
|
313
|
-
gameId,
|
|
267
|
+
chessGround.set(newConfig);
|
|
314
268
|
});
|
|
315
|
-
},
|
|
316
|
-
onremove() {
|
|
317
|
-
if (this.removeWatches) {
|
|
318
|
-
this.removeWatches();
|
|
319
|
-
}
|
|
320
269
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
270
|
+
PubSub.publish('viewing_game', {
|
|
271
|
+
gameId,
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
onremove() {
|
|
275
|
+
if (this.removeWatches) {
|
|
276
|
+
this.removeWatches();
|
|
277
|
+
}
|
|
326
278
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
279
|
+
if (chessGround) {
|
|
280
|
+
// Yuck. This has been null for people at this stage before. Perhaps onremove
|
|
281
|
+
// can be called before oncreate in edge cases?
|
|
282
|
+
chessGround.destroy();
|
|
283
|
+
}
|
|
330
284
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
};
|
|
285
|
+
PubSub.publish('exited_game');
|
|
286
|
+
},
|
|
334
287
|
};
|
|
288
|
+
};
|