};
}
-function animateSquareToSquare(move_pieces, complete) {
- 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);
-
- // animate the piece to the destination square
- piece.addEventListener('transitionend', complete, {once: true});
- }
- requestAnimationFrame(() => {
- for (const [piece, destination] of move_pieces) {
- let destSquarePosition = findSquarePosition(destination);
- piece.style.transitionProperty = 'top, left';
- piece.style.transitionDuration = cfg.moveSpeed + 'ms';
- piece.style.top = destSquarePosition.top;
- piece.style.left = destSquarePosition.left;
- }
- });
-}
-
-function fadeIn(pieces, onFinish) {
- pieces.forEach((piece) => {
- piece.style.opacity = 0;
- piece.style.display = null;
- piece.addEventListener('transitionend', onFinish, {once: true});
- });
- requestAnimationFrame(() => {
- pieces.forEach((piece) => {
- piece.style.transitionProperty = 'opacity';
- piece.style.transitionDuration = cfg.appearSpeed + 'ms';
- piece.style.opacity = 1;
- });
- });
-}
-
-function fadeOut(pieces, onFinish) {
- pieces.forEach((piece) => {
- piece.style.opacity = 1;
- piece.style.display = null;
- piece.addEventListener('transitionend', onFinish, {once: true});
- });
- requestAnimationFrame(() => {
- pieces.forEach((piece) => {
- piece.style.transitionProperty = 'opacity';
- piece.style.transitionDuration = cfg.trashSpeed + 'ms';
- piece.style.opacity = 0;
- });
- });
-}
-
// execute an array of animations
function doAnimations(a, oldPos, newPos) {
let fadeout_pieces = [];
}
var numFinished = 0;
- function onFinish(e) {
+ function onFinish(e, opt_force) {
if (e && e.target) {
e.target.transitionProperty = null;
e.target.transitionDuration = null;
}
- numFinished++;
-
- // exit if all the animations aren't finished
- if (numFinished !== a.length) return;
+ if (opt_force) {
+ // For whatever reason, the transition didn't seem to actually run
+ // (and thus, we didn't get an end event). Finish off now.
+ // (In particular, this seems to happen in Chrome if the tab is
+ // hidden and left alone for a while.)
+ if (numFinished == a.length) return;
+ numFinished = a.length; // Make sure a very delayed later event will be ignored.
+ } else {
+ numFinished++;
+ if (numFinished !== a.length) return;
+ }
for (let piece of removed_pieces) {
piece.remove();
}
}
- requestAnimationFrame(() => { // Firefox workaround.
- if (fadeout_pieces.length > 0) {
- fadeOut(fadeout_pieces, onFinish);
- }
- if (fadein_pieces.length > 0) {
- fadeIn(fadein_pieces, onFinish);
- }
- if (move_pieces.length > 0) {
- animateSquareToSquare(move_pieces, onFinish);
- }
- });
+ if (fadeout_pieces.length == 0 || fadein_pieces.length > 0 || move_pieces.length > 0) {
+ requestAnimationFrame(() => { // Firefox workaround.
+ // Backup in case the transition never runs.
+ setTimeout(() => onFinish(null, true),
+ cfg.appearSpeed + cfg.trashSpeed + cfg.moveSpeed + 100);
+
+ fadein_pieces.forEach((piece) => {
+ piece.style.opacity = 0;
+ piece.style.display = null;
+ piece.addEventListener('transitionend', onFinish, {once: true});
+ });
+ fadeout_pieces.forEach((piece) => {
+ piece.style.opacity = 1;
+ piece.style.display = null;
+ piece.addEventListener('transitionend', onFinish, {once: true});
+ });
+ 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);
+ piece.addEventListener('transitionend', onFinish, {once: true});
+ }
+ requestAnimationFrame(() => {
+ fadein_pieces.forEach((piece) => {
+ piece.style.transitionProperty = 'opacity';
+ piece.style.transitionDuration = cfg.appearSpeed + 'ms';
+ piece.style.opacity = 1;
+ });
+ fadeout_pieces.forEach((piece) => {
+ piece.style.transitionProperty = 'opacity';
+ piece.style.transitionDuration = cfg.trashSpeed + 'ms';
+ piece.style.opacity = 0;
+ });
+ for (const [piece, destination] of move_pieces) {
+ let destSquarePosition = findSquarePosition(destination);
+ piece.style.transitionProperty = 'top, left';
+ piece.style.transitionDuration = cfg.moveSpeed + 'ms';
+ piece.style.top = destSquarePosition.top;
+ piece.style.left = destSquarePosition.left;
+ }
+ });
+ });
+ }
}
// returns the distance between two squares