]> git.sesse.net Git - remoteglot/blobdiff - www/js/chessboard-0.3.0.js
Unbreak dragging again.
[remoteglot] / www / js / chessboard-0.3.0.js
index 5d257a0dc3b222b9facbbc31bb74bffdaeb43d7c..f69d0ed3802968a07c2ee533464565c82cb7a88e 100644 (file)
@@ -26,7 +26,7 @@ function validMove(move) {
   var tmp = move.split('-');
   if (tmp.length !== 2) return false;
 
-  return (validSquare(tmp[0]) === true && validSquare(tmp[1]) === true);
+  return validSquare(tmp[0]) && validSquare(tmp[1]);
 }
 
 function validSquare(square) {
@@ -67,9 +67,9 @@ function validPositionObject(pos) {
   if (typeof pos !== 'object') return false;
 
   for (var i in pos) {
-    if (pos.hasOwnProperty(i) !== true) continue;
+    if (!pos.hasOwnProperty(i)) continue;
 
-    if (validSquare(i) !== true || validPieceCode(pos[i]) !== true) {
+    if (!validSquare(i) || !validPieceCode(pos[i])) {
       return false;
     }
   }
@@ -104,7 +104,7 @@ function pieceCodeToFen(piece) {
 // convert FEN string to position object
 // returns false if the FEN string is invalid
 function fenToObj(fen) {
-  if (validFen(fen) !== true) {
+  if (!validFen(fen)) {
     return false;
   }
 
@@ -144,7 +144,7 @@ function fenToObj(fen) {
 // position object to FEN string
 // returns false if the obj is not a valid position object
 function objToFen(obj) {
-  if (validPositionObject(obj) !== true) {
+  if (!validPositionObject(obj)) {
     return false;
   }
 
@@ -157,7 +157,7 @@ function objToFen(obj) {
       var square = COLUMNS[j] + currentRow;
 
       // piece exists
-      if (obj.hasOwnProperty(square) === true) {
+      if (obj.hasOwnProperty(square)) {
         if (num_empty > 0) {
           fen += num_empty;
           num_empty = 0;
@@ -266,7 +266,7 @@ function deepCopy(thing) {
  */
 function error(code, msg, obj) {
   // do nothing if showErrors is not set
-  if (cfg.hasOwnProperty('showErrors') !== true ||
+  if (!cfg.hasOwnProperty('showErrors') ||
       cfg.showErrors === false) {
     return;
   }
@@ -346,7 +346,7 @@ function validAnimationSpeed(speed) {
 
 // validate config / set default options
 function expandConfig() {
-  if (typeof cfg === 'string' || validPositionObject(cfg) === true) {
+  if (typeof cfg === 'string' || validPositionObject(cfg)) {
     cfg = {
       position: cfg
     };
@@ -369,45 +369,45 @@ function expandConfig() {
   }
 
   // default piece theme is wikipedia
-  if (cfg.hasOwnProperty('pieceTheme') !== true ||
+  if (!cfg.hasOwnProperty('pieceTheme') ||
       (typeof cfg.pieceTheme !== 'string' &&
        typeof cfg.pieceTheme !== 'function')) {
     cfg.pieceTheme = 'img/chesspieces/wikipedia/{piece}.png';
   }
 
   // animation speeds
-  if (cfg.hasOwnProperty('appearSpeed') !== true ||
-      validAnimationSpeed(cfg.appearSpeed) !== true) {
+  if (!cfg.hasOwnProperty('appearSpeed') ||
+      !validAnimationSpeed(cfg.appearSpeed)) {
     cfg.appearSpeed = 200;
   }
-  if (cfg.hasOwnProperty('moveSpeed') !== true ||
-      validAnimationSpeed(cfg.moveSpeed) !== true) {
+  if (!cfg.hasOwnProperty('moveSpeed') ||
+      !validAnimationSpeed(cfg.moveSpeed)) {
     cfg.moveSpeed = 200;
   }
-  if (cfg.hasOwnProperty('snapbackSpeed') !== true ||
-      validAnimationSpeed(cfg.snapbackSpeed) !== true) {
+  if (!cfg.hasOwnProperty('snapbackSpeed') ||
+      !validAnimationSpeed(cfg.snapbackSpeed)) {
     cfg.snapbackSpeed = 50;
   }
-  if (cfg.hasOwnProperty('snapSpeed') !== true ||
-      validAnimationSpeed(cfg.snapSpeed) !== true) {
+  if (!cfg.hasOwnProperty('snapSpeed') ||
+      !validAnimationSpeed(cfg.snapSpeed)) {
     cfg.snapSpeed = 25;
   }
-  if (cfg.hasOwnProperty('trashSpeed') !== true ||
-      validAnimationSpeed(cfg.trashSpeed) !== true) {
+  if (!cfg.hasOwnProperty('trashSpeed') ||
+      !validAnimationSpeed(cfg.trashSpeed)) {
     cfg.trashSpeed = 100;
   }
 
   // make sure position is valid
-  if (cfg.hasOwnProperty('position') === true) {
+  if (cfg.hasOwnProperty('position')) {
     if (cfg.position === 'start') {
       CURRENT_POSITION = deepCopy(START_POSITION);
     }
 
-    else if (validFen(cfg.position) === true) {
+    else if (validFen(cfg.position)) {
       CURRENT_POSITION = fenToObj(cfg.position);
     }
 
-    else if (validPositionObject(cfg.position) === true) {
+    else if (validPositionObject(cfg.position)) {
       CURRENT_POSITION = deepCopy(cfg.position);
     }
 
@@ -458,7 +458,7 @@ function buildBoard(orientation) {
         'style="grid-row: ' + (i+1) + '; grid-column: ' + (j+1) + ';" ' +
         'data-square="' + square + '">';
 
-      if (cfg.showNotation === true) {
+      if (cfg.showNotation) {
         // alpha notation
         if ((orientation === 'white' && row === 1) ||
             (orientation === 'black' && row === 8)) {
@@ -550,57 +550,6 @@ function findSquarePosition(square) {
   };
 }
 
-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 = [];
@@ -658,39 +607,79 @@ function doAnimations(a, oldPos, newPos) {
   }
 
   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();
     }
 
     // run their onMoveEnd function
-    if (cfg.hasOwnProperty('onMoveEnd') === true &&
+    if (cfg.hasOwnProperty('onMoveEnd') &&
       typeof cfg.onMoveEnd === 'function') {
       cfg.onMoveEnd(deepCopy(oldPos), deepCopy(newPos));
     }
   }
 
-  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
@@ -744,9 +733,9 @@ function calculateAnimations(pos1, pos2) {
 
   // remove pieces that are the same in both positions
   for (var i in pos2) {
-    if (pos2.hasOwnProperty(i) !== true) continue;
+    if (!pos2.hasOwnProperty(i)) continue;
 
-    if (pos1.hasOwnProperty(i) === true && pos1[i] === pos2[i]) {
+    if (pos1.hasOwnProperty(i) && pos1[i] === pos2[i]) {
       delete pos1[i];
       delete pos2[i];
     }
@@ -754,7 +743,7 @@ function calculateAnimations(pos1, pos2) {
 
   // find all the "move" animations
   for (var i in pos2) {
-    if (pos2.hasOwnProperty(i) !== true) continue;
+    if (!pos2.hasOwnProperty(i)) continue;
 
     var closestPiece = findClosestPiece(pos1, pos2[i], i);
     if (closestPiece !== false) {
@@ -773,7 +762,7 @@ function calculateAnimations(pos1, pos2) {
 
   // add pieces to pos2
   for (var i in pos2) {
-    if (pos2.hasOwnProperty(i) !== true) continue;
+    if (!pos2.hasOwnProperty(i)) continue;
 
     animations.push({
       type: 'add',
@@ -786,11 +775,11 @@ function calculateAnimations(pos1, pos2) {
 
   // clear pieces from pos1
   for (var i in pos1) {
-    if (pos1.hasOwnProperty(i) !== true) continue;
+    if (!pos1.hasOwnProperty(i)) continue;
 
     // do not clear a piece if it is on a square that is the result
     // of a "move", ie: a piece capture
-    if (squaresMovedTo.hasOwnProperty(i) === true) continue;
+    if (squaresMovedTo.hasOwnProperty(i)) continue;
 
     animations.push({
       type: 'clear',
@@ -835,10 +824,10 @@ function calculatePositionFromMoves(position, moves) {
   position = deepCopy(position);
 
   for (var i in moves) {
-    if (moves.hasOwnProperty(i) !== true) continue;
+    if (!moves.hasOwnProperty(i)) continue;
 
     // skip the move if the position doesn't have a piece on the source square
-    if (position.hasOwnProperty(i) !== true) continue;
+    if (!position.hasOwnProperty(i)) continue;
 
     var piece = position[i];
     delete position[i];
@@ -858,7 +847,7 @@ function setCurrentPosition(position) {
   if (oldFen === newFen) return;
 
   // run their onChange function
-  if (cfg.hasOwnProperty('onChange') === true &&
+  if (cfg.hasOwnProperty('onChange') &&
     typeof cfg.onChange === 'function') {
     cfg.onChange(oldPos, newPos);
   }
@@ -882,7 +871,7 @@ function snapbackDraggedPiece() {
     drawPositionInstant();
 
     // run their onSnapbackEnd function
-    if (cfg.hasOwnProperty('onSnapbackEnd') === true &&
+    if (cfg.hasOwnProperty('onSnapbackEnd') &&
       typeof cfg.onSnapbackEnd === 'function') {
       cfg.onSnapbackEnd(DRAGGED_PIECE, DRAGGED_PIECE_SOURCE,
         deepCopy(CURRENT_POSITION), CURRENT_ORIENTATION);
@@ -911,7 +900,7 @@ function dropDraggedPieceOnSquare(square) {
 
   if (DRAGGED_PIECE_SOURCE === square) {
     // Nothing to do, but call onSnapEnd anyway
-    if (cfg.hasOwnProperty('onSnapEnd') === true && typeof cfg.onSnapEnd === 'function') {
+    if (cfg.hasOwnProperty('onSnapEnd') && typeof cfg.onSnapEnd === 'function') {
       cfg.onSnapEnd(DRAGGED_PIECE_SOURCE, square, DRAGGED_PIECE);
     }
     return;
@@ -935,7 +924,7 @@ function dropDraggedPieceOnSquare(square) {
     drawPositionInstant();
 
     // execute their onSnapEnd function
-    if (cfg.hasOwnProperty('onSnapEnd') === true &&
+    if (cfg.hasOwnProperty('onSnapEnd') &&
       typeof cfg.onSnapEnd === 'function') {
       requestAnimationFrame(() => {  // HACK: so that we don't add event handlers from the callback...
         cfg.onSnapEnd(DRAGGED_PIECE_SOURCE, square, DRAGGED_PIECE);
@@ -1041,13 +1030,13 @@ function stopDraggedPiece(location) {
   }
 
   // run their onDrop function, which can potentially change the drop action
-  if (cfg.hasOwnProperty('onDrop') === true &&
+  if (cfg.hasOwnProperty('onDrop') &&
     typeof cfg.onDrop === 'function') {
     var newPosition = deepCopy(CURRENT_POSITION);
 
     // source piece was on the board and position is on the board
-    if (validSquare(DRAGGED_PIECE_SOURCE) === true &&
-      validSquare(location.square) === true) {
+    if (validSquare(DRAGGED_PIECE_SOURCE) &&
+      validSquare(location.square)) {
       // move the piece
       delete newPosition[DRAGGED_PIECE_SOURCE];
       newPosition[location.square] = DRAGGED_PIECE;
@@ -1137,7 +1126,7 @@ widget.move = function() {
     }
 
     // skip invalid arguments
-    if (validMove(arguments[i]) !== true) {
+    if (!validMove(arguments[i])) {
       error(2826, 'Invalid move passed to the move method.', arguments[i]);
       continue;
     }
@@ -1205,17 +1194,17 @@ widget.position = function(position, useAnimation) {
   }
 
   // convert FEN to position object
-  if (validFen(position) === true) {
+  if (validFen(position)) {
     position = fenToObj(position);
   }
 
   // validate position object
-  if (validPositionObject(position) !== true) {
+  if (!validPositionObject(position)) {
     error(6482, 'Invalid value passed to the position method.', position);
     return;
   }
 
-  if (useAnimation === true) {
+  if (useAnimation) {
     // start the animations
     doAnimations(calculateAnimations(CURRENT_POSITION, position),
       CURRENT_POSITION, position);
@@ -1253,12 +1242,12 @@ function mousedownSquare(e) {
 
   // no piece on this square
   if (!validSquare(square) ||
-      CURRENT_POSITION.hasOwnProperty(square) !== true) {
+      !CURRENT_POSITION.hasOwnProperty(square)) {
     return;
   }
 
   // do nothing if we're not draggable
-  if (cfg.draggable !== true) return;
+  if (!cfg.draggable) return;
 
   beginDraggingPiece(square, CURRENT_POSITION[square], e.pageX, e.pageY);
 }
@@ -1270,13 +1259,13 @@ function touchstartSquare(e) {
   }
 
   // do nothing if we're not draggable
-  if (cfg.draggable !== true) return;
+  if (!cfg.draggable) return;
 
   var square = target.getAttribute('data-square');
 
   // no piece on this square
-  if (validSquare(square) !== true ||
-      CURRENT_POSITION.hasOwnProperty(square) !== true) {
+  if (!validSquare(square) ||
+      !CURRENT_POSITION.hasOwnProperty(square)) {
     return;
   }
 
@@ -1286,14 +1275,14 @@ function touchstartSquare(e) {
 
 function mousemoveWindow(e) {
   // do nothing if we are not dragging a piece
-  if (DRAGGING_A_PIECE !== true) return;
+  if (!DRAGGING_A_PIECE) return;
 
   updateDraggedPiece(findSquareFromEvent(e.pageX, e.pageY));
 }
 
 function touchmoveWindow(e) {
   // do nothing if we are not dragging a piece
-  if (DRAGGING_A_PIECE !== true) return;
+  if (!DRAGGING_A_PIECE) return;
 
   // prevent screen from scrolling
   e.preventDefault();
@@ -1304,18 +1293,14 @@ function touchmoveWindow(e) {
 
 function mouseupWindow(e) {
   // do nothing if we are not dragging a piece
-  if (DRAGGING_A_PIECE !== true) return;
+  if (!DRAGGING_A_PIECE) return;
 
   stopDraggedPiece(findSquareFromEvent(e.pageX, e.pageY));
 }
 
 function touchendWindow(e) {
   // do nothing if we are not dragging a piece
-  if (DRAGGING_A_PIECE !== true) return;
-
-  // get the location
-  var location = isXYOnSquare(e.changedTouches[0].pageX,
-    e.changedTouches[0].pageY);
+  if (!DRAGGING_A_PIECE) return;
 
   stopDraggedPiece(findSquareFromEvent(e.changedTouches[0].pageX,
     e.changedTouches[0].pageY));
@@ -1331,18 +1316,18 @@ function mouseenterSquare(e) {
   // NOTE: this should never happen, but it's a safeguard
   if (DRAGGING_A_PIECE !== false) return;
 
-  if (cfg.hasOwnProperty('onMouseoverSquare') !== true ||
+  if (!cfg.hasOwnProperty('onMouseoverSquare') ||
     typeof cfg.onMouseoverSquare !== 'function') return;
 
   // get the square
   var square = target.getAttribute('data-square');
 
   // NOTE: this should never happen; defensive
-  if (validSquare(square) !== true) return;
+  if (!validSquare(square)) return;
 
   // get the piece on this square
   var piece = false;
-  if (CURRENT_POSITION.hasOwnProperty(square) === true) {
+  if (CURRENT_POSITION.hasOwnProperty(square)) {
     piece = CURRENT_POSITION[square];
   }
 
@@ -1361,18 +1346,18 @@ function mouseleaveSquare(e) {
   // NOTE: this should never happen, but it's a safeguard
   if (DRAGGING_A_PIECE !== false) return;
 
-  if (cfg.hasOwnProperty('onMouseoutSquare') !== true ||
+  if (!cfg.hasOwnProperty('onMouseoutSquare') ||
     typeof cfg.onMouseoutSquare !== 'function') return;
 
   // get the square
   var square = target.getAttribute('data-square');
 
   // NOTE: this should never happen; defensive
-  if (validSquare(square) !== true) return;
+  if (!validSquare(square)) return;
 
   // get the piece on this square
   var piece = false;
-  if (CURRENT_POSITION.hasOwnProperty(square) === true) {
+  if (CURRENT_POSITION.hasOwnProperty(square)) {
     piece = CURRENT_POSITION[square];
   }
 
@@ -1406,7 +1391,7 @@ function addEvents() {
   window.addEventListener('mouseup', mouseupWindow);
 
   // touch drag pieces
-  if (isTouchDevice() === true) {
+  if (isTouchDevice()) {
     boardEl.addEventListener('touchstart', touchstartSquare);
     window.addEventListener('touchmove', touchmoveWindow);
     window.addEventListener('touchend', touchendWindow);
@@ -1423,8 +1408,7 @@ function initDom() {
 }
 
 function init() {
-  if (checkDeps() !== true ||
-      expandConfig() !== true) return;
+  if (!checkDeps() || !expandConfig()) return;
 
   initDom();
   addEvents();