X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=www%2Fjs%2Fchessboard-0.3.0.js;h=a1a6fbcb2523cc2ba5274f9dbdac15bf7fb6a8a1;hb=d283085484150e7ae0107d2a53a8ebe9263c430f;hp=451f1a9f4d17cf73ed93c0b52788ccfb2cda1577;hpb=4615f6b5ba23f497b8f43b9a38a410925d35ff91;p=remoteglot diff --git a/www/js/chessboard-0.3.0.js b/www/js/chessboard-0.3.0.js index 451f1a9..a1a6fbc 100644 --- a/www/js/chessboard-0.3.0.js +++ b/www/js/chessboard-0.3.0.js @@ -199,8 +199,7 @@ cfg = cfg || {}; // Constants //------------------------------------------------------------------------------ -var MINIMUM_JQUERY_VERSION = '1.7.0', - START_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR', +var START_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR', START_POSITION = fenToObj(START_FEN); // use unique class names to prevent clashing with anything else on the page @@ -216,9 +215,6 @@ var CSS = { numeric: 'numeric-fc462', piece: 'piece-417db', row: 'row-5277c', - sparePieces: 'spare-pieces-7492f', - sparePiecesBottom: 'spare-pieces-bottom-ae20f', - sparePiecesTop: 'spare-pieces-top-4028b', square: 'square-55d63' }; var CSSColor = {}; @@ -232,9 +228,7 @@ CSSColor['black'] = 'black-3c85d'; // DOM elements var containerEl, boardEl, - draggedPieceEl, - sparePiecesTopEl, - sparePiecesBottomEl; + draggedPieceEl; // constructor return object var widget = {}; @@ -243,8 +237,7 @@ var widget = {}; // Stateful //------------------------------------------------------------------------------ -var ANIMATION_HAPPENING = false, - BOARD_BORDER_SIZE = 2, +var BOARD_BORDER_SIZE = 2, CURRENT_ORIENTATION = 'white', CURRENT_POSITION = {}, SQUARE_SIZE, @@ -252,7 +245,6 @@ var ANIMATION_HAPPENING = false, DRAGGED_PIECE_LOCATION, DRAGGED_PIECE_SOURCE, DRAGGING_A_PIECE = false, - SPARE_PIECE_ELS_IDS = {}, SQUARE_ELS_IDS = {}, SQUARE_ELS_OFFSETS; @@ -260,40 +252,15 @@ var ANIMATION_HAPPENING = false, // JS Util Functions //------------------------------------------------------------------------------ -// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript +let id_counter = 0; function createId() { - return 'xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx'.replace(/x/g, function(c) { - var r = Math.random() * 16 | 0; - return r.toString(16); - }); + return 'chesspiece-id-' + (id_counter++); } function deepCopy(thing) { return JSON.parse(JSON.stringify(thing)); } -function parseSemVer(version) { - var tmp = version.split('.'); - return { - major: parseInt(tmp[0], 10), - minor: parseInt(tmp[1], 10), - patch: parseInt(tmp[2], 10) - }; -} - -// returns true if version is >= minimum -function compareSemVer(version, minimum) { - version = parseSemVer(version); - minimum = parseSemVer(minimum); - - var versionNum = (version.major * 10000 * 10000) + - (version.minor * 10000) + version.patch; - var minimumNum = (minimum.major * 10000 * 10000) + - (minimum.minor * 10000) + minimum.patch; - - return (versionNum >= minimumNum); -} - //------------------------------------------------------------------------------ // Validation / Errors //------------------------------------------------------------------------------ @@ -407,21 +374,6 @@ function expandConfig() { cfg.draggable = false; } - // default for dropOffBoard is 'snapback' - if (cfg.dropOffBoard !== 'trash') { - cfg.dropOffBoard = 'snapback'; - } - - // default for sparePieces is false - if (cfg.sparePieces !== true) { - cfg.sparePieces = false; - } - - // draggable must be true if sparePieces is enabled - if (cfg.sparePieces === true) { - cfg.draggable = true; - } - // default piece theme is wikipedia if (cfg.hasOwnProperty('pieceTheme') !== true || (typeof cfg.pieceTheme !== 'string' && @@ -509,15 +461,6 @@ function createElIds() { SQUARE_ELS_IDS[square] = square + '-' + createId(); } } - - // spare pieces - var pieces = 'KQRBNP'.split(''); - for (var i = 0; i < pieces.length; i++) { - var whitePiece = 'w' + pieces[i]; - var blackPiece = 'b' + pieces[i]; - SPARE_PIECE_ELS_IDS[whitePiece] = whitePiece + '-' + createId(); - SPARE_PIECE_ELS_IDS[blackPiece] = blackPiece + '-' + createId(); - } } //------------------------------------------------------------------------------ @@ -527,18 +470,8 @@ function createElIds() { function buildBoardContainer() { var html = '
'; - if (cfg.sparePieces === true) { - html += '
'; - } - html += '
'; - if (cfg.sparePieces === true) { - html += '
'; - } - html += '
'; return html; @@ -641,37 +574,20 @@ function buildPieceImgSrc(piece) { * @param {!string=} id */ function buildPiece(piece, hidden, id) { - var html = ''; - - let elem = document.createElement('template'); - elem.innerHTML = html; - return elem.content; -} - -function buildSparePieces(color) { - var pieces = ['wK', 'wQ', 'wR', 'wB', 'wN', 'wP']; - if (color === 'black') { - pieces = ['bK', 'bQ', 'bR', 'bB', 'bN', 'bP']; - } - - var html = ''; - for (var i = 0; i < pieces.length; i++) { - html += buildPiece(pieces[i], false, SPARE_PIECE_ELS_IDS[pieces[i]]); - } - - return html; + return img; } //------------------------------------------------------------------------------ @@ -733,70 +649,38 @@ function animateSquareToSquare(src, dest, piece, completeFn) { }); } -function animateSparePieceToSquare(piece, dest, completeFn) { - 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(); - 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.querySelector('.' + CSS.piece).remove(); - destSquareEl.append(buildPiece(piece)); - - // remove the animated piece - animatedPieceEl.remove(); - - // run complete function - if (typeof completeFn === 'function') { - completeFn(); - } - }; - - // animate the piece to the destination square - // FIXME: support this for non-jquery - var opts = { - duration: cfg.moveSpeed, - complete: complete - }; - //$(animatedPieceEl).animate(destOffset, opts); -} - -function fadeIn(piece, onFinish) { - piece.style.opacity = 0; - piece.style.display = null; - piece.addEventListener('transitionend', onFinish, {once: true}); +function fadeIn(pieces, onFinish) { + pieces.forEach((piece) => { + 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; + pieces.forEach((piece) => { + 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}); +function fadeOut(pieces, onFinish) { + pieces.forEach((piece) => { + 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; + 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) { - ANIMATION_HAPPENING = true; - var numFinished = 0; function onFinish(e) { if (e && e.target) { @@ -809,7 +693,6 @@ function doAnimations(a, oldPos, newPos) { if (numFinished !== a.length) return; drawPositionInstant(); - ANIMATION_HAPPENING = false; // run their onMoveEnd function if (cfg.hasOwnProperty('onMoveEnd') === true && @@ -819,25 +702,23 @@ function doAnimations(a, oldPos, newPos) { } requestAnimationFrame(() => { // Firefox workaround. + let fadeout_pieces = []; + let fadein_pieces = []; + for (var i = 0; i < a.length; i++) { // clear a piece if (a[i].type === 'clear') { document.getElementById(SQUARE_ELS_IDS[a[i].square]).querySelectorAll('.' + CSS.piece).forEach( - (piece) => fadeOut(piece, onFinish) + (piece) => fadeout_pieces.push(piece) ); } - // add a piece (no spare pieces) - if (a[i].type === 'add' && cfg.sparePieces !== true) { + // add a piece + if (a[i].type === 'add') { 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 - if (a[i].type === 'add' && cfg.sparePieces === true) { - animateSparePieceToSquare(a[i].piece, a[i].square, onFinish); + fadein_pieces.push(piece); } // move a piece @@ -846,6 +727,15 @@ function doAnimations(a, oldPos, newPos) { onFinish); } } + + // TODO: Batch moves as well, not just fade in/out. + // (We batch them because requestAnimationFrame seemingly costs real time.) + if (fadeout_pieces.length > 0) { + fadeOut(fadeout_pieces, onFinish); + } + if (fadein_pieces.length > 0) { + fadeIn(fadein_pieces, onFinish); + } }); } @@ -866,55 +756,26 @@ function squareDistance(s1, s2) { return yDelta; } -// returns an array of closest squares from square -function createRadius(square) { - var squares = []; - - // calculate distance of all squares - for (var i = 0; i < 8; i++) { - for (var j = 0; j < 8; j++) { - var s = COLUMNS[i] + (j + 1); - - // skip the square we're starting from - if (square === s) continue; - - squares.push({ - square: s, - distance: squareDistance(square, s) - }); - } - } - - // sort by distance - squares.sort(function(a, b) { - return a.distance - b.distance; - }); - - // just return the square code - var squares2 = []; - for (var i = 0; i < squares.length; i++) { - squares2.push(squares[i].square); - } - - return squares2; -} - // returns the square of the closest instance of piece // returns false if no instance of piece is found in position function findClosestPiece(position, piece, square) { - // create array of closest squares from square - var closestSquares = createRadius(square); - - // search through the position in order of distance for the piece - for (var i = 0; i < closestSquares.length; i++) { - var s = closestSquares[i]; + let best_square = false; + let best_dist = 1e9; + for (var i = 0; i < COLUMNS.length; i++) { + for (var j = 1; j <= 8; j++) { + let other_square = COLUMNS[i] + j; - if (position.hasOwnProperty(s) === true && position[s] === piece) { - return s; + if (position[other_square] === piece && square != other_square) { + let dist = squareDistance(square, other_square); + if (dist < best_dist) { + best_square = other_square; + best_dist = dist; + } + } } } - return false; + return best_square; } // calculate an array of animations that need to happen in order to get @@ -1008,17 +869,6 @@ function drawPositionInstant() { function drawBoard() { boardEl.innerHTML = buildBoard(CURRENT_ORIENTATION); drawPositionInstant(); - - if (cfg.sparePieces === true) { - if (CURRENT_ORIENTATION === 'white') { - sparePiecesTopEl.innerHTML = buildSparePieces('black'); - sparePiecesBottomEl.innerHTML = buildSparePieces('white'); - } - else { - sparePiecesTopEl.innerHTML = buildSparePieces('white'); - sparePiecesBottomEl.innerHTML = buildSparePieces('black'); - } - } } // given a position and a set of moves, return a new position @@ -1092,12 +942,6 @@ function removeSquareHighlights() { } function snapbackDraggedPiece() { - // there is no "snapback" for spare pieces - if (DRAGGED_PIECE_SOURCE === 'spare') { - trashDraggedPiece(); - return; - } - removeSquareHighlights(); // animation complete @@ -1130,25 +974,6 @@ function snapbackDraggedPiece() { DRAGGING_A_PIECE = false; } -function trashDraggedPiece() { - removeSquareHighlights(); - - // remove the source piece - var newPosition = deepCopy(CURRENT_POSITION); - delete newPosition[DRAGGED_PIECE_SOURCE]; - setCurrentPosition(newPosition); - - // redraw the position - drawPositionInstant(); - - // hide the dragged piece - // FIXME: support this for non-jquery - //$(draggedPieceEl).fadeOut(cfg.trashSpeed); - - // set state - DRAGGING_A_PIECE = false; -} - function dropDraggedPieceOnSquare(square) { removeSquareHighlights(); @@ -1201,14 +1026,7 @@ function beginDraggingPiece(source, piece, x, y) { DRAGGING_A_PIECE = true; DRAGGED_PIECE = piece; DRAGGED_PIECE_SOURCE = source; - - // if the piece came from spare pieces, location is offboard - if (source === 'spare') { - DRAGGED_PIECE_LOCATION = 'offboard'; - } - else { - DRAGGED_PIECE_LOCATION = source; - } + DRAGGED_PIECE_LOCATION = source; // capture the x, y coords of all squares in memory captureSquareOffsets(); @@ -1220,12 +1038,10 @@ function beginDraggingPiece(source, piece, x, y) { 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 - let square = document.getElementById(SQUARE_ELS_IDS[source]); - square.classList.add(CSS.highlight1); - square.querySelector('.' + CSS.piece).style.display = 'none'; - } + // highlight the source square and hide the piece + let square = document.getElementById(SQUARE_ELS_IDS[source]); + square.classList.add(CSS.highlight1); + square.querySelector('.' + CSS.piece).style.display = 'none'; } function updateDraggedPiece(x, y) { @@ -1267,25 +1083,12 @@ function stopDraggedPiece(location) { if (location === 'offboard' && cfg.dropOffBoard === 'snapback') { action = 'snapback'; } - if (location === 'offboard' && cfg.dropOffBoard === 'trash') { - action = 'trash'; - } // run their onDrop function, which can potentially change the drop action if (cfg.hasOwnProperty('onDrop') === true && typeof cfg.onDrop === 'function') { var newPosition = deepCopy(CURRENT_POSITION); - // source piece is a spare piece and position is off the board - //if (DRAGGED_PIECE_SOURCE === 'spare' && location === 'offboard') {...} - // position has not changed; do nothing - - // source piece is a spare piece and position is on the board - if (DRAGGED_PIECE_SOURCE === 'spare' && validSquare(location) === true) { - // add the piece to the board - newPosition[location] = DRAGGED_PIECE; - } - // source piece was on the board and position is off the board if (validSquare(DRAGGED_PIECE_SOURCE) === true && location === 'offboard') { // remove the piece from the board @@ -1304,7 +1107,7 @@ function stopDraggedPiece(location) { var result = cfg.onDrop(DRAGGED_PIECE_SOURCE, location, DRAGGED_PIECE, newPosition, oldPosition, CURRENT_ORIENTATION); - if (result === 'snapback' || result === 'trash') { + if (result === 'snapback') { action = result; } } @@ -1313,9 +1116,6 @@ function stopDraggedPiece(location) { if (action === 'snapback') { snapbackDraggedPiece(); } - else if (action === 'trash') { - trashDraggedPiece(); - } else if (action === 'drop') { dropDraggedPieceOnSquare(location); } @@ -1488,12 +1288,6 @@ widget.resize = function() { draggedPieceEl.style.width = SQUARE_SIZE + 'px'; } - // spare pieces - if (cfg.sparePieces === true) { - containerEl.querySelector('.' + CSS.sparePieces) - .style.paddingLeft = (SQUARE_SIZE + BOARD_BORDER_SIZE) + 'px'; - } - // redraw the board drawBoard(); }; @@ -1548,39 +1342,10 @@ function touchstartSquare(e) { return; } - e = e.originalEvent; beginDraggingPiece(square, CURRENT_POSITION[square], e.changedTouches[0].pageX, e.changedTouches[0].pageY); } -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 = 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 = e.target.getAttribute('data-piece'); - - e = e.originalEvent; - beginDraggingPiece('spare', piece, - e.changedTouches[0].pageX, e.changedTouches[0].pageY); -} - function mousemoveWindow(e) { // do nothing if we are not dragging a piece if (DRAGGING_A_PIECE !== true) return; @@ -1595,8 +1360,8 @@ function touchmoveWindow(e) { // prevent screen from scrolling e.preventDefault(); - updateDraggedPiece(e.originalEvent.changedTouches[0].pageX, - e.originalEvent.changedTouches[0].pageY); + updateDraggedPiece(e.changedTouches[0].pageX, + e.changedTouches[0].pageY); } function mouseupWindow(e) { @@ -1614,8 +1379,8 @@ function touchendWindow(e) { if (DRAGGING_A_PIECE !== true) return; // get the location - var location = isXYOnSquare(e.originalEvent.changedTouches[0].pageX, - e.originalEvent.changedTouches[0].pageY); + var location = isXYOnSquare(e.changedTouches[0].pageX, + e.changedTouches[0].pageY); stopDraggedPiece(location); } @@ -1696,7 +1461,6 @@ function addEvents() { // mouse drag pieces boardEl.addEventListener('mousedown', mousedownSquare); - containerEl.addEventListener('mousedown', mousedownSparePiece); // mouse enter / leave square boardEl.addEventListener('mouseenter', mouseenterSquare); @@ -1708,7 +1472,6 @@ function addEvents() { // touch drag pieces if (isTouchDevice() === true) { boardEl.addEventListener('touchstart', touchstartSquare); - containerEl.addEventListener('touchstart', touchstartSparePiece); window.addEventListener('touchmove', touchmoveWindow); window.addEventListener('touchend', touchendWindow); } @@ -1719,11 +1482,6 @@ function initDom() { containerEl.innerHTML = buildBoardContainer(); boardEl = containerEl.querySelector('.' + CSS.board); - if (cfg.sparePieces === true) { - sparePiecesTopEl = containerEl.querySelector('.' + CSS.sparePiecesTop); - sparePiecesBottomEl = containerEl.querySelector('.' + CSS.sparePiecesBottom); - } - // create the drag piece var draggedPieceId = createId(); document.body.append(buildPiece('wP', true, draggedPieceId));