+
+ for (const square of squares_to_clear) {
+ delete PIECE_ON_SQUARE[square];
+ }
+ for (const [square, piece] of Object.entries(squares_to_fill)) {
+ PIECE_ON_SQUARE[square] = piece;
+ piece.setAttribute('data-square', square);
+ }
+
+ var numFinished = 0;
+ function onFinish(e, opt_force) {
+ if (++numFinished === a.length) {
+ for (let piece of removed_pieces) {
+ piece.remove();
+ }
+
+ // run their onMoveEnd function
+ if (cfg.hasOwnProperty('onMoveEnd') &&
+ typeof cfg.onMoveEnd === 'function') {
+ cfg.onMoveEnd(deepCopy(oldPos), deepCopy(newPos));
+ }
+ }
+ }
+
+ fadein_pieces.forEach((piece) => {
+ piece.style.display = null;
+ piece.style.opacity = 1;
+ piece.animate(
+ [ { opacity: 0 }, { opacity: 1 } ],
+ { duration: cfg.appearSpeed }
+ ).addEventListener('finish', onFinish);
+ });
+ fadeout_pieces.forEach((piece) => {
+ piece.style.display = null;
+ piece.style.opacity = 0;
+ piece.animate(
+ [ { opacity: 1 }, { opacity: 0 } ],
+ { duration: cfg.trashSpeed }
+ ).addEventListener('finish', onFinish);
+ });
+ for (const [piece, destination] of move_pieces) {
+ // Move it to the end of the stack, which changes the implicit z-index
+ // so that it will go on top of any pieces it's replacing.
+ piece.remove();
+ boardEl.appendChild(piece);
+
+ let destSquarePosition = findSquarePosition(destination);
+ piece.animate(
+ [
+ { top: piece.style.top, left: piece.style.left },
+ { top: destSquarePosition.top, left: destSquarePosition.left }
+ ],
+ { duration: cfg.moveSpeed }
+ ).addEventListener('finish', onFinish);
+ piece.style.top = destSquarePosition.top;
+ piece.style.left = destSquarePosition.left;
+ }