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) {
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;
}
}
// 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;
}
// 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;
}
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;
*/
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;
}
// validate config / set default options
function expandConfig() {
- if (typeof cfg === 'string' || validPositionObject(cfg) === true) {
+ if (typeof cfg === 'string' || validPositionObject(cfg)) {
cfg = {
position: cfg
};
}
// 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);
}
'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)) {
};
}
-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();
}
// 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
// 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];
}
// 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) {
// add pieces to pos2
for (var i in pos2) {
- if (pos2.hasOwnProperty(i) !== true) continue;
+ if (!pos2.hasOwnProperty(i)) continue;
animations.push({
type: 'add',
// 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',
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];
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);
}
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);
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;
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);
}
// 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;
}
// skip invalid arguments
- if (validMove(arguments[i]) !== true) {
+ if (!validMove(arguments[i])) {
error(2826, 'Invalid move passed to the move method.', arguments[i]);
continue;
}
}
// 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);
// 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);
}
}
// 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;
}
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();
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;
+ if (!DRAGGING_A_PIECE) return;
// get the location
var location = isXYOnSquare(e.changedTouches[0].pageX,
// 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];
}
// 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];
}
window.addEventListener('mouseup', mouseupWindow);
// touch drag pieces
- if (isTouchDevice() === true) {
+ if (isTouchDevice()) {
boardEl.addEventListener('touchstart', touchstartSquare);
window.addEventListener('touchmove', touchmoveWindow);
window.addEventListener('touchend', touchendWindow);
}
function init() {
- if (checkDeps() !== true ||
- expandConfig() !== true) return;
+ if (!checkDeps() || !expandConfig()) return;
initDom();
addEvents();