}
// set the containerEl
- containerEl = $(el);
+ containerEl = el;
}
- // else it must be something that becomes a jQuery collection
- // with size 1
- // ie: a single DOM node or jQuery object
+ // else it must be a DOM node
else {
- containerEl = $(containerElOrId);
-
- if (containerEl.length !== 1) {
- window.alert('ChessBoard Error 1003: The first argument to ' +
- 'ChessBoard() must be an ID or a single DOM node.' +
- '\n\nExiting...');
- return false;
- }
+ containerEl = containerElOrId;
}
// JSON must exist
// fudge factor, and then keep reducing until we find an exact mod 8 for
// our square size
function calculateSquareSize() {
- var containerWidth = parseInt(containerEl.css('width'), 10);
+ var containerWidth = parseInt(getComputedStyle(containerEl).width, 10);
// defensive, prevent infinite loop
if (! containerWidth || containerWidth <= 0) {
}
html += '" />';
- return html;
+ let elem = document.createElement('template');
+ elem.innerHTML = html;
+ return elem.content;
}
function buildSparePieces(color) {
// Animations
//------------------------------------------------------------------------------
+function offset(el) { // From https://youmightnotneedjquery.com/.
+ let box = el.getBoundingClientRect();
+ let docElem = document.documentElement;
+ return {
+ top: box.top + window.pageYOffset - docElem.clientTop,
+ left: box.left + window.pageXOffset - docElem.clientLeft
+ };
+}
+
function animateSquareToSquare(src, dest, piece, completeFn) {
// get information about the source and destination squares
- var srcSquareEl = $('#' + SQUARE_ELS_IDS[src]);
- var srcSquarePosition = srcSquareEl.offset();
- var destSquareEl = $('#' + SQUARE_ELS_IDS[dest]);
- var destSquarePosition = destSquareEl.offset();
+ var srcSquareEl = document.getElementById(SQUARE_ELS_IDS[src]);
+ var srcSquarePosition = offset(srcSquareEl);
+ var destSquareEl = document.getElementById(SQUARE_ELS_IDS[dest]);
+ var destSquarePosition = offset(destSquareEl);
// create the animated piece and absolutely position it
// over the source square
var animatedPieceId = createId();
- $('body').append(buildPiece(piece, true, animatedPieceId));
- var animatedPieceEl = $('#' + animatedPieceId);
- animatedPieceEl.css({
- display: '',
- position: 'absolute',
- top: srcSquarePosition.top,
- left: srcSquarePosition.left
- });
-
- // remove original piece from source square
- srcSquareEl.find('.' + CSS.piece).remove();
+ document.body.append(buildPiece(piece, true, animatedPieceId));
+ var animatedPieceEl = document.getElementById(animatedPieceId);
+ animatedPieceEl.style.display = null;
+ animatedPieceEl.style.position = 'absolute';
+ animatedPieceEl.style.top = srcSquarePosition.top + 'px';
+ animatedPieceEl.style.left = srcSquarePosition.left + 'px';
+
+ // remove original piece(s) from source square
+ // TODO: multiple pieces should never really happen, but it will if we are moving
+ // while another animation still isn't done
+ srcSquareEl.querySelectorAll('.' + CSS.piece).forEach((piece) => piece.remove());
// on complete
var complete = function() {
};
// animate the piece to the destination square
- var opts = {
- duration: cfg.moveSpeed,
- complete: complete
- };
- animatedPieceEl.animate(destSquarePosition, opts);
+ animatedPieceEl.addEventListener('transitionend', complete, {once: true});
+ requestAnimationFrame(() => {
+ animatedPieceEl.style.transitionProperty = 'top left';
+ animatedPieceEl.style.transitionDuration = cfg.moveSpeed + 'ms';
+ animatedPieceEl.style.top = destSquarePosition.top + 'px';
+ animatedPieceEl.style.left = destSquarePosition.left + 'px';
+ });
}
function animateSparePieceToSquare(piece, dest, completeFn) {
- var srcOffset = $('#' + SPARE_PIECE_ELS_IDS[piece]).offset();
- var destSquareEl = $('#' + SQUARE_ELS_IDS[dest]);
- var destOffset = destSquareEl.offset();
+ var srcOffset = offset(document.getelementById(SPARE_PIECE_ELS_IDS[piece]));
+ var destSquareEl = document.getElementById(SQUARE_ELS_IDS[dest]);
+ var destOffset = offset(destSquareEl);
// create the animate piece
var pieceId = createId();
- $('body').append(buildPiece(piece, true, pieceId));
- var animatedPieceEl = $('#' + pieceId);
- animatedPieceEl.css({
- display: '',
- position: 'absolute',
- left: srcOffset.left,
- top: srcOffset.top
- });
+ document.body.append(buildPiece(piece, true, pieceId));
+ var animatedPieceEl = document.getElementById(pieceId);
+ animatedPieceEl.style.display = '';
+ animatedPieceEl.style.position = 'absolute';
+ animatedPieceEl.style.left = srcOffset.left;
+ animatedPieceEl.style.top = srcOffset.top;
// on complete
var complete = function() {
// add the "real" piece to the destination square
- destSquareEl.find('.' + CSS.piece).remove();
+ destSquareEl.querySelector('.' + CSS.piece).remove();
destSquareEl.append(buildPiece(piece));
// remove the animated piece
};
// animate the piece to the destination square
+ // FIXME: support this for non-jquery
var opts = {
duration: cfg.moveSpeed,
complete: complete
};
- animatedPieceEl.animate(destOffset, opts);
+ $(animatedPieceEl).animate(destOffset, opts);
+}
+
+function fadeIn(piece, onFinish) {
+ piece.style.opacity = 0;
+ piece.style.display = null;
+ piece.addEventListener('transitionend', onFinish, {once: true});
+ requestAnimationFrame(() => {
+ piece.style.transitionProperty = 'opacity';
+ piece.style.transitionDuration = cfg.appearSpeed + 'ms';
+ piece.style.opacity = 1;
+ });
+}
+
+function fadeOut(piece, onFinish) {
+ piece.style.opacity = 1;
+ piece.style.display = null;
+ piece.addEventListener('transitionend', onFinish, {once: true});
+ requestAnimationFrame(() => {
+ piece.style.transitionProperty = 'opacity';
+ piece.style.transitionDuration = cfg.trashSpeed + 'ms';
+ piece.style.opacity = 0;
+ });
}
// execute an array of animations
ANIMATION_HAPPENING = true;
var numFinished = 0;
- function onFinish() {
+ function onFinish(e) {
+ if (e && e.target) {
+ e.target.transitionProperty = null;
+ }
+
numFinished++;
// exit if all the animations aren't finished
for (var i = 0; i < a.length; i++) {
// clear a piece
if (a[i].type === 'clear') {
- $('#' + SQUARE_ELS_IDS[a[i].square] + ' .' + CSS.piece)
- .fadeOut(cfg.trashSpeed, onFinish);
+ document.getElementById(SQUARE_ELS_IDS[a[i].square]).querySelectorAll('.' + CSS.piece).forEach(
+ (piece) => fadeOut(piece, onFinish)
+ );
}
// add a piece (no spare pieces)
if (a[i].type === 'add' && cfg.sparePieces !== true) {
- $('#' + SQUARE_ELS_IDS[a[i].square])
- .append(buildPiece(a[i].piece, true))
- .find('.' + CSS.piece)
- .fadeIn(cfg.appearSpeed, onFinish);
+ let square = document.getElementById(SQUARE_ELS_IDS[a[i].square]);
+ square.append(buildPiece(a[i].piece, true));
+ let piece = square.querySelector('.' + CSS.piece);
+ fadeIn(piece, onFinish);
}
// add a piece from a spare piece
function drawPositionInstant() {
// clear the board
- boardEl.find('.' + CSS.piece).remove();
+ boardEl.querySelectorAll('.' + CSS.piece).forEach((piece) => piece.remove());
// add the pieces
for (var i in CURRENT_POSITION) {
if (CURRENT_POSITION.hasOwnProperty(i) !== true) continue;
- $('#' + SQUARE_ELS_IDS[i]).append(buildPiece(CURRENT_POSITION[i]));
+ document.getElementById(SQUARE_ELS_IDS[i]).append(buildPiece(CURRENT_POSITION[i]));
}
}
function drawBoard() {
- boardEl.html(buildBoard(CURRENT_ORIENTATION));
+ boardEl.innerHTML = buildBoard(CURRENT_ORIENTATION);
drawPositionInstant();
if (cfg.sparePieces === true) {
if (CURRENT_ORIENTATION === 'white') {
- sparePiecesTopEl.html(buildSparePieces('black'));
- sparePiecesBottomEl.html(buildSparePieces('white'));
+ sparePiecesTopEl.innerHTML = buildSparePieces('black');
+ sparePiecesBottomEl.innerHTML = buildSparePieces('white');
}
else {
- sparePiecesTopEl.html(buildSparePieces('white'));
- sparePiecesBottomEl.html(buildSparePieces('black'));
+ sparePiecesTopEl.innerHTML = buildSparePieces('white');
+ sparePiecesBottomEl.innerHTML = buildSparePieces('black');
}
}
}
for (var i in SQUARE_ELS_IDS) {
if (SQUARE_ELS_IDS.hasOwnProperty(i) !== true) continue;
- SQUARE_ELS_OFFSETS[i] = $('#' + SQUARE_ELS_IDS[i]).offset();
+ SQUARE_ELS_OFFSETS[i] = offset(document.getElementById(SQUARE_ELS_IDS[i]));
}
}
function removeSquareHighlights() {
- boardEl.find('.' + CSS.square)
- .removeClass(CSS.highlight1 + ' ' + CSS.highlight2);
+ boardEl.querySelectorAll('.' + CSS.square).forEach((piece) => {
+ piece.classList.remove(CSS.highlight1);
+ piece.classList.remove(CSS.highlight2);
+ });
}
function snapbackDraggedPiece() {
// animation complete
function complete() {
drawPositionInstant();
- draggedPieceEl.css('display', 'none');
+ draggedPieceEl.style.display = 'none';
// run their onSnapbackEnd function
if (cfg.hasOwnProperty('onSnapbackEnd') === true &&
// get source square position
var sourceSquarePosition =
- $('#' + SQUARE_ELS_IDS[DRAGGED_PIECE_SOURCE]).offset();
+ offset(document.getElementById(SQUARE_ELS_IDS[DRAGGED_PIECE_SOURCE]));
// animate the piece to the target square
- var opts = {
- duration: cfg.snapbackSpeed,
- complete: complete
- };
- draggedPieceEl.animate(sourceSquarePosition, opts);
+ draggedPieceEl.addEventListener('transitionend', complete, {once: true});
+ requestAnimationFrame(() => {
+ draggedPieceEl.style.transitionProperty = 'top left';
+ draggedPieceEl.style.transitionDuration = cfg.snapbackSpeed + 'ms';
+ draggedPieceEl.style.top = sourceSquarePosition.top + 'px';
+ draggedPieceEl.style.left = sourceSquarePosition.left + 'px';
+ });
// set state
DRAGGING_A_PIECE = false;
drawPositionInstant();
// hide the dragged piece
- draggedPieceEl.fadeOut(cfg.trashSpeed);
+ // FIXME: support this for non-jquery
+ $(draggedPieceEl).fadeOut(cfg.trashSpeed);
// set state
DRAGGING_A_PIECE = false;
setCurrentPosition(newPosition);
// get target square information
- var targetSquarePosition = $('#' + SQUARE_ELS_IDS[square]).offset();
+ var targetSquarePosition = offset(document.getElementById(SQUARE_ELS_IDS[square]));
// animation complete
var complete = function() {
drawPositionInstant();
- draggedPieceEl.css('display', 'none');
+ draggedPieceEl.style.display = 'none';
// execute their onSnapEnd function
if (cfg.hasOwnProperty('onSnapEnd') === true &&
typeof cfg.onSnapEnd === 'function') {
- cfg.onSnapEnd(DRAGGED_PIECE_SOURCE, square, DRAGGED_PIECE);
+ requestAnimationFrame(() => { // HACK: so that we don't add event handlers from the callback...
+ cfg.onSnapEnd(DRAGGED_PIECE_SOURCE, square, DRAGGED_PIECE);
+ });
}
};
// snap the piece to the target square
- var opts = {
- duration: cfg.snapSpeed,
- complete: complete
- };
- draggedPieceEl.animate(targetSquarePosition, opts);
+ draggedPieceEl.addEventListener('transitionend', complete, {once: true});
+ requestAnimationFrame(() => {
+ draggedPieceEl.style.transitionProperty = 'top left';
+ draggedPieceEl.style.transitionDuration = cfg.snapSpeed + 'ms';
+ draggedPieceEl.style.top = targetSquarePosition.top + 'px';
+ draggedPieceEl.style.left = targetSquarePosition.left + 'px';
+ });
// set state
DRAGGING_A_PIECE = false;
captureSquareOffsets();
// create the dragged piece
- draggedPieceEl.attr('src', buildPieceImgSrc(piece))
- .css({
- display: '',
- position: 'absolute',
- left: x - (SQUARE_SIZE / 2),
- top: y - (SQUARE_SIZE / 2)
- });
+ draggedPieceEl.setAttribute('src', buildPieceImgSrc(piece));
+ draggedPieceEl.style.display = null;
+ draggedPieceEl.style.position = 'absolute';
+ draggedPieceEl.style.left = (x - (SQUARE_SIZE / 2)) + 'px';
+ draggedPieceEl.style.top = (y - (SQUARE_SIZE / 2)) + 'px';
if (source !== 'spare') {
// highlight the source square and hide the piece
- $('#' + SQUARE_ELS_IDS[source]).addClass(CSS.highlight1)
- .find('.' + CSS.piece).css('display', 'none');
+ let square = document.getElementById(SQUARE_ELS_IDS[source]);
+ square.classList.add(CSS.highlight1);
+ square.querySelector('.' + CSS.piece).style.display = 'none';
}
}
function updateDraggedPiece(x, y) {
// put the dragged piece over the mouse cursor
- draggedPieceEl.css({
- left: x - (SQUARE_SIZE / 2),
- top: y - (SQUARE_SIZE / 2)
- });
+ draggedPieceEl.style.left = (x - (SQUARE_SIZE / 2)) + 'px';
+ draggedPieceEl.style.top = (y - (SQUARE_SIZE / 2)) + 'px';
// get location
var location = isXYOnSquare(x, y);
// remove highlight from previous square
if (validSquare(DRAGGED_PIECE_LOCATION) === true) {
- $('#' + SQUARE_ELS_IDS[DRAGGED_PIECE_LOCATION])
- .removeClass(CSS.highlight2);
+ document.getElementById(SQUARE_ELS_IDS[DRAGGED_PIECE_LOCATION])
+ .classList.remove(CSS.highlight2);
}
// add highlight to new square
if (validSquare(location) === true) {
- $('#' + SQUARE_ELS_IDS[location]).addClass(CSS.highlight2);
+ document.getElementById(SQUARE_ELS_IDS[location]).classList.add(CSS.highlight2);
}
// run onDragMove
// remove the widget from the page
widget.destroy = function() {
// remove markup
- containerEl.html('');
+ containerEl.innerHTML = '';
draggedPieceEl.remove();
-
- // remove event handlers
- containerEl.unbind();
};
// shorthand method to get the current FEN
SQUARE_SIZE = calculateSquareSize();
// set board width
- boardEl.css('width', (SQUARE_SIZE * 8) + 'px');
+ boardEl.style.width = (SQUARE_SIZE * 8) + 'px';
// set drag piece size
- draggedPieceEl.css({
- height: SQUARE_SIZE,
- width: SQUARE_SIZE
- });
+ if (draggedPieceEl !== null) {
+ draggedPieceEl.style.height = SQUARE_SIZE + 'px';
+ draggedPieceEl.style.width = SQUARE_SIZE + 'px';
+ }
// spare pieces
if (cfg.sparePieces === true) {
- containerEl.find('.' + CSS.sparePieces)
- .css('paddingLeft', (SQUARE_SIZE + BOARD_BORDER_SIZE) + 'px');
+ containerEl.querySelector('.' + CSS.sparePieces)
+ .style.paddingLeft = (SQUARE_SIZE + BOARD_BORDER_SIZE) + 'px';
}
// redraw the board
return ('ontouchstart' in document.documentElement);
}
-// reference: http://www.quirksmode.org/js/detect.html
-function isMSIE() {
- return (navigator && navigator.userAgent &&
- navigator.userAgent.search(/MSIE/) !== -1);
-}
-
-function stopDefault(e) {
- e.preventDefault();
-}
-
function mousedownSquare(e) {
+ let target = e.target.closest('.' + CSS.square);
+ if (!target) {
+ return;
+ }
+
// do nothing if we're not draggable
if (cfg.draggable !== true) return;
- var square = $(this).attr('data-square');
+ var square = target.getAttribute('data-square');
// no piece on this square
if (validSquare(square) !== true ||
}
function touchstartSquare(e) {
+ let target = e.target.closest('.' + CSS.square);
+ if (!target) {
+ return;
+ }
+
// do nothing if we're not draggable
if (cfg.draggable !== true) return;
- var square = $(this).attr('data-square');
+ var square = target.getAttribute('data-square');
// no piece on this square
if (validSquare(square) !== true ||
}
function mousedownSparePiece(e) {
+ if (!e.target.matches('.' + CSS.sparePieces + ' .' + CSS.piece)) {
+ return;
+ }
+
// do nothing if sparePieces is not enabled
if (cfg.sparePieces !== true) return;
- var piece = $(this).attr('data-piece');
+ var piece = e.target.getAttribute('data-piece');
beginDraggingPiece('spare', piece, e.pageX, e.pageY);
}
function touchstartSparePiece(e) {
+ if (!e.target.matches('.' + CSS.sparePieces + ' .' + CSS.piece)) {
+ return;
+ }
+
// do nothing if sparePieces is not enabled
if (cfg.sparePieces !== true) return;
- var piece = $(this).attr('data-piece');
+ var piece = e.target.getAttribute('data-piece');
e = e.originalEvent;
beginDraggingPiece('spare', piece,
}
function mouseenterSquare(e) {
+ let target = e.target.closest('.' + CSS.square);
+ if (!target) {
+ return;
+ }
+
// do not fire this event if we are dragging a piece
// NOTE: this should never happen, but it's a safeguard
if (DRAGGING_A_PIECE !== false) return;
typeof cfg.onMouseoverSquare !== 'function') return;
// get the square
- var square = $(e.currentTarget).attr('data-square');
+ var square = target.getAttribute('data-square');
// NOTE: this should never happen; defensive
if (validSquare(square) !== true) return;
}
function mouseleaveSquare(e) {
+ let target = e.target.closest('.' + CSS.square);
+ if (!target) {
+ return;
+ }
+
// do not fire this event if we are dragging a piece
// NOTE: this should never happen, but it's a safeguard
if (DRAGGING_A_PIECE !== false) return;
typeof cfg.onMouseoutSquare !== 'function') return;
// get the square
- var square = $(e.currentTarget).attr('data-square');
+ var square = target.getAttribute('data-square');
// NOTE: this should never happen; defensive
if (validSquare(square) !== true) return;
function addEvents() {
// prevent browser "image drag"
- $('body').on('mousedown mousemove', '.' + CSS.piece, stopDefault);
+ let stopDefault = (e) => {
+ if (e.target.matches('.' + CSS.piece)) {
+ e.preventDefault();
+ }
+ };
+ document.body.addEventListener('mousedown', stopDefault);
+ document.body.addEventListener('mousemove', stopDefault);
// mouse drag pieces
- boardEl.on('mousedown', '.' + CSS.square, mousedownSquare);
- containerEl.on('mousedown', '.' + CSS.sparePieces + ' .' + CSS.piece,
- mousedownSparePiece);
+ boardEl.addEventListener('mousedown', mousedownSquare);
+ containerEl.addEventListener('mousedown', mousedownSparePiece);
// mouse enter / leave square
- boardEl.on('mouseenter', '.' + CSS.square, mouseenterSquare);
- boardEl.on('mouseleave', '.' + CSS.square, mouseleaveSquare);
+ boardEl.addEventListener('mouseenter', mouseenterSquare);
+ boardEl.addEventListener('mouseleave', mouseleaveSquare);
- // IE doesn't like the events on the window object, but other browsers
- // perform better that way
- if (isMSIE() === true) {
- // IE-specific prevent browser "image drag"
- document.ondragstart = function() { return false; };
-
- $('body').on('mousemove', mousemoveWindow);
- $('body').on('mouseup', mouseupWindow);
- }
- else {
- $(window).on('mousemove', mousemoveWindow);
- $(window).on('mouseup', mouseupWindow);
- }
+ window.addEventListener('mousemove', mousemoveWindow);
+ window.addEventListener('mouseup', mouseupWindow);
// touch drag pieces
if (isTouchDevice() === true) {
- boardEl.on('touchstart', '.' + CSS.square, touchstartSquare);
- containerEl.on('touchstart', '.' + CSS.sparePieces + ' .' + CSS.piece,
- touchstartSparePiece);
- $(window).on('touchmove', touchmoveWindow);
- $(window).on('touchend', touchendWindow);
+ boardEl.addEventListener('touchstart', touchstartSquare);
+ containerEl.addEventListener('touchstart', touchstartSparePiece);
+ window.addEventListener('touchmove', touchmoveWindow);
+ window.addEventListener('touchend', touchendWindow);
}
}
function initDom() {
// build board and save it in memory
- containerEl.html(buildBoardContainer());
- boardEl = containerEl.find('.' + CSS.board);
+ containerEl.innerHTML = buildBoardContainer();
+ boardEl = containerEl.querySelector('.' + CSS.board);
if (cfg.sparePieces === true) {
- sparePiecesTopEl = containerEl.find('.' + CSS.sparePiecesTop);
- sparePiecesBottomEl = containerEl.find('.' + CSS.sparePiecesBottom);
+ sparePiecesTopEl = containerEl.querySelector('.' + CSS.sparePiecesTop);
+ sparePiecesBottomEl = containerEl.querySelector('.' + CSS.sparePiecesBottom);
}
// create the drag piece
var draggedPieceId = createId();
- $('body').append(buildPiece('wP', true, draggedPieceId));
- draggedPieceEl = $('#' + draggedPieceId);
+ document.body.append(buildPiece('wP', true, draggedPieceId));
+ draggedPieceEl = document.getElementById(draggedPieceId);
// get the border size
- BOARD_BORDER_SIZE = parseInt(boardEl.css('borderLeftWidth'), 10);
+ BOARD_BORDER_SIZE = parseInt(boardEl.style.borderLeftWidth, 10);
// set the size and draw the board
widget.resize();