Compare commits

...

47 Commits

Author SHA1 Message Date
Jesse D. McDonald 21623b24f0 0.8.7 2021-09-26 18:21:16 -05:00
Jesse D. McDonald d2fe0f47c3 update dependencies to latest versions 2021-09-26 18:21:01 -05:00
Jesse D. McDonald f5bd481975 0.8.6 2021-09-26 18:21:01 -05:00
Jesse D. McDonald efe995e247 add <!DOCTYPE html> to index.html to avoid quirks mode 2021-09-26 18:21:01 -05:00
Jesse D. McDonald b553eb434a distinguish between 0 and undefined for afterTime when polling metadata 2021-09-26 18:21:01 -05:00
Jesse D. McDonald 4f72d75642 0.8.5 2020-06-24 21:45:23 -05:00
Jesse D. McDonald a829e7224c minor layout tweaks 2020-06-24 21:45:15 -05:00
Jesse D. McDonald 23202e7a7b 0.8.4 2020-06-22 14:26:52 -05:00
Jesse D. McDonald 06c605344f fix missing CSS import for traditional chess icon theme 2020-06-22 14:26:45 -05:00
Jesse D. McDonald 015447dc57 0.8.3 2020-06-21 23:04:48 -05:00
Jesse D. McDonald 59af2e0a29 fix for missing data when showing tiles for old games 2020-06-21 23:04:33 -05:00
Jesse D. McDonald 8de753aac5 use horizontal clip effect instead of fold 2020-06-21 23:02:51 -05:00
Jesse D. McDonald 0febac8b3c use CSS grid for game selection list 2020-06-21 23:01:34 -05:00
Jesse D. McDonald 2c1892303e 0.8.2 2020-05-21 16:14:59 -05:00
Jesse D. McDonald 0df3a7c647 display cumulative waiting time since each player's first move 2020-05-21 16:14:55 -05:00
Jesse D. McDonald 3bae819cb2 0.8.1 2020-05-20 13:39:38 -05:00
Jesse D. McDonald d020e94ac0 highlight the piece beside the name of the current player or winner 2020-05-20 13:39:29 -05:00
Jesse D. McDonald f2fad336a3 0.8.0 2020-05-14 23:48:24 -05:00
Jesse D. McDonald 6495c49022 add "private copy" feature for client-only exploration of moves 2020-05-14 23:46:14 -05:00
Jesse D. McDonald 6dd6c2e3d6 fix issues reported by eslint 2020-05-12 18:26:05 -05:00
Jesse D. McDonald 04638e650d 0.7.4 2020-05-11 13:04:04 -05:00
Jesse D. McDonald d1439b3f09 fix (maybe) for page not reloading after updating service worker 2020-05-11 13:04:00 -05:00
Jesse D. McDonald 994880f454 0.7.3 2020-05-10 20:20:37 -05:00
Jesse D. McDonald 9795c83583 fix for race between polling and server response after update 2020-05-10 20:20:31 -05:00
Jesse D. McDonald f4318b2464 0.7.2 2020-05-10 17:56:05 -05:00
Jesse D. McDonald fd3a8db71d fix for too much padding in side-panel header 2020-05-10 17:56:00 -05:00
Jesse D. McDonald 994da62aac add -moz-appearance alongside -webkit-appearance (formality) 2020-05-10 17:39:48 -05:00
Jesse D. McDonald 07069e25a8 0.7.1 2020-05-10 17:29:10 -05:00
Jesse D. McDonald 0f3313902c add background & gradient border to side panel 2020-05-10 17:29:06 -05:00
Jesse D. McDonald 5f94e931a0 0.7.0 2020-05-10 15:42:41 -05:00
Jesse D. McDonald cb99962074 completely redesign the user interface 2020-05-10 15:42:23 -05:00
Jesse D. McDonald 8b06a83361 use 11 KiB .mp3 for audio rather than 188 KiB .wav 2020-05-10 11:07:18 -05:00
Jesse D. McDonald 91a7884a4d mark completed feature in roadmap 2020-05-09 13:06:17 -05:00
Jesse D. McDonald 555864b1cf 0.6.1 2020-05-09 13:05:38 -05:00
Jesse D. McDonald a1a9eea758 fix for not notifying on next move after switching game 2020-05-09 13:05:32 -05:00
Jesse D. McDonald 327d7a74bc 0.6.0 2020-05-09 12:54:56 -05:00
Jesse D. McDonald 8621724c40 add notifications for games which are not currently visible 2020-05-09 12:54:49 -05:00
Jesse D. McDonald a523c81f88 fix for dragging from phantom square broken (again) 2020-05-09 12:53:45 -05:00
Jesse D. McDonald 21214dd5df factor the code for the status message out of renderBoard() 2020-05-09 11:30:30 -05:00
Jesse D. McDonald 6f6600c6f4 remember the notify and reverse flags for each game separately 2020-05-09 11:29:25 -05:00
Jesse D. McDonald c2dbd6267c add getGameId() and $ (jQuery) to the Admin object 2020-05-09 10:30:46 -05:00
Jesse D. McDonald aee33bf30e mark completed feature in roadmap 2020-05-08 22:18:47 -05:00
Jesse D. McDonald f314f35e39 0.5.0 2020-05-08 22:15:22 -05:00
Jesse D. McDonald 5873a97d93 remove piece IDs and unused <img> elements; animate click moves 2020-05-08 22:15:11 -05:00
Jesse D. McDonald 56cce3340e prohibit castling through check 2020-05-08 20:52:22 -05:00
Jesse D. McDonald b1caa69920 move (de)serialization into the Game class & add rule versioning 2020-05-08 20:40:48 -05:00
Jesse D. McDonald 503a26eda3 add a project roadmap to track planned future changes 2020-05-08 15:29:44 -05:00
17 changed files with 18931 additions and 6754 deletions

21
.eslintrc.js Normal file
View File

@ -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",
}
};

13
ROADMAP.md Normal file
View File

@ -0,0 +1,13 @@
# Road Map
- [x] Block castling through check (middle square needs to be clear of check).
- [x] Notifications for games other than the currently selected game.
- [ ] Protocol and UI for offering and accepting a draw.
- [ ] In-browser local, private games.
- [ ] Password-protected user accounts.
- [ ] Server-side storage for settings across browsers.
- [ ] Persistent (but changeable) display names.
- [ ] Games "owned" by specific player accounts.
- [ ] Invite specific other players to join new games.
- [ ] Create open games for other players to join.
- [ ] Create games controlled entirely by one player.

View File

@ -2,92 +2,375 @@
box-sizing: border-box; box-sizing: border-box;
} }
html, body, #page {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: white;
}
body { body {
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
#page { body > #page {
position: fixed;
top: 0;
left: 0;
width: 100%; width: 100%;
height: 100vh;
display: flex;
flex-flow: column nowrap;
}
h1 {
font-family: 'Vollkorn', serif;
font-size: 2em;
line-height: 1.4em;
height: 1.4em;
margin-top: 8px;
margin-left: 8px;
margin-bottom: 0;
}
a.plain-link {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
line-height: inherit;
color: inherit;
background-color: inherit;
text-decoration: inherit;
}
.media-button-svg {
width: 12pt;
height: 12pt;
}
button:disabled .silhouette {
fill: #c0c0c0;
}
#content {
display: flex; display: flex;
flex-flow: row nowrap; flex-flow: row nowrap;
} }
#cb_outer2 { #board_ui {
flex: 1 1 auto; display: flex;
flex-flow: column nowrap;
justify-content: stretch;
align-items: center;
width: 100%; width: 100%;
max-width: calc(100vh - (8px + 2.8em + 8px)); height: 100%;
margin-left: 8px; background-color: #FFFFF0;
} }
#cb_outer { #page.horizontal-layout #board_ui {
border-left: 10px solid #C4B28F;
border-image:
linear-gradient(
to right,
#C4B28F,
#F5DEB3 15%,
#C4B28F 45%,
#FFFFF0 80%,
#C4B28F) 1 100%;
}
#header {
display: flex;
flex-flow: row nowrap;
flex: 0 0 auto;
width: 100%; width: 100%;
max-width: calc(100vw - (8px + 24px)); height: 2.5rem;
font-size: 2rem;
line-height: 2.4rem;
margin: 0;
background-image: linear-gradient(#FFFFF0, #F5DEB3);
border-bottom: 1px solid black;
align-items: center;
}
#header > h1 {
font-family: 'Vollkorn', serif;
text-align: center;
font-size: 1.2rem;
line-height: 2.4rem;
margin: 0;
padding: 0;
padding-top: 0.1rem;
height: 2.5rem;
white-space: nowrap;
flex: 1 0 auto;
}
#header > button {
flex: 0 0 auto;
width: 2.5rem;
height: 2.5rem;
border: none;
background: none;
padding: 0;
margin: 0;
}
#header > button:active {
background-image: linear-gradient(#F5DEB3, #FFFFF0);
}
input.image-checkbox {
display: inline-block;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
padding: 0;
margin: 0;
}
input.image-checkbox:checked {
color: #00f;
}
input.image-checkbox:focus {
outline: blue solid medium;
outline: -webkit-focus-ring-color solid medium;
outline-offset: 3px;
}
#header > .checkbox-container {
flex: 0 0 auto;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 2.5rem;
height: 2.5rem;
border: none;
background: none;
}
button#settings, button#cb_choose_game {
border-right: 1px solid #DCC8A1;
}
#header > .checkbox-container, button#help {
border-left: 1px solid #DCC8A1;
} }
#cb_container { #cb_container {
position: relative;
width: 100%; width: 100%;
padding-top: 100%; flex: 1 1 auto;
position: relative;
} }
#cb_inner { #page.horizontal-layout #cb_container {
position: absolute; flex: 0 0.5 auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
} }
#cb_board { #cb_board {
position: relative; position: absolute;
width: 100%;
height: 100%;
border-collapse: collapse; border-collapse: collapse;
border-style: hidden; border-style: hidden;
padding-top: 100%;
box-shadow: 0 0 0 1px black, 2px 2px 4px #00000080; box-shadow: 0 0 0 1px black, 2px 2px 4px #00000080;
border-radius: 6pt; border-radius: 6pt;
overflow: hidden; overflow: hidden;
background-color: #FAEED2; background-color: #FAEED2;
} }
#cb_status {
display: flex;
position: relative;
flex-flow: column nowrap;
width: 100%;
padding-top: 0.25rem;
padding-left: 0.25rem;
padding-right: 0.25rem;
padding-bottom: 0.5rem;
}
#page.horizontal-layout #cb_status {
flex: 1 1 auto;
}
#cb_status::after {
content: '';
display: block;
position: absolute;
width: 100%;
height: 1.5em;
left: 0;
bottom: 0.5rem;
background: linear-gradient(rgba(255,255,240,0),rgba(255,255,240,1));
pointer-events: none;
}
#cb_message {
height: 1.2em;
margin-bottom: 0.1rem;
flex: 1 1 auto;
}
#cb_explain_check {
color: red;
height: 2.4em;
margin-bottom: 0.1em;
}
#cb_scrollable {
flex: 0 0 auto;
overflow: auto;
height: 4.8em;
padding-bottom: 1.2em;
}
#page.horizontal-layout #cb_scrollable {
flex: 1 1 auto;
}
#cb_history {
color: black;
}
#cb_history_future {
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 {
position: relative;
display: flex;
flex-flow: row nowrap;
white-space: nowrap;
justify-content: stretch;
align-items: flex-end;
font-size: 1.5rem;
width: 100%;
height: 3rem;
padding-left: 2rem;
padding-right: 2rem;
}
#cb_names_text {
display: flex;
flex-flow: row nowrap;
white-space: nowrap;
justify-content: stretch;
align-items: baseline;
width: 100%;
z-index: 1;
}
#cb_names::before {
content: '';
display: block;
background-image: url(../svg/pacosako-theme.svg#light_king_left);
background-size: contain;
background-repeat: no-repeat;
position: absolute;
bottom: 0;
left: 0.5rem;
width: 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 {
content: '';
display: block;
background-image: url(../svg/pacosako-theme.svg#dark_king_right);
background-size: contain;
background-repeat: no-repeat;
position: absolute;
bottom: 0;
right: 0.5rem;
width: 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 {
padding-left: 0.25em;
padding-right: 0.25em;
}
#cb_names input {
flex: 1 1 auto;
width: 4em;
background-color: inherit;
border: none;
margin: 2px;
font-size: 1.5rem;
}
#cb_names input:focus {
outline: 1px solid blue;
outline-offset: 2px;
}
#cb_dark_name {
text-align: right;
}
#cb_navigate {
display: flex;
flex-flow: row nowrap;
align-items: stretch;
justify-content: stretch;
border-top: 1px solid black;
background-image: linear-gradient(#FFFFF0, #F5DEB3);
white-space: nowrap;
width: 100%;
flex: 0 1 auto;
font-size: 1.25rem;
}
#cb_navigate .nav-spacer {
flex: 1 1 auto;
min-width: 1rem;
width: 100%;
background: none;
background-color: #DCC8A140;
}
#cb_navigate button {
padding: 0;
margin: 0;
border: none;
width: 2rem;
min-width: 2rem;
min-height: 2rem;
background: none;
font-size: inherit;
}
#cb_navigate button:active {
background-image: linear-gradient(#F5DEB3, #FFFFF0);
}
#cb_navigate > .nav-spacer, #cb_navigate > button {
border-left: 1px solid #DCC8A1;
}
#cb_navigate > .nav-spacer:first-child, #cb_navigate > button:first-child {
border-left: none;
}
#cb_board tr { #cb_board tr {
position: relative; position: relative;
} }
@ -97,163 +380,14 @@ button:disabled .silhouette {
position: relative; position: relative;
} }
#cb_light_name, #cb_dark_name {
width: 8em;
}
#cb_control_container {
display: flex;
flex-flow: column nowrap;
flex: 0 1000 auto;
margin-left: 1em;
width: 100%;
min-width: 24em;
max-height: calc(100vh - (8px + 2.8em));
padding-right: calc(3.25em + 10px);
}
#cb_control_form {
flex: 0 1 auto;
display: flex;
flex-flow: column nowrap;
margin-right: auto;
border-radius: 6pt;
padding: 1.125em;
background-color: #FFFFF0;
box-shadow: 0 0 0 1px black, 2px 2px 4px #00000080;
}
#cb_controls, #cb_theme, #cb_names, #cb_navigate {
white-space: nowrap;
}
#cb_theme, #cb_names, #cb_navigate {
margin-top: 1.125em;
}
#cb_names input {
background-color: inherit;
border: none;
border-bottom: 1px solid black;
margin: 2px;
}
#cb_names input:focus {
outline: 1px solid blue;
outline-offset: 2px;
}
#cb_scrollable {
flex: 1 1000 auto;
padding-bottom: 0.5em;
overflow: auto;
}
#cb_message {
margin-top: 0.5em;
margin-bottom: 1em;
}
#cb_theme {
display: flex;
flex-flow: row nowrap;
align-items: baseline;
}
.cb-spacer {
flex: 1 1 auto;
}
#cb_choose_game {
margin-left: 0.2em;
}
#cb_theme label {
flex: 0 0 auto;
padding-right: 0.2em;
}
#cb_undo {
margin-left: auto;
margin-right: 0.1em;
}
#cb_redo {
margin-left: 0.1em;
margin-right: auto;
}
#cb_resign {
margin-left: 0.1em;
margin-right: 0;
}
#cb_navigate {
display: flex;
flex-flow: row nowrap;
justify-items: center;
justify-content: center;
padding-left: 1em;
}
#cb_navigate button {
margin-left: 0.1em;
margin-right: 0.1em;
}
#cb_navigate button:first-child {
margin-left: 0;
}
#cb_navigate button:last-child {
margin-right: 0;
}
#cb_history {
max-width: 7.5in;
margin-bottom: 0.5em;
}
#cb_history_future {
color: grey;
}
#cb_explain_check {
color: red;
margin-top: 0.5em;
}
.cb-hbox {
display: flex;
flex-flow: row nowrap;
align-items: center;
}
.cb-vbox {
display: flex;
flex-flow: column nowrap;
align-items: center;
}
.cb-align-start {
align-items: start;
}
.cb-align-stretch {
align-items: stretch;
}
.cb-square { .cb-square {
position: relative; position: relative;
width: calc((100% - 16pt) / 8);
height: calc((100% - 16pt) / 8);
border: 1px solid black; border: 1px solid black;
padding: 0; padding: 0;
} }
.cb-horiz-label { .cb-horiz-label {
position: relative; position: relative;
width: calc((100% - 16pt) / 8);
height: 8pt; height: 8pt;
border: 1px solid black; border: 1px solid black;
padding: 0; padding: 0;
@ -261,7 +395,7 @@ button:disabled .silhouette {
.cb-horiz-label div { .cb-horiz-label div {
position: absolute; position: absolute;
top: calc(50% - (1em / 2)); top: calc(50% - 3pt);
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
@ -273,7 +407,6 @@ button:disabled .silhouette {
.cb-vert-label { .cb-vert-label {
position: relative; position: relative;
width: 8pt; width: 8pt;
height: calc((100% - 16pt) / 8);
border: 1px solid black; border: 1px solid black;
padding: 0; padding: 0;
} }
@ -338,20 +471,20 @@ button:disabled .silhouette {
height: 100%; height: 100%;
} }
#cb_phantom .cb-lt-piece, .cb-phantom .cb-lt-piece,
#cb_phantom .cb-dk-piece { .cb-phantom .cb-dk-piece {
top: 5%; top: 5%;
} }
#cb_board #cb_phantom .cb-lt-piece, #cb_board .cb-phantom .cb-lt-piece,
#cb_board.cb-reversed #cb_phantom .cb-dk-piece { #cb_board.cb-reversed .cb-phantom .cb-dk-piece {
left: 15%; left: 15%;
right: auto; right: auto;
clip-path: inset(0 15% 0 0); clip-path: inset(0 15% 0 0);
} }
#cb_board #cb_phantom .cb-dk-piece, #cb_board .cb-phantom .cb-dk-piece,
#cb_board.cb-reversed #cb_phantom .cb-lt-piece { #cb_board.cb-reversed .cb-phantom .cb-lt-piece {
left: auto; left: auto;
right: 15%; right: 15%;
clip-path: inset(0 0 0 15%); clip-path: inset(0 0 0 15%);
@ -393,13 +526,62 @@ button:disabled .silhouette {
z-index: 1; z-index: 1;
} }
.badges { .cb-private .cb-hide-if-private {
position: fixed; display: none !important;
bottom: 5px; }
right: 5px;
margin: 0; .cb-show-if-private {
display: none !important;
}
.cb-private .cb-show-if-private {
display: initial !important;
}
div.hbox {
display: flex; display: flex;
flex-flow: column nowrap; 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 {
margin: 0;
}
.rules {
display: block;
max-width: 80vw;
}
.badges {
position: static;
bottom: auto;
right: auto;
margin-top: 0;
margin-bottom: 0;
margin-left: auto;
margin-right: 5px;
display: flex;
flex-flow: row nowrap;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
} }
@ -409,23 +591,31 @@ button:disabled .silhouette {
} }
.badge img { .badge img {
width: 3em; width: 3rem;
height: 3em; height: 3rem;
opacity: 0.5;
margin: 0; margin: 0;
} }
.badge.game-link-badge img { #cb_theme {
width: 1.8em; display: flex;
height: 1.8em; flex-flow: row nowrap;
margin: 0.6em; align-items: baseline;
margin-top: 1rem;
}
#cb_theme label {
flex: 0 0 auto;
padding-right: 0.2rem;
} }
.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 > * {
@ -434,14 +624,14 @@ button:disabled .silhouette {
.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;
@ -474,6 +664,7 @@ button:disabled .silhouette {
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 {
@ -596,77 +787,46 @@ button:disabled .silhouette {
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);
} }
} }
@media only screen and (max-aspect-ratio: 3/2) { .cb-dk-piece.cb-king { content: url(../svg/pacosako-theme.svg#dark_king_right); }
#content { .cb-dk-piece.cb-queen { content: url(../svg/pacosako-theme.svg#dark_queen_right); }
flex-flow: column nowrap; .cb-dk-piece.cb-bishop { content: url(../svg/pacosako-theme.svg#dark_bishop_right); }
} .cb-dk-piece.cb-knight { content: url(../svg/pacosako-theme.svg#dark_knight_right); }
.cb-dk-piece.cb-rook { content: url(../svg/pacosako-theme.svg#dark_rook_right); }
.cb-dk-piece.cb-pawn { content: url(../svg/pacosako-theme.svg#dark_pawn_right); }
.cb-lt-piece.cb-king { content: url(../svg/pacosako-theme.svg#light_king_left); }
.cb-lt-piece.cb-queen { content: url(../svg/pacosako-theme.svg#light_queen_left); }
.cb-lt-piece.cb-bishop { content: url(../svg/pacosako-theme.svg#light_bishop_left); }
.cb-lt-piece.cb-knight { content: url(../svg/pacosako-theme.svg#light_knight_left); }
.cb-lt-piece.cb-rook { content: url(../svg/pacosako-theme.svg#light_rook_left); }
.cb-lt-piece.cb-pawn { content: url(../svg/pacosako-theme.svg#light_pawn_left); }
#cb_outer2 { .cb-reversed .cb-dk-piece.cb-king { content: url(../svg/pacosako-theme.svg#dark_king_left); }
width: auto; .cb-reversed .cb-dk-piece.cb-queen { content: url(../svg/pacosako-theme.svg#dark_queen_left); }
} .cb-reversed .cb-dk-piece.cb-bishop { content: url(../svg/pacosako-theme.svg#dark_bishop_left); }
.cb-reversed .cb-dk-piece.cb-knight { content: url(../svg/pacosako-theme.svg#dark_knight_left); }
#cb_control_container { .cb-reversed .cb-dk-piece.cb-rook { content: url(../svg/pacosako-theme.svg#dark_rook_left); }
margin-top: 1em; .cb-reversed .cb-dk-piece.cb-pawn { content: url(../svg/pacosako-theme.svg#dark_pawn_left); }
margin-left: 8px; .cb-reversed .cb-lt-piece.cb-king { content: url(../svg/pacosako-theme.svg#light_king_right); }
max-height: none; .cb-reversed .cb-lt-piece.cb-queen { content: url(../svg/pacosako-theme.svg#light_queen_right); }
overflow: visible; .cb-reversed .cb-lt-piece.cb-bishop { content: url(../svg/pacosako-theme.svg#light_bishop_right); }
width: 100%; .cb-reversed .cb-lt-piece.cb-knight { content: url(../svg/pacosako-theme.svg#light_knight_right); }
max-width: calc(100vw - (8px + 24px)); .cb-reversed .cb-lt-piece.cb-rook { content: url(../svg/pacosako-theme.svg#light_rook_right); }
padding-right: 0; .cb-reversed .cb-lt-piece.cb-pawn { content: url(../svg/pacosako-theme.svg#light_pawn_right); }
}
.badges {
position: static;
bottom: auto;
right: auto;
margin-left: auto;
margin-right: 5px;
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
}
}
.cb-dk-piece.cb-king { content: url(../svg/traditional-theme.svg#dark_king_right); }
.cb-dk-piece.cb-queen { content: url(../svg/traditional-theme.svg#dark_queen_right); }
.cb-dk-piece.cb-bishop { content: url(../svg/traditional-theme.svg#dark_bishop_right); }
.cb-dk-piece.cb-knight { content: url(../svg/traditional-theme.svg#dark_knight_right); }
.cb-dk-piece.cb-rook { content: url(../svg/traditional-theme.svg#dark_rook_right); }
.cb-dk-piece.cb-pawn { content: url(../svg/traditional-theme.svg#dark_pawn_right); }
.cb-lt-piece.cb-king { content: url(../svg/traditional-theme.svg#light_king_left); }
.cb-lt-piece.cb-queen { content: url(../svg/traditional-theme.svg#light_queen_left); }
.cb-lt-piece.cb-bishop { content: url(../svg/traditional-theme.svg#light_bishop_left); }
.cb-lt-piece.cb-knight { content: url(../svg/traditional-theme.svg#light_knight_left); }
.cb-lt-piece.cb-rook { content: url(../svg/traditional-theme.svg#light_rook_left); }
.cb-lt-piece.cb-pawn { content: url(../svg/traditional-theme.svg#light_pawn_left); }
.cb-reversed .cb-dk-piece.cb-king { content: url(../svg/traditional-theme.svg#dark_king_left); }
.cb-reversed .cb-dk-piece.cb-queen { content: url(../svg/traditional-theme.svg#dark_queen_left); }
.cb-reversed .cb-dk-piece.cb-bishop { content: url(../svg/traditional-theme.svg#dark_bishop_left); }
.cb-reversed .cb-dk-piece.cb-knight { content: url(../svg/traditional-theme.svg#dark_knight_left); }
.cb-reversed .cb-dk-piece.cb-rook { content: url(../svg/traditional-theme.svg#dark_rook_left); }
.cb-reversed .cb-dk-piece.cb-pawn { content: url(../svg/traditional-theme.svg#dark_pawn_left); }
.cb-reversed .cb-lt-piece.cb-king { content: url(../svg/traditional-theme.svg#light_king_right); }
.cb-reversed .cb-lt-piece.cb-queen { content: url(../svg/traditional-theme.svg#light_queen_right); }
.cb-reversed .cb-lt-piece.cb-bishop { content: url(../svg/traditional-theme.svg#light_bishop_right); }
.cb-reversed .cb-lt-piece.cb-knight { content: url(../svg/traditional-theme.svg#light_knight_right); }
.cb-reversed .cb-lt-piece.cb-rook { content: url(../svg/traditional-theme.svg#light_rook_right); }
.cb-reversed .cb-lt-piece.cb-pawn { content: url(../svg/traditional-theme.svg#light_pawn_right); }
/* vim: set expandtab sw=3 ts=8: */ /* vim: set expandtab sw=3 ts=8: */

25
css/theme/traditional.css Normal file
View File

@ -0,0 +1,25 @@
.cb-theme-traditional .cb-dk-piece.cb-king { content: url(../../svg/traditional-theme.svg#dark_king_right); }
.cb-theme-traditional .cb-dk-piece.cb-queen { content: url(../../svg/traditional-theme.svg#dark_queen_right); }
.cb-theme-traditional .cb-dk-piece.cb-bishop { content: url(../../svg/traditional-theme.svg#dark_bishop_right); }
.cb-theme-traditional .cb-dk-piece.cb-knight { content: url(../../svg/traditional-theme.svg#dark_knight_right); }
.cb-theme-traditional .cb-dk-piece.cb-rook { content: url(../../svg/traditional-theme.svg#dark_rook_right); }
.cb-theme-traditional .cb-dk-piece.cb-pawn { content: url(../../svg/traditional-theme.svg#dark_pawn_right); }
.cb-theme-traditional .cb-lt-piece.cb-king { content: url(../../svg/traditional-theme.svg#light_king_left); }
.cb-theme-traditional .cb-lt-piece.cb-queen { content: url(../../svg/traditional-theme.svg#light_queen_left); }
.cb-theme-traditional .cb-lt-piece.cb-bishop { content: url(../../svg/traditional-theme.svg#light_bishop_left); }
.cb-theme-traditional .cb-lt-piece.cb-knight { content: url(../../svg/traditional-theme.svg#light_knight_left); }
.cb-theme-traditional .cb-lt-piece.cb-rook { content: url(../../svg/traditional-theme.svg#light_rook_left); }
.cb-theme-traditional .cb-lt-piece.cb-pawn { content: url(../../svg/traditional-theme.svg#light_pawn_left); }
.cb-theme-traditional.cb-reversed .cb-dk-piece.cb-king { content: url(../../svg/traditional-theme.svg#dark_king_left); }
.cb-theme-traditional.cb-reversed .cb-dk-piece.cb-queen { content: url(../../svg/traditional-theme.svg#dark_queen_left); }
.cb-theme-traditional.cb-reversed .cb-dk-piece.cb-bishop { content: url(../../svg/traditional-theme.svg#dark_bishop_left); }
.cb-theme-traditional.cb-reversed .cb-dk-piece.cb-knight { content: url(../../svg/traditional-theme.svg#dark_knight_left); }
.cb-theme-traditional.cb-reversed .cb-dk-piece.cb-rook { content: url(../../svg/traditional-theme.svg#dark_rook_left); }
.cb-theme-traditional.cb-reversed .cb-dk-piece.cb-pawn { content: url(../../svg/traditional-theme.svg#dark_pawn_left); }
.cb-theme-traditional.cb-reversed .cb-lt-piece.cb-king { content: url(../../svg/traditional-theme.svg#light_king_right); }
.cb-theme-traditional.cb-reversed .cb-lt-piece.cb-queen { content: url(../../svg/traditional-theme.svg#light_queen_right); }
.cb-theme-traditional.cb-reversed .cb-lt-piece.cb-bishop { content: url(../../svg/traditional-theme.svg#light_bishop_right); }
.cb-theme-traditional.cb-reversed .cb-lt-piece.cb-knight { content: url(../../svg/traditional-theme.svg#light_knight_right); }
.cb-theme-traditional.cb-reversed .cb-lt-piece.cb-rook { content: url(../../svg/traditional-theme.svg#light_rook_right); }
.cb-theme-traditional.cb-reversed .cb-lt-piece.cb-pawn { content: url(../../svg/traditional-theme.svg#light_pawn_right); }

View File

@ -1,3 +1,4 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -14,262 +15,212 @@
</head> </head>
<body> <body>
<div id="page"> <div id="page">
<h1><a href="." class="plain-link">Paco Ŝako</a></h1> <div id="board_ui">
<div id="header">
<div id="content"> <button id="settings" title="Settings" type="button"><span class="fas fa-cog"></span></button>
<div id="cb_outer2"> <button id="cb_choose_game" title="Choose Game" type="button" class="cb-hide-if-private"><span class="fas fa-list"></span></button>
<div id="cb_outer"> <h1>Paco Ŝako<span class="cb-show-if-private" style="display: none"> - Private Mode</span></h1>
<div id="cb_container"> <div class="checkbox-container"><input id="cb_reverse" title="Reverse Board" type="checkbox" autocomplete="off" class="image-checkbox fas fa-sync"></div>
<div id="cb_inner"> <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>
<table id="cb_board" class="noselect"> <button id="help" title="Help" type="button"><span class="fas fa-question-circle"></span></button>
<tr id="cb_row9">
<td id="cb_L9" class="cb-corner"></td>
<td id="cb_a9" class="cb-horiz-label"><div>A</div></td>
<td id="cb_b9" class="cb-horiz-label"><div>B</div></td>
<td id="cb_c9" class="cb-horiz-label"><div>C</div></td>
<td id="cb_d9" class="cb-horiz-label"><div>D</div></td>
<td id="cb_e9" class="cb-horiz-label"><div>E</div></td>
<td id="cb_f9" class="cb-horiz-label"><div>F</div></td>
<td id="cb_g9" class="cb-horiz-label"><div>G</div></td>
<td id="cb_h9" class="cb-horiz-label"><div>H</div></td>
<td id="cb_R9" class="cb-corner"></td>
</tr>
<tr id="cb_row8">
<td id="cb_L8" class="cb-vert-label"><div>8</div></td>
<td id="cb_a8" class="cb-square cb-lt-bg"></td>
<td id="cb_b8" class="cb-square cb-dk-bg"></td>
<td id="cb_c8" class="cb-square cb-lt-bg"></td>
<td id="cb_d8" class="cb-square cb-dk-bg"></td>
<td id="cb_e8" class="cb-square cb-lt-bg"></td>
<td id="cb_f8" class="cb-square cb-dk-bg"></td>
<td id="cb_g8" class="cb-square cb-lt-bg"></td>
<td id="cb_h8" class="cb-square cb-dk-bg"></td>
<td id="cb_R8" class="cb-vert-label"><div>8</div></td>
</tr>
<tr id="cb_row7">
<td id="cb_L7" class="cb-vert-label"><div>7</div></td>
<td id="cb_a7" class="cb-square cb-dk-bg"></td>
<td id="cb_b7" class="cb-square cb-lt-bg"></td>
<td id="cb_c7" class="cb-square cb-dk-bg"></td>
<td id="cb_d7" class="cb-square cb-lt-bg"></td>
<td id="cb_e7" class="cb-square cb-dk-bg"></td>
<td id="cb_f7" class="cb-square cb-lt-bg"></td>
<td id="cb_g7" class="cb-square cb-dk-bg"></td>
<td id="cb_h7" class="cb-square cb-lt-bg"></td>
<td id="cb_R7" class="cb-vert-label"><div>7</div></td>
</tr>
<tr id="cb_row6">
<td id="cb_L6" class="cb-vert-label"><div>6</div></td>
<td id="cb_a6" class="cb-square cb-lt-bg"></td>
<td id="cb_b6" class="cb-square cb-dk-bg"></td>
<td id="cb_c6" class="cb-square cb-lt-bg"></td>
<td id="cb_d6" class="cb-square cb-dk-bg"></td>
<td id="cb_e6" class="cb-square cb-lt-bg"></td>
<td id="cb_f6" class="cb-square cb-dk-bg"></td>
<td id="cb_g6" class="cb-square cb-lt-bg"></td>
<td id="cb_h6" class="cb-square cb-dk-bg"></td>
<td id="cb_R6" class="cb-vert-label"><div>6</div></td>
</tr>
<tr id="cb_row5">
<td id="cb_L5" class="cb-vert-label"><div>5</div></td>
<td id="cb_a5" class="cb-square cb-dk-bg"></td>
<td id="cb_b5" class="cb-square cb-lt-bg"></td>
<td id="cb_c5" class="cb-square cb-dk-bg"></td>
<td id="cb_d5" class="cb-square cb-lt-bg"></td>
<td id="cb_e5" class="cb-square cb-dk-bg"></td>
<td id="cb_f5" class="cb-square cb-lt-bg"></td>
<td id="cb_g5" class="cb-square cb-dk-bg"></td>
<td id="cb_h5" class="cb-square cb-lt-bg"></td>
<td id="cb_R5" class="cb-vert-label"><div>5</div></td>
</tr>
<tr id="cb_row4">
<td id="cb_L4" class="cb-vert-label"><div>4</div></td>
<td id="cb_a4" class="cb-square cb-lt-bg"></td>
<td id="cb_b4" class="cb-square cb-dk-bg"></td>
<td id="cb_c4" class="cb-square cb-lt-bg"></td>
<td id="cb_d4" class="cb-square cb-dk-bg"></td>
<td id="cb_e4" class="cb-square cb-lt-bg"></td>
<td id="cb_f4" class="cb-square cb-dk-bg"></td>
<td id="cb_g4" class="cb-square cb-lt-bg"></td>
<td id="cb_h4" class="cb-square cb-dk-bg"></td>
<td id="cb_R4" class="cb-vert-label"><div>4</div></td>
</tr>
<tr id="cb_row3">
<td id="cb_L3" class="cb-vert-label"><div>3</div></td>
<td id="cb_a3" class="cb-square cb-dk-bg"></td>
<td id="cb_b3" class="cb-square cb-lt-bg"></td>
<td id="cb_c3" class="cb-square cb-dk-bg"></td>
<td id="cb_d3" class="cb-square cb-lt-bg"></td>
<td id="cb_e3" class="cb-square cb-dk-bg"></td>
<td id="cb_f3" class="cb-square cb-lt-bg"></td>
<td id="cb_g3" class="cb-square cb-dk-bg"></td>
<td id="cb_h3" class="cb-square cb-lt-bg"></td>
<td id="cb_R3" class="cb-vert-label"><div>3</div></td>
</tr>
<tr id="cb_row2">
<td id="cb_L2" class="cb-vert-label"><div>2</div></td>
<td id="cb_a2" class="cb-square cb-lt-bg"></td>
<td id="cb_b2" class="cb-square cb-dk-bg"></td>
<td id="cb_c2" class="cb-square cb-lt-bg"></td>
<td id="cb_d2" class="cb-square cb-dk-bg"></td>
<td id="cb_e2" class="cb-square cb-lt-bg"></td>
<td id="cb_f2" class="cb-square cb-dk-bg"></td>
<td id="cb_g2" class="cb-square cb-lt-bg"></td>
<td id="cb_h2" class="cb-square cb-dk-bg"></td>
<td id="cb_R2" class="cb-vert-label"><div>2</div></td>
</tr>
<tr id="cb_row1">
<td id="cb_L1" class="cb-vert-label"><div>1</div></td>
<td id="cb_a1" class="cb-square cb-dk-bg"></td>
<td id="cb_b1" class="cb-square cb-lt-bg"></td>
<td id="cb_c1" class="cb-square cb-dk-bg"></td>
<td id="cb_d1" class="cb-square cb-lt-bg"></td>
<td id="cb_e1" class="cb-square cb-dk-bg"></td>
<td id="cb_f1" class="cb-square cb-lt-bg"></td>
<td id="cb_g1" class="cb-square cb-dk-bg"></td>
<td id="cb_h1" class="cb-square cb-lt-bg"></td>
<td id="cb_R1" class="cb-vert-label"><div>1</div></td>
</tr>
<tr id="cb_row0">
<td id="cb_L0" class="cb-corner"></td>
<td id="cb_a0" class="cb-horiz-label"><div>A</div></td>
<td id="cb_b0" class="cb-horiz-label"><div>B</div></td>
<td id="cb_c0" class="cb-horiz-label"><div>C</div></td>
<td id="cb_d0" class="cb-horiz-label"><div>D</div></td>
<td id="cb_e0" class="cb-horiz-label"><div>E</div></td>
<td id="cb_f0" class="cb-horiz-label"><div>F</div></td>
<td id="cb_g0" class="cb-horiz-label"><div>G</div></td>
<td id="cb_h0" class="cb-horiz-label"><div>H</div></td>
<td id="cb_R0" class="cb-corner"></td>
</tr>
</table>
</div>
</div>
</div>
</div> </div>
<div id="cb_control_container"> <div id="cb_container">
<form id="cb_control_form" autocomplete="off" onsubmit="return false;"> <table id="cb_board" class="noselect cb-theme-pacosako" style="visibility: hidden">
<div id="cb_controls"> <tr id="cb_row9">
<div class="cb-hbox"> <td id="cb_L9" class="cb-corner"></td>
<div class="cb-vbox cb-align-start"> <td id="cb_a9" class="cb-horiz-label"><div>A</div></td>
<div><input id="cb_notify" type="checkbox"><label for="cb_notify">Notify</label></div> <td id="cb_b9" class="cb-horiz-label"><div>B</div></td>
<div><input id="cb_sound" type="checkbox"><label for="cb_sound">Sound</label></div> <td id="cb_c9" class="cb-horiz-label"><div>C</div></td>
<div><input id="cb_reverse" type="checkbox"><label for="cb_reverse">Reverse</label></div> <td id="cb_d9" class="cb-horiz-label"><div>D</div></td>
</div> <td id="cb_e9" class="cb-horiz-label"><div>E</div></td>
<div class="cb-spacer"></div> <td id="cb_f9" class="cb-horiz-label"><div>F</div></td>
<div class="cb-vbox cb-align-stretch"> <td id="cb_g9" class="cb-horiz-label"><div>G</div></td>
<div class="cb-hbox"> <td id="cb_h9" class="cb-horiz-label"><div>H</div></td>
<button id="cb_undo" type="button" disabled="true">Undo</button> <td id="cb_R9" class="cb-corner"></td>
<button id="cb_redo" type="button" disabled="true">Redo</button> </tr>
<button id="cb_resign" type="button" disabled="true">Resign</button> <tr id="cb_row8">
</div> <td id="cb_L8" class="cb-vert-label"><div>8</div></td>
<div id="cb_navigate"> <td id="cb_a8" class="cb-square cb-lt-bg"></td>
<button id="cb_nav_first" title="View First Turn" type="button" disabled="true"> <td id="cb_b8" class="cb-square cb-dk-bg"></td>
<svg viewBox="0 0 144 144" class="media-button-svg silhouette"> <td id="cb_c8" class="cb-square cb-lt-bg"></td>
<path d="M 6 24 H 24 V 120 H 6"/> <td id="cb_d8" class="cb-square cb-dk-bg"></td>
<path d="M 18 72 L 90 24 V 120"/> <td id="cb_e8" class="cb-square cb-lt-bg"></td>
<path d="M 66 72 L 138 24 V 120"/> <td id="cb_f8" class="cb-square cb-dk-bg"></td>
</svg> <td id="cb_g8" class="cb-square cb-lt-bg"></td>
</button> <td id="cb_h8" class="cb-square cb-dk-bg"></td>
<button id="cb_nav_prev_turn" title="View Prior Turn" type="button" disabled="true"> <td id="cb_R8" class="cb-vert-label"><div>8</div></td>
<svg viewBox="0 0 144 144" class="media-button-svg silhouette"> </tr>
<path d="M 12 72 L 84 24 V 120"/> <tr id="cb_row7">
<path d="M 60 72 L 132 24 V 120"/> <td id="cb_L7" class="cb-vert-label"><div>7</div></td>
</svg> <td id="cb_a7" class="cb-square cb-dk-bg"></td>
</button> <td id="cb_b7" class="cb-square cb-lt-bg"></td>
<button id="cb_nav_prev_state" title="View Prior State" type="button" disabled="true"> <td id="cb_c7" class="cb-square cb-dk-bg"></td>
<svg viewBox="0 0 144 144" class="media-button-svg silhouette"> <td id="cb_d7" class="cb-square cb-lt-bg"></td>
<path d="M 36 72 L 108 24 V 120"/> <td id="cb_e7" class="cb-square cb-dk-bg"></td>
</svg> <td id="cb_f7" class="cb-square cb-lt-bg"></td>
</button> <td id="cb_g7" class="cb-square cb-dk-bg"></td>
<button id="cb_nav_next_state" title="View Next State" type="button" disabled="true"> <td id="cb_h7" class="cb-square cb-lt-bg"></td>
<svg viewBox="0 0 144 144" class="media-button-svg silhouette"> <td id="cb_R7" class="cb-vert-label"><div>7</div></td>
<path d="M 108 72 L 36 24 V 120"/> </tr>
</svg> <tr id="cb_row6">
</button> <td id="cb_L6" class="cb-vert-label"><div>6</div></td>
<button id="cb_nav_next_turn" title="View Next Turn" type="button" disabled="true"> <td id="cb_a6" class="cb-square cb-lt-bg"></td>
<svg viewBox="0 0 144 144" class="media-button-svg silhouette"> <td id="cb_b6" class="cb-square cb-dk-bg"></td>
<path d="M 84 72 L 12 24 V 120"/> <td id="cb_c6" class="cb-square cb-lt-bg"></td>
<path d="M 132 72 L 60 24 V 120"/> <td id="cb_d6" class="cb-square cb-dk-bg"></td>
</svg> <td id="cb_e6" class="cb-square cb-lt-bg"></td>
</button> <td id="cb_f6" class="cb-square cb-dk-bg"></td>
<button id="cb_nav_last" title="View Current Move" type="button" disabled="true"> <td id="cb_g6" class="cb-square cb-lt-bg"></td>
<svg viewBox="0 0 144 144" class="media-button-svg silhouette"> <td id="cb_h6" class="cb-square cb-dk-bg"></td>
<path d="M 78 72 L 6 24 V 120"/> <td id="cb_R6" class="cb-vert-label"><div>6</div></td>
<path d="M 126 72 L 54 24 V 120"/> </tr>
<path d="M 138 24 H 120 V 120 H 138"/> <tr id="cb_row5">
</svg> <td id="cb_L5" class="cb-vert-label"><div>5</div></td>
</button> <td id="cb_a5" class="cb-square cb-dk-bg"></td>
</div> <td id="cb_b5" class="cb-square cb-lt-bg"></td>
</div> <td id="cb_c5" class="cb-square cb-dk-bg"></td>
</div> <td id="cb_d5" class="cb-square cb-lt-bg"></td>
</div> <td id="cb_e5" class="cb-square cb-dk-bg"></td>
<div id="cb_theme"> <td id="cb_f5" class="cb-square cb-lt-bg"></td>
<label for="cb_select_theme">Theme:</label> <td id="cb_g5" class="cb-square cb-dk-bg"></td>
<select id="cb_select_theme"> <td id="cb_h5" class="cb-square cb-lt-bg"></td>
<option value="traditional">Traditional</option> <td id="cb_R5" class="cb-vert-label"><div>5</div></td>
<option value="pacosako">Paco Ŝako</option> </tr>
</select> <tr id="cb_row4">
<div class="cb-spacer"></div> <td id="cb_L4" class="cb-vert-label"><div>4</div></td>
<button id="cb_choose_game">Choose Game…</button> <td id="cb_a4" class="cb-square cb-lt-bg"></td>
</div> <td id="cb_b4" class="cb-square cb-dk-bg"></td>
<div id="cb_names"> <td id="cb_c4" class="cb-square cb-lt-bg"></td>
<label for="cb_light_name">Players:</label> <td id="cb_d4" class="cb-square cb-dk-bg"></td>
<input id="cb_light_name" placeholder="Light"> vs. <input id="cb_dark_name" placeholder="Dark"> <td id="cb_e4" class="cb-square cb-lt-bg"></td>
</div> <td id="cb_f4" class="cb-square cb-dk-bg"></td>
</form> <td id="cb_g4" class="cb-square cb-lt-bg"></td>
<div id="cb_message"></div> <td id="cb_h4" class="cb-square cb-dk-bg"></td>
<td id="cb_R4" class="cb-vert-label"><div>4</div></td>
</tr>
<tr id="cb_row3">
<td id="cb_L3" class="cb-vert-label"><div>3</div></td>
<td id="cb_a3" class="cb-square cb-dk-bg"></td>
<td id="cb_b3" class="cb-square cb-lt-bg"></td>
<td id="cb_c3" class="cb-square cb-dk-bg"></td>
<td id="cb_d3" class="cb-square cb-lt-bg"></td>
<td id="cb_e3" class="cb-square cb-dk-bg"></td>
<td id="cb_f3" class="cb-square cb-lt-bg"></td>
<td id="cb_g3" class="cb-square cb-dk-bg"></td>
<td id="cb_h3" class="cb-square cb-lt-bg"></td>
<td id="cb_R3" class="cb-vert-label"><div>3</div></td>
</tr>
<tr id="cb_row2">
<td id="cb_L2" class="cb-vert-label"><div>2</div></td>
<td id="cb_a2" class="cb-square cb-lt-bg"></td>
<td id="cb_b2" class="cb-square cb-dk-bg"></td>
<td id="cb_c2" class="cb-square cb-lt-bg"></td>
<td id="cb_d2" class="cb-square cb-dk-bg"></td>
<td id="cb_e2" class="cb-square cb-lt-bg"></td>
<td id="cb_f2" class="cb-square cb-dk-bg"></td>
<td id="cb_g2" class="cb-square cb-lt-bg"></td>
<td id="cb_h2" class="cb-square cb-dk-bg"></td>
<td id="cb_R2" class="cb-vert-label"><div>2</div></td>
</tr>
<tr id="cb_row1">
<td id="cb_L1" class="cb-vert-label"><div>1</div></td>
<td id="cb_a1" class="cb-square cb-dk-bg"></td>
<td id="cb_b1" class="cb-square cb-lt-bg"></td>
<td id="cb_c1" class="cb-square cb-dk-bg"></td>
<td id="cb_d1" class="cb-square cb-lt-bg"></td>
<td id="cb_e1" class="cb-square cb-dk-bg"></td>
<td id="cb_f1" class="cb-square cb-lt-bg"></td>
<td id="cb_g1" class="cb-square cb-dk-bg"></td>
<td id="cb_h1" class="cb-square cb-lt-bg"></td>
<td id="cb_R1" class="cb-vert-label"><div>1</div></td>
</tr>
<tr id="cb_row0">
<td id="cb_L0" class="cb-corner"></td>
<td id="cb_a0" class="cb-horiz-label"><div>A</div></td>
<td id="cb_b0" class="cb-horiz-label"><div>B</div></td>
<td id="cb_c0" class="cb-horiz-label"><div>C</div></td>
<td id="cb_d0" class="cb-horiz-label"><div>D</div></td>
<td id="cb_e0" class="cb-horiz-label"><div>E</div></td>
<td id="cb_f0" class="cb-horiz-label"><div>F</div></td>
<td id="cb_g0" class="cb-horiz-label"><div>G</div></td>
<td id="cb_h0" class="cb-horiz-label"><div>H</div></td>
<td id="cb_R0" class="cb-corner"></td>
</tr>
</table>
</div>
<div id="cb_status">
<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_scrollable"> <div id="cb_scrollable">
<div id="cb_history"> <div id="cb_history">
<span id="cb_history_past"></span><span id="cb_history_future"></span> <span id="cb_history_past"></span><span id="cb_history_future"></span>
<div id="cb_explain_check"></div>
</div> </div>
<details>
<summary>Rule Reference</summary>
<p>The basic movement for each piece is the same as traditional chess.</p>
<p>Pieces are never removed from the board. Instead, the capturing piece shares the square with the captured piece, and the two pieces become a joined pair.</p>
<p>When either piece moves from a square containing two pieces, the other piece moves with it.
Each player can only move a joined pair according to the rules for their own piece. Joined pieces cannot capture other pieces.</p>
<p>A free (non-joined) piece may move into a square occupied by pieces of both colors.
When it does, the other piece of the same color becomes a free piece and must move to a new location following the normal movement rules.
This process may be repeated multiple times in the same turn.</p>
<p>Ŝako (checkmate) occurs when an opposing piece joins with the king.
<strong>Important:</strong> The king is not permitted to join with (capture) other pieces.</p>
<p>Due to joined movement, it is possible for a pawn to be moved backward to, or past, its starting row.
Pawns may move forward two spaces from either of the first two rows on their own side of the board.</p>
<p>When a pawn is captured <i>en passant</i> while joined with another piece, the captured pawn moves back one square to become joined with the capturing pawn
and the joined piece from the capturing side moves to a new location from its original position as with any other capture.</p>
<p>Pawns are promoted when they reach the final row on the opposite side of the board, even if they were moved there by the other player as part of a joined pair.</p>
</details>
</div> </div>
</div> </div>
</div> <div id="cb_names" class="cb-hide-if-private">
<div id="cb_names_text">
<input id="cb_light_name" autocomplete="off" placeholder="Light">
<span class="cb-names-vs">vs.</span>
<input id="cb_dark_name" autocomplete="off" placeholder="Dark">
</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">
<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>
<div class="nav-spacer"></div>
<button id="cb_resign" title="Resign" type="button" disabled="true"><span class="fas fa-flag"></span></button>
<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_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 Move" type="button" disabled="true"><span class="fas fa-play fa-flip-horizontal"></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_last" title="View Current Move" type="button" disabled="true"><span class="fas fa-fast-forward"></span></button>
</div>
</div> <!-- board_ui -->
</div>
<div id="rules_content" style="display: none">
<div id="rules" class="rules">
<p>The basic movement for each piece is the same as traditional chess.</p>
<p>Pieces are never removed from the board. Instead, the capturing piece shares the square with the captured piece, and the two pieces become a joined pair.</p>
<p>When either piece moves from a square containing two pieces, the other piece moves with it.
Each player can only move a joined pair according to the rules for their own piece. Joined pieces cannot capture other pieces.</p>
<p>A free (non-joined) piece may move into a square occupied by pieces of both colors.
When it does, the other piece of the same color becomes a free piece and must move to a new location following the normal movement rules.
This process may be repeated multiple times in the same turn.</p>
<p>Ŝako (checkmate) occurs when an opposing piece joins with the king.
<strong>Important:</strong> The king is not permitted to join with (capture) other pieces.</p>
<p>Due to joined movement, it is possible for a pawn to be moved backward to, or past, its starting row.
Pawns may move forward two spaces from either of the first two rows on their own side of the board.</p>
<p>When a pawn is captured <i>en passant</i> while joined with another piece, the captured pawn moves back one square to become joined with the capturing pawn
and the joined piece from the capturing side moves to a new location from its original position as with any other capture.</p>
<p>Pawns are promoted when they reach the final row on the opposite side of the board, even if they were moved there by the other player as part of a joined pair.</p>
</div>
<div class="badges"> <div class="badges">
<!-- "external-link-alt" by Font Awesome (fontawesome.com/icons/external-link-alt?style=solid) / CC BY 4.0 (creativecommons.org/licenses/by/4.0) --> <!-- "external-link-alt" by Font Awesome (fontawesome.com/icons/external-link-alt?style=solid) / CC BY 4.0 (creativecommons.org/licenses/by/4.0) -->
<div class="badge game-link-badge"><a id="game_link" href="#" rel="noopener noreferer" target="_blank"><img src="<%=require('./svg/external-link-alt-solid.svg')%>" alt="This Game" title="Link to This Game"></a></div>
<div class="badge official-badge"><a href="https://pacosako.com/" rel="noopener noreferer" target="_blank"><img src="<%=require('./svg/pacosako-logo.svg')%>" alt="Official Site" title="Official Site"></a></div> <div class="badge official-badge"><a href="https://pacosako.com/" rel="noopener noreferer" target="_blank"><img src="<%=require('./svg/pacosako-logo.svg')%>" alt="Official Site" title="Official Site"></a></div>
<div class="badge jitsi-badge"><a id="jitsi_link" href="https://meet.jit.si/PacoSako" rel="noopener noreferer" target="_blank"><img src="<%=require('./svg/jitsi-logo-blue.svg')%>" alt="Jitsi Meet" title="Jitsi Meet"></a></div>
<div class="badge gogs-badge"><a href="https://jessemcdonald.info/gogs/nybble/paco_sako" rel="noopener noreferer" target="_blank"><img src="<%=require('./png/gogs.png')%>" alt="Source Code" title="Source Code"></a></div> <div class="badge gogs-badge"><a href="https://jessemcdonald.info/gogs/nybble/paco_sako" rel="noopener noreferer" target="_blank"><img src="<%=require('./png/gogs.png')%>" alt="Source Code" title="Source Code"></a></div>
</div> </div>
</div>
<div id="cb_hidden" style="display: none"> <div id="settings_content" style="display: none">
<div id="cb_phantom" class="cb-phantom"></div> <div id="settings">
<div><input id="cb_sound" type="checkbox"><label for="cb_sound">Sound</label></div>
<div id="cb_pieces" style="display: none"> <div id="cb_theme">
<div id="cb_piece_kd" class="cb-piece cb-dk-piece cb-king" ><img src="<%=require('./svg/traditional-theme.svg')%>#dark_king_right" alt="kd"></div> <label for="cb_select_theme">Theme:</label>
<div id="cb_piece_qd" class="cb-piece cb-dk-piece cb-queen" ><img src="<%=require('./svg/traditional-theme.svg')%>#dark_queen_right" alt="qd"></div> <select id="cb_select_theme">
<div id="cb_piece_bd" class="cb-piece cb-dk-piece cb-bishop" ><img src="<%=require('./svg/traditional-theme.svg')%>#dark_bishop_right" alt="bd"></div> <option value="pacosako">Paco Ŝako</option>
<div id="cb_piece_nd" class="cb-piece cb-dk-piece cb-knight" ><img src="<%=require('./svg/traditional-theme.svg')%>#dark_knight_right" alt="nd"></div> <option value="traditional">Traditional</option>
<div id="cb_piece_rd" class="cb-piece cb-dk-piece cb-rook" ><img src="<%=require('./svg/traditional-theme.svg')%>#dark_rook_right" alt="rd"></div> </select>
<div id="cb_piece_pd" class="cb-piece cb-dk-piece cb-pawn" ><img src="<%=require('./svg/traditional-theme.svg')%>#dark_pawn_right" alt="pd"></div>
<div id="cb_piece_kl" class="cb-piece cb-lt-piece cb-king" ><img src="<%=require('./svg/traditional-theme.svg')%>#light_king_left" alt="kl"></div>
<div id="cb_piece_ql" class="cb-piece cb-lt-piece cb-queen" ><img src="<%=require('./svg/traditional-theme.svg')%>#light_queen_left" alt="ql"></div>
<div id="cb_piece_bl" class="cb-piece cb-lt-piece cb-bishop" ><img src="<%=require('./svg/traditional-theme.svg')%>#light_bishop_left" alt="bl"></div>
<div id="cb_piece_nl" class="cb-piece cb-lt-piece cb-knight" ><img src="<%=require('./svg/traditional-theme.svg')%>#light_knight_left" alt="nl"></div>
<div id="cb_piece_rl" class="cb-piece cb-lt-piece cb-rook" ><img src="<%=require('./svg/traditional-theme.svg')%>#light_rook_left" alt="rl"></div>
<div id="cb_piece_pl" class="cb-piece cb-lt-piece cb-pawn" ><img src="<%=require('./svg/traditional-theme.svg')%>#light_pawn_left" alt="pl"></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,8 @@
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/solid.css';
import './js/pacosako_ui.js'; import './js/pacosako_ui.js';

View File

@ -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;

View File

@ -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';
@ -31,26 +32,39 @@ const INITIAL_EDGE_ROW = ROOK + KNIGHT + BISHOP + QUEEN + KING + BISHOP + KNIGHT
const ROWS = '12345678'; const ROWS = '12345678';
const COLUMNS = 'abcdefgh'; const COLUMNS = 'abcdefgh';
/*
* Rule Version
*
* Increment this whenever a change in the rules would make some previously
* illegal moves illegal. The implementation in the Game class needs to check
* this._version and apply the appropriate rules based on which rules were in
* effect when the game was started.
*
* Version 1: Initial version. (Default if version field is missing.)
* Version 2: Prohibit moving through check.
*/
const CURRENT_VERSION = 2;
function otherSide(side) { function otherSide(side) {
if (side === LIGHT) { if (side === LIGHT) {
return DARK; return DARK;
} else if (side === DARK) { } else if (side === DARK) {
return LIGHT; return LIGHT;
} else { } else {
throw { message: 'invalid side', side: side }; throw new Error(`invalid side: ${side}`);
} }
} }
function squareIndex(square) { function squareIndex(square) {
if (typeof square !== 'string' || square.length !== 2) { if (typeof square !== 'string' || square.length !== 2) {
throw { message: 'invalid square', square: square }; throw new Error(`invalid square: ${square}`);
} }
const column = COLUMNS.indexOf(square[0].toLowerCase()); const column = COLUMNS.indexOf(square[0].toLowerCase());
const row = ROWS.indexOf(square[1]); const row = ROWS.indexOf(square[1]);
if (column < 0 || row < 0) { if (column < 0 || row < 0) {
throw { message: 'invalid square', square: square }; throw new Error(`invalid square: ${square}`);
} }
return (row * 8) + column; return (row * 8) + column;
@ -72,7 +86,7 @@ function encodePiece(side, type) {
let result = ALL_PIECES.indexOf(type); let result = ALL_PIECES.indexOf(type);
if (result < 0) { if (result < 0) {
throw { message: 'invalid piece', piece: type }; throw new Error(`invalid piece: ${type}`);
} }
if (side === LIGHT) { if (side === LIGHT) {
@ -80,7 +94,7 @@ function encodePiece(side, type) {
} else if (side === DARK) { } else if (side === DARK) {
return result; return result;
} else { } else {
throw { message: 'invalid side', side: side }; throw new Error(`invalid side: ${side}`);
} }
} }
@ -92,7 +106,7 @@ function decodePiece(side, value) {
} else if (side === DARK) { } else if (side === DARK) {
sideShift = 0; sideShift = 0;
} else { } else {
throw { message: 'invalid side', side: side }; throw new Error(`invalid side: ${side}`);
} }
let pieceValue = (value >>> sideShift) & 0b1111; let pieceValue = (value >>> sideShift) & 0b1111;
@ -100,7 +114,7 @@ function decodePiece(side, value) {
if (pieceValue < ALL_PIECES.length) { if (pieceValue < ALL_PIECES.length) {
return ALL_PIECES[pieceValue]; return ALL_PIECES[pieceValue];
} else { } else {
throw { message: 'invalid encoded piece', value: pieceValue }; throw new Error(`invalid encoded piece: ${pieceValue}`);
} }
} }
@ -108,7 +122,7 @@ class Board {
constructor(original) { constructor(original) {
if (original !== null && original !== undefined) { if (original !== null && original !== undefined) {
if (!(original instanceof this.constructor)) { if (!(original instanceof this.constructor)) {
throw { message: 'can only clone from another Board instance' }; throw new TypeError(`can only clone from another Board instance`);
} }
this._board = new Uint8Array(original._board); this._board = new Uint8Array(original._board);
@ -175,7 +189,7 @@ class Board {
if (type !== EMPTY) { if (type !== EMPTY) {
if (this._phantom) { if (this._phantom) {
throw { message: 'phantom square is already occupied' }; throw new Error(`phantom square is already occupied`);
} }
this.putPiece(side, square, EMPTY); this.putPiece(side, square, EMPTY);
@ -190,17 +204,17 @@ class Board {
move(from, to) { move(from, to) {
if (this._phantom && from !== PHANTOM) { if (this._phantom && from !== PHANTOM) {
throw { message: 'must complete prior move before moving other pieces' }; throw new Error(`must complete prior move before moving other pieces`);
} }
let lightPiece = this.getPiece(LIGHT, from); let lightPiece = this.getPiece(LIGHT, from);
let darkPiece = this.getPiece(DARK, from); let darkPiece = this.getPiece(DARK, from);
if (lightPiece === EMPTY && darkPiece === EMPTY) { if (lightPiece === EMPTY && darkPiece === EMPTY) {
throw { message: 'cannot move from empty square' }; throw new Error(`cannot move from empty square: ${from}${to}`);
} else if (lightPiece !== EMPTY && darkPiece !== EMPTY) { } else if (lightPiece !== EMPTY && darkPiece !== EMPTY) {
if (!this.isEmpty(to)) { if (!this.isEmpty(to)) {
throw { message: 'cannot capture with joined pieces' }; throw new Error(`cannot capture with joined pieces`);
} }
const fromIndex = squareIndex(from); const fromIndex = squareIndex(from);
@ -214,7 +228,7 @@ class Board {
const displaced = this.getPiece(moving, to); const displaced = this.getPiece(moving, to);
if (displaced !== EMPTY && this.getPiece(other, to) === EMPTY) { if (displaced !== EMPTY && this.getPiece(other, to) === EMPTY) {
throw { message: 'cannot join with piece of same color' }; throw new Error(`cannot join with piece of same color`);
} }
if (from === PHANTOM) { if (from === PHANTOM) {
@ -258,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) {
@ -273,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;
@ -302,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;
@ -462,9 +476,38 @@ function diffHistory(game1, game2) {
class Game { class Game {
constructor(original) { constructor(original) {
if (typeof original === 'string') {
const moves = JSON.parse(original);
original = new Game();
if ('version' in moves === false) {
original._version = 1;
} else if (!Number.isInteger(moves.version) ||
moves.version < 1 || moves.version > CURRENT_VERSION) {
throw new Error('invalid version');
} else {
original._version = moves.version;
}
for (const move of moves.past) {
original.replayMove(move);
}
let n = 0;
for (const move of moves.future.slice().reverse()) {
original.replayMove(move);
n += 1;
}
for (let i = 0; i < n; ++i) {
original.undo();
}
}
if (original !== undefined) { if (original !== undefined) {
if (!(original instanceof this.constructor)) { if (!(original instanceof this.constructor)) {
throw { message: 'can only clone from another Game instance' }; throw new TypeError(`can only clone from another Game instance`);
} }
Object.assign(this, original, { Object.assign(this, original, {
@ -488,6 +531,7 @@ class Game {
this._undo = null; this._undo = null;
this._checkCache = {}; this._checkCache = {};
this._ignoreCheck = false; this._ignoreCheck = false;
this._version = CURRENT_VERSION;
/* set to false when the king or rook moves */ /* set to false when the king or rook moves */
this._castling = { this._castling = {
@ -525,6 +569,41 @@ class Game {
this._ignoreCheck = !!value; this._ignoreCheck = !!value;
} }
get version() {
return this._version;
}
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,
version: this._version,
});
}
canCapture(side, from) { canCapture(side, from) {
if (from === PHANTOM) { if (from === PHANTOM) {
return true; return true;
@ -568,7 +647,18 @@ class Game {
board.isEmpty('f' + row) && board.isEmpty('f' + row) &&
board.isEmpty('g' + row)) { board.isEmpty('g' + row)) {
if (!this.isInCheck(side)) { if (!this.isInCheck(side)) {
yield 'g' + row; if (this._version < 2) {
yield 'g' + row;
} else {
/* Prohibit castling through check */
const testGame = new Game(this);
testGame._board.putPiece(side, 'e' + row, EMPTY);
testGame._board.putPiece(side, 'f' + row, KING);
testGame._checkCache = {};
if (!testGame.isInCheck(side)) {
yield 'g' + row;
}
}
} }
} }
@ -577,7 +667,18 @@ class Game {
board.isEmpty('c' + row) && board.isEmpty('c' + row) &&
board.isEmpty('b' + row)) { board.isEmpty('b' + row)) {
if (!this.isInCheck(side)) { if (!this.isInCheck(side)) {
yield 'c' + row; if (this._version < 2) {
yield 'c' + row;
} else {
/* Prohibit castling through check */
const testGame = new Game(this);
testGame._board.putPiece(side, 'e' + row, EMPTY);
testGame._board.putPiece(side, 'd' + row, KING);
testGame._checkCache = {};
if (!testGame.isInCheck(side)) {
yield 'c' + row;
}
}
} }
} }
} }
@ -671,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);
@ -732,7 +831,7 @@ class Game {
const kings = [...this._board.findPieces(side, KING)]; const kings = [...this._board.findPieces(side, KING)];
if (kings.length !== 1) { if (kings.length !== 1) {
throw { message: 'there should be exactly one king per side' }; throw new Error(`there should be exactly one king per side`);
} }
const king = kings[0]; const king = kings[0];
@ -756,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);
} }
@ -812,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);
} }
@ -894,7 +993,7 @@ class Game {
move(from, to, meta) { move(from, to, meta) {
if (this._status !== PLAYING) { if (this._status !== PLAYING) {
throw { message: "can't move, game is already over" }; throw new Error(`can't move, game is already over`);
} }
const side = this._player; const side = this._player;
@ -906,13 +1005,13 @@ class Game {
const alongside = board.getPiece(other, from); const alongside = board.getPiece(other, from);
if (from === PHANTOM && !board.phantom) { if (from === PHANTOM && !board.phantom) {
throw { message: "attempted to continue a completed move" }; throw new Error(`attempted to continue a completed move`);
} }
const fromSquare = (from === PHANTOM) ? board.phantom.from : from; const fromSquare = (from === PHANTOM) ? board.phantom.from : from;
if (!this.isLegalMove(side, from, to, alongside === EMPTY)) { if (!this.isLegalMove(side, from, to, alongside === EMPTY)) {
throw { message: "illegal move", side: side, from: fromSquare, to: to }; throw new Error(`illegal move by ${side} side: ${fromSquare}${to}`);
} }
const move = { const move = {
@ -1053,7 +1152,7 @@ class Game {
resign(meta) { resign(meta) {
if (this._status !== PLAYING) { if (this._status !== PLAYING) {
throw { message: "can't resign, game is already over" }; throw new Error(`can't resign, game is already over`);
} }
const move = { const move = {
@ -1101,8 +1200,8 @@ class Game {
} }
replayMove(move) { replayMove(move) {
if (!move || move.side !== this._player) { if (otherSide(move.side) === this._player) {
throw { message: "other player's move", move: move }; throw new Error(`other player's move`);
} }
if (move.resign) { if (move.resign) {
@ -1164,6 +1263,7 @@ class Game {
renderHistory() { renderHistory() {
if (this._history === undefined) { if (this._history === undefined) {
const replay = new Game(); const replay = new Game();
replay._version = this._version;
for (const move of this._moves) { for (const move of this._moves) {
replay.replayMove(move); replay.replayMove(move);
} }
@ -1190,6 +1290,9 @@ export default {
/* Coordinates */ /* Coordinates */
ROWS, COLUMNS, PHANTOM, ROWS, COLUMNS, PHANTOM,
/* Versioning */
CURRENT_VERSION,
/* Miscellaneous */ /* Miscellaneous */
Util: { otherSide, offsetSquare, diffHistory }, Util: { otherSide, offsetSquare, diffHistory },
}; };

View File

@ -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(() => {

File diff suppressed because it is too large Load Diff

Binary file not shown.

23127
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "paco-sako", "name": "paco-sako",
"version": "0.4.8", "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",
@ -31,28 +31,35 @@
"url": "https://jessemcdonald.info/gogs/nybble/paco_sako.git" "url": "https://jessemcdonald.info/gogs/nybble/paco_sako.git"
}, },
"devDependencies": { "devDependencies": {
"clean-webpack-plugin": "^3.0.0", "@fortawesome/fontawesome-free": "^5.13.0",
"copy-webpack-plugin": "^5.1.1", "buffer": "^6.0.3",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^6.4.1",
"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"
}, },

View File

@ -1 +0,0 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="external-link-alt" class="svg-inline--fa fa-external-link-alt fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z"></path></svg>

Before

Width:  |  Height:  |  Size: 597 B

View File

@ -1,160 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="160"
height="160"
viewBox="0 0 150 150.00001"
id="svg3526"
version="1.1"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
inkscape:export-filename="/Users/ystamcheva/Dropbox/Designs/appLogo.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:docname="jitsi-logo-blue.svg">
<defs
id="defs3528">
<filter
style="color-interpolation-filters:sRGB;"
inkscape:label="Blur"
id="filter921">
<feGaussianBlur
stdDeviation="4 4"
result="blur"
id="feGaussianBlur919" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="89.185304"
inkscape:cy="80.953412"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="999"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
units="px"
inkscape:snap-bbox="true"
inkscape:snap-page="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:pagecheckerboard="true" />
<metadata
id="metadata3531">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-902.36211)"
style="opacity:1">
<path
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.91489375;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;filter:url(#filter921)"
d="M 142.5,977.36212 A 67.499998,67.499998 0 0 1 74.999998,1044.8621 67.499998,67.499998 0 0 1 7.5,977.36212 a 67.499998,67.499998 0 0 1 67.499998,-67.5 67.499998,67.499998 0 0 1 67.500002,67.5 z"
id="path1006-7"
inkscape:connector-curvature="0"
transform="matrix(0.97916666,0,0,0.97916666,1.562503,20.361715)" />
<path
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.87500012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
d="M 141.09375,977.36212 A 66.09375,66.09375 0 0 1 75.000003,1043.4558 66.09375,66.09375 0 0 1 8.9062529,977.36212 66.09375,66.09375 0 0 1 75.000003,911.26837 66.09375,66.09375 0 0 1 141.09375,977.36212 Z"
id="path1006"
inkscape:connector-curvature="0" />
<g
id="g1247"
transform="matrix(0.93034217,0,0,0.93034217,4.9699418,67.566622)"
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333">
<path
inkscape:connector-curvature="0"
id="path3618"
d=""
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path35"
d="m 66.150479,984.58608 c 3.546945,0 11.036812,-2.11769 15.990996,-3.51965 0.720489,-0.20282 1.392044,-0.39263 2.002303,-0.56287 0.09877,-0.0272 0.194448,-0.0519 0.284976,-0.0746 -0.27828,-0.27544 -0.741093,-0.6937 -1.495321,-1.32572 -3.300213,-2.23667 -6.416409,-3.27807 -9.805606,-3.27807 -0.73929,0 -1.507554,0.0453 -2.344712,0.14011 -2.869465,0.32644 -5.26015,1.01023 -6.408683,1.33796 -0.582186,0.16689 -0.757576,0.21672 -0.939018,0.21672 -0.346144,0 -0.643483,-0.20591 -0.759765,-0.52398 -0.116412,-0.31974 -0.01674,-0.67258 0.253555,-0.89897 l 0.01635,-0.0131 c 1.980412,-1.65899 5.670166,-4.74737 12.67005,-6.12731 1.214078,-0.23862 2.512891,-0.36006 3.859091,-0.36006 3.133581,0 6.378164,0.64722 9.641162,1.92195 4.444111,1.7351 7.480982,3.9625 9.923563,5.75233 1.31491,0.96438 2.45057,1.79755 3.43891,2.2556 0.25252,0.11744 0.38361,0.15053 0.44465,0.15916 0.0449,-0.0582 0.14243,-0.21891 0.28575,-0.64052 0.0384,-0.11165 0.31588,-1.29018 -1.67496,-7.99311 -1.15703,-3.89116 -2.552556,-7.86512 -3.279226,-9.62945 -1.405694,-3.41366 -1.060709,-5.83293 -0.62803,-7.2479 -1.190899,0.4377 -2.408198,1.11879 -3.688853,2.05948 l -0.07984,0.059 c -0.639877,0.4744 -1.29173,1.01126 -1.993675,1.63864 -4.13029,3.69813 -7.224723,5.62613 -9.201529,5.73095 l -0.05447,0.003 -0.05421,-0.005 c -1.741536,-0.14783 -4.380754,-2.68287 -5.460393,-3.96636 -0.224453,-0.15054 -0.480197,-0.21879 -0.817713,-0.21879 -0.338933,0 -0.718944,0.0712 -1.086593,0.14101 -0.267463,0.0507 -0.543168,0.10237 -0.816555,0.13006 -0.871412,0.0874 -2.092831,0.36919 -3.271626,0.64052 -0.568278,0.13058 -1.154714,0.26566 -1.690799,0.37628 -0.01017,0.002 -0.240292,0.0492 -0.651595,0.15762 -2.913377,0.86188 -5.108841,1.85073 -6.182685,2.78512 -0.01172,0.0102 -0.04636,0.0371 -0.101603,0.0777 -0.726284,0.51625 -2.472327,1.98916 -2.99914,4.4951 l -0.0055,0.0209 c -1.099856,4.61487 0.567635,10.33796 2.783445,13.60701 1.042166,1.53653 2.165202,2.49512 3.083359,2.62956 0.228573,0.0324 0.502861,0.0497 0.813978,0.0497 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path39"
d="m 82.429799,960.11108 c 0.0707,0.0139 0.15337,0.0209 0.24467,0.0209 1.90392,0 6.155901,-2.75679 6.942451,-4.01838 l 0.06258,-0.10045 0.08937,-0.0787 c 0.268236,-0.26476 1.042938,-1.65925 1.418958,-2.49396 -4.032164,-1.2097 -4.477077,-3.3928 -4.870352,-5.33252 -0.04572,-0.22523 -0.08589,-0.42804 -0.12182,-0.60936 -0.04597,-0.2372 -0.09413,-0.47813 -0.13547,-0.66434 -6.00678,1.99226 -7.842965,3.1104 -8.845083,3.94189 -0.518572,0.43075 -0.823894,1.65577 0.671555,5.04652 0.763886,1.7284 3.397825,4.06809 4.543138,4.28842 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path43"
d="m 51.013383,1000.8062 c -0.746759,-0.88008 -1.063414,-1.98921 -0.939147,-3.29974 0.528616,-6.36104 -0.19638,-7.8977 -0.532093,-8.26238 -0.081,-0.0882 -0.124782,-0.0882 -0.159422,-0.0882 -0.01301,0 -0.02511,7.7e-4 -0.03812,0.002 -0.623265,0.14899 -4.821418,2.98729 -5.748203,11.46142 -0.446973,4.0896 0.336228,9.3415 1.003663,12.5359 0.536342,-1.886 1.383287,-3.9635 3.023994,-6.1018 1.527514,-1.9888 3.193718,-3.5571 5.260665,-4.9318 -0.642581,-0.2672 -1.332293,-0.6791 -1.87134,-1.3155 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path47"
d="m 95.474451,928.32276 c -0.501702,3.30962 -1.318514,6.4535 -2.842938,9.77174 1.661697,-1.88125 2.63278,-3.92515 2.958062,-6.21925 0.135341,-0.95035 0.263342,-1.85937 -0.115124,-3.55249 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path51"
d="m 86.212271,943.73132 c 2.97918,-2.69331 4.792959,-7.14115 5.547315,-9.78307 -2.594662,2.49911 -5.747945,3.84003 -7.771624,4.70178 -0.696924,0.29721 -1.29804,0.55309 -1.658349,0.76312 -0.151695,0.0882 -0.304807,0.17693 -0.459851,0.26643 -1.2276,0.71019 -3.080783,1.78352 -3.35095,2.44503 l -0.0077,0.0215 -0.01004,0.0213 c -0.840764,1.76678 -1.314522,4.42364 -1.466347,5.94729 1.948991,-1.19013 3.958248,-1.98441 5.627284,-2.6436 1.549149,-0.61206 2.888653,-1.14132 3.550293,-1.73973 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path55"
d="m 89.217464,946.05955 c -0.01816,0.046 -0.0376,0.0895 -0.05859,0.13096 -0.49359,1.43492 0.186206,3.38675 1.445743,4.12295 0.335069,0.19599 0.660866,0.31575 0.9734,0.35696 0.04301,0.002 0.08576,0.003 0.128903,0.003 0.978809,0 1.777206,-0.71599 2.369437,-2.12722 0.372929,-1.07397 0.425983,-2.34754 0.14487,-3.49724 -0.2184,-0.89317 -0.783459,-1.95929 -1.143511,-2.49087 -0.67207,0.46127 -2.000242,1.47601 -2.912218,2.28136 -0.636915,0.61515 -0.867034,1.0025 -0.948032,1.21962 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path59"
d="m 97.64004,982.53162 c 1.082085,-0.29489 1.941393,-0.53634 2.57522,-0.72409 -1.305382,-0.90928 -2.816414,-2.04055 -4.870613,-3.63825 -5.034538,-3.91524 -10.43312,-5.90119 -16.043535,-5.90119 -3.07267,0 -5.749361,0.59133 -7.867818,1.30719 0.528101,-0.0328 1.065087,-0.0485 1.616625,-0.0485 0.655201,0 1.341823,0.0231 2.040034,0.0697 2.182586,0.14628 7.80575,1.139 12.891025,7.20244 1.024524,1.21936 2.125668,2.22869 5.257575,2.22869 1.117627,0 2.420431,-0.12453 3.980783,-0.38104 0.09645,-0.0269 0.242352,-0.0667 0.420704,-0.11487 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path63"
d="m 104.77707,956.11317 c -0.99864,-1.55082 -2.25329,-2.51418 -3.27214,-2.51418 -0.18853,0 -0.36855,0.0332 -0.53493,0.0985 -0.54587,0.21531 -1.41033,2.70966 -1.027486,4.52331 0.260506,1.23391 1.760336,5.40335 2.480436,7.40707 0.27584,0.76723 0.4095,1.14209 0.45419,1.28142 0.0354,0.10985 0.0863,0.26747 0.15066,0.46629 0.58168,1.77257 2.07468,6.32859 2.51908,10.0177 0.92395,-3.93455 1.44728,-8.6742 1.24228,-14.34655 -0.0931,-2.60111 -0.80793,-5.06378 -2.01209,-6.93357 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path67"
d="m 86.080664,982.55557 c -0.0197,-0.0258 -0.03863,-0.0511 -0.0573,-0.0753 -0.07907,0.0129 -0.208099,0.0411 -0.410145,0.0999 l -0.0846,0.0254 c -1.031607,0.37988 -2.924066,1.01834 -5.111545,1.75647 -2.625311,0.88468 -5.598697,1.88769 -8.088022,2.78087 -3.167319,1.18021 -4.194419,1.64586 -4.516482,1.80901 -0.05846,0.15685 -0.124009,0.35696 -0.197024,0.57768 -0.749077,2.27994 -2.4646,7.4985 -10.924006,11.1469 1.747203,1.7699 5.550278,4.9468 13.037055,4.9468 0.648376,0 1.320961,-0.024 1.99522,-0.073 5.652653,-0.4019 10.966115,-2.903 14.964283,-7.04037 3.635669,-3.76149 5.699397,-8.45284 5.731333,-12.97525 -0.884804,-0.0735 -2.384761,-0.29373 -3.7732,-0.95292 -0.0161,-0.008 -1.602847,-0.7729 -2.565559,-2.02626 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path71"
d="m 53.890317,990.77391 c -0.01571,1.33075 -0.191744,2.60703 -0.363142,3.85124 -0.0922,0.67168 -0.188525,1.36693 -0.25935,2.06566 -0.09607,1.40544 0.207583,1.89516 0.342409,2.03836 0.07353,0.081 0.194835,0.17333 0.455344,0.17333 0.20063,0 0.440149,-0.0556 0.693189,-0.1611 2.51199,-1.05285 4.897523,-2.88028 6.044254,-3.8945 -1.76008,-0.78488 -4.467033,-2.48018 -6.912704,-4.07299 z" />
<path
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333"
inkscape:connector-curvature="0"
id="path75"
d="m 95.375553,985.509 c -0.07108,0.93464 -0.22368,2.69768 -0.467577,4.04066 -0.295536,1.62628 -0.784876,3.00172 -1.069466,3.72015 0.508012,0.46976 1.014479,0.93077 1.342981,1.2218 1.321863,-0.8651 5.661019,-4.15901 8.654629,-11.63703 -0.95898,0.64774 -2.30583,1.21769 -4.051869,1.71682 -1.776691,0.50595 -3.503161,0.80213 -4.408698,0.9376 z" />
<path
d="m 113.82909,953.6111 c -1.81082,-3.78531 -4.33568,-5.69644 -6.07954,-6.80467 -1.46622,-0.93142 -3.15225,-1.60825 -5.02372,-2.01878 -0.20887,-1.30809 -0.56622,-2.64527 -1.05569,-3.9464 3.15586,-4.70424 3.91563,-9.99349 2.19019,-15.35151 -1.32521,-4.11947 -2.35412,-6.77569 -3.23905,-8.36102 -1.911774,-3.42899 -4.56065,-4.14858 -6.446413,-4.14858 -1.943196,0 -3.803719,0.8257 -5.108069,2.26771 -1.335383,1.47601 -1.959035,3.40761 -1.755701,5.43786 0.173716,1.73149 -0.280469,4.87692 -0.581928,6.00008 -0.0052,0.0151 -0.541108,1.51644 -4.528716,3.44908 -0.09606,0.0345 -0.3003,0.10443 -0.614637,0.20977 -2.293718,0.76814 -6.556258,2.19714 -9.395719,5.9518 -2.169451,2.62788 -2.702317,5.23194 -3.317984,8.24615 -0.368036,1.79704 -0.752812,4.14484 -0.65739,6.92095 -7.127627,1.58275 -12.26261,4.80815 -15.273726,9.59879 -3.116711,4.96037 -3.657432,11.10957 -1.605551,18.28497 l 0.01803,0.0533 c 0.0376,0.13058 0.07726,0.26064 0.118601,0.39019 -0.350007,-0.06 -0.703749,-0.11049 -1.066891,-0.15054 -0.317942,-0.0366 -0.6458,-0.0541 -0.970954,-0.0541 -3.558791,0 -7.345641,2.23693 -10.130116,5.98463 -2.115366,2.84564 -4.655943,7.87207 -4.74557,15.65802 -0.06735,5.7826 0.551023,11.1139 1.839276,15.8461 0.96078,3.526 2.032564,5.6921 2.443997,6.4503 l 8.729958,16.3644 3.999713,-18.1224 c 1.365002,-6.1728 2.712748,-8.7931 4.451837,-10.525 4.046715,2.4388 8.826282,3.7217 13.899968,3.7217 5.655614,0 11.552937,-1.6311 16.603314,-4.5923 3.280769,-1.9257 6.07722,-4.2913 8.322519,-7.0385 0.03039,0 0.06039,0 0.09066,0 h 0.239133 c 1.388438,-0.047 3.286563,-0.7336 5.206829,-1.884 1.5995,-0.9571 4.01092,-2.71815 6.43174,-5.67428 2.43963,-2.98176 4.43007,-6.60919 5.91407,-10.78236 1.73845,-4.88554 2.79658,-10.57425 3.1426,-16.90438 0.41889,-5.88793 -0.2676,-10.75686 -2.04507,-14.47211 z m -4.00796,14.09132 c -0.31098,5.76971 -1.2549,10.90199 -2.80263,15.25209 -1.25078,3.51578 -2.89766,6.53385 -4.89404,8.97425 -3.437747,4.19944 -6.797068,5.32543 -7.153514,5.3396 h -0.02833 c -0.32554,0 -0.51664,-0.1329 -1.428745,-0.7711 -0.254843,-0.17758 -0.639877,-0.44646 -0.957562,-0.65352 -1.907525,3.7101 -5.040848,6.91526 -9.099024,9.29556 -4.13338,2.424 -8.941019,3.7604 -13.534121,3.7604 -5.453826,0 -10.241634,-1.8001 -13.887219,-5.2144 -4.973371,3.1622 -7.962467,5.8005 -10.38586,16.7757 l -0.458692,2.0806 -1.002762,-1.8788 c -0.25304,-0.4625 -1.121233,-2.1754 -1.938946,-5.1807 -1.14042,-4.19 -1.688224,-8.9624 -1.627314,-14.1831 0.121563,-10.41898 5.714078,-15.64835 8.811602,-15.64835 0.101988,0 0.203205,0.005 0.299785,0.0165 2.936041,0.3285 4.854641,1.59705 8.337456,3.90069 0.360052,0.23862 0.739162,0.48934 1.138747,0.75178 1.247817,0.819 3.011631,1.81893 3.455643,1.90469 0.845014,-0.0491 1.672256,-1.94178 1.912677,-3.69748 0.01468,-0.10675 0.0291,-0.20578 0.04301,-0.29811 0.01893,-0.20758 0.02923,-0.39019 0.03477,-0.54008 -0.147317,-0.0514 -0.300429,-0.1119 -0.45676,-0.18067 l -0.03477,-0.0117 c -2.190699,-0.75422 -5.3915,-4.45879 -7.002459,-9.83638 -1.555716,-5.43554 -1.247947,-9.93129 0.914164,-13.37058 3.505351,-5.57951 11.114077,-6.89132 13.630573,-7.3222 0.786679,-0.15633 1.609414,-0.30275 2.446573,-0.435 0.390828,-0.0981 0.658033,-0.18015 0.830462,-0.25471 0.07469,-0.0519 0.107526,-0.10727 0.05653,-0.30945 l 0.06825,-0.0191 -0.06606,0.0148 c -0.03052,-0.13714 -0.07276,-0.29759 -0.121176,-0.48328 -0.06709,-0.25717 -0.142037,-0.54807 -0.219559,-0.89318 -0.779081,-3.49505 -0.381428,-6.42375 0.111132,-8.8286 0.553341,-2.70669 0.859951,-4.20523 2.138288,-5.70197 1.693632,-2.33119 4.73926,-3.35134 6.561409,-3.96237 0.508399,-0.17024 0.947646,-0.31704 1.201588,-0.43938 5.581569,-2.67707 7.358776,-5.49168 7.866917,-7.38105 0.402675,-1.49918 1.041007,-5.44108 0.763757,-8.19387 -0.03078,-0.31228 0.04198,-0.56931 0.218271,-0.76428 0.156461,-0.17268 0.378853,-0.27094 0.611418,-0.27094 0.52295,0 1.23919,0 3.91176,8.30308 1.409944,4.37779 0.358635,8.48207 -3.12199,12.20002 -0.04468,0.0483 -0.09014,0.0956 -0.133925,0.14101 -0.09504,0.0979 -0.237974,0.24583 -0.257419,0.29953 7.73e-4,0 -0.0062,0.13418 0.225998,0.51909 1.47124,2.42918 2.270668,5.45009 2.038746,7.6959 -0.05524,0.52308 -0.155301,1.02646 -0.241966,1.46944 -0.05151,0.25343 -0.113192,0.56364 -0.144999,0.80368 0.01429,0 0.0291,0 0.04468,0 0.397654,-0.0421 1.013064,-0.0901 1.754929,-0.0901 1.745657,0 4.245547,0.26747 6.245917,1.53898 1.20816,0.76646 2.73709,1.94925 3.86077,4.30156 1.32392,2.76503 1.81519,6.62579 1.46402,11.47554 z"
id="path87"
inkscape:connector-curvature="0"
style="fill:#0096d5;fill-opacity:1;stroke-width:1.07487333" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

4
sw.js
View File

@ -14,3 +14,7 @@ addEventListener('message', (event) => {
skipWaiting(); skipWaiting();
} }
}); });
self.addEventListener('activate', (event) => {
event.waitUntil(clients.claim());
});

View File

@ -23,7 +23,7 @@ module.exports = {
loaders: [MiniCssExtractPlugin.loader, "css-loader"] loaders: [MiniCssExtractPlugin.loader, "css-loader"]
}, },
{ {
test: { and: [ /\.(jpe?g|png|gif|svg)$/i, /jquery-ui/i ] }, test: { and: [ /\.(jpe?g|png|gif|svg|ttf|eot|woff2?)$/i, /jquery-ui/i ] },
loader: "file-loader", loader: "file-loader",
options: { options: {
name: '[name].[contenthash].[ext]', name: '[name].[contenthash].[ext]',
@ -31,7 +31,7 @@ module.exports = {
} }
}, },
{ {
test: { and: [ /\.(jpe?g|png|gif|mp3|wav)$/i, { not: [ /jquery-ui/i ] } ] }, test: { and: [ /\.(jpe?g|png|gif|mp3|wav|ttf|eot|woff2?)$/i, { not: [ /jquery-ui/i ] } ] },
loader: "file-loader", loader: "file-loader",
options: { options: {
name: '[path][name].[contenthash].[ext]', name: '[path][name].[contenthash].[ext]',
@ -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,12 +95,14 @@ 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,}\.(css|js|svg|png|jpg|wav)$/, dontCacheBustURLsMatching: /\.[0-9a-f]{16,}\.\w{2,4}$/,
exclude: [ /(^|[/\\])\.htaccess$/ ], exclude: [ /(^|[/\\])\.htaccess$/ ],
}), }),
], ],