I'm working on a personal project to build a website that quizzes users on chess opening theory moves. I know my code is not very object-oriented but I am working on refactoring it right now. I just wanted to get the basics of it working before I started to restructure everything.

Here is the link to the repo to see all of the code. The website is live on Github pages if you want to try it out right now (I have not added anything to the Results section yet).

My question is how can I improve my JavaScript code to make it shorter for the menuJQeuryFunctions.js file? The file is over 1000 lines of just JQuery functions, there must be a way to truncate this code.

Here is a snippet of my HTML code:

        <div id="container">
            <div id="flex-div nav">
                <nav class="openings-menu">
                    <div class="text">Openings Menu</div>
                    <ul class="parent">
                        <li><a href="#" class="level-1-btn" id="kings-pawn-opening">King's Pawn Opening<span class="fas fa-angle-down kings-pawn-arrow"></span></a></li>
                            <ul class="level-2-class" id="kings-pawn-show">
                                <li><a href="#" class="level-2-btn" id="sicilian-defence">Sicilian Defence<span class="fas fa-angle-down"></a></li>
                                    <ul class="level-3-class" id="sicilian-defence-show">
                                        <li><a href="#" class="level-3-btn" id="open-sicilian">Open Sicilian<span class="fas fa-angle-down"></a></li>
                                            <ul class="level-4-class" id="open-sicilian-show">
                                                <li><a href="#" class="level-4-btn" id="najdorf-variation">Najdorf Variation<span class="fas fa-angle-down"</a></li>
                                                    <ul class="level-5-class" id="najdorf-variation-show">
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-classical">Classical Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-english">English Attack</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-lipnitzky">Lipnitzky Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-opocensky">Opocensky Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-amsterdam">Amsterdam Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-adams">Adams Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="sicilian-najdorf-argentine">Argentine Variation</a></li>
                                                <li><a href="#" class="level-4-btn" id="dragon-variation">Dragon Variation<span class="fas fa-angle-down"></a></li>
                                                    <ul class="level-5-class" id="dragon-variation-show">
                                                        <li><a href="#" class="level-5-btn" id="dragon-positional">Positional Line</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-yugoslav">Yugoslav Attack</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-soltis">Soltis Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-classical">Classical Variation</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-levenfish">Levenfish Attack</a></li>
                                                        <li><a href="#" class="level-5-btn" id="dragon-harrington-glek">Harrington-Glek Variation</a></li>

Here is what a snippet of my script.js code looks like. This code runs the main chess game after it knows what opening is selected.

let board = null
let $board = $('#board')
const game = new Chess()
let squareClass = 'square-55d63'
let squareToHighlight = null
let colorToHighlight = null
let $status = $('#status')
let $fen = $('#fen')
let $pgn = $('#pgn')
let variation = []
let attempt = []
let totalMoves = 0

// updates three variables which are the colour's turn, FEN, and PGN
// after each move is made and prints to the HTML tags
function updateStatus () {
    let status = ''
    let moveColor = 'White'

    if (game.turn() === 'b') {
        moveColor = 'Black'

    // checkmate?
    if (game.in_checkmate()) {
        status = 'Game over, ' + moveColor + ' is in checkmate.'

    // draw?
    else if (game.in_draw()) {
        status = 'Game over, drawn position'
    } else { // game still on
        status = moveColor + ' to move'

        // check?
        if (game.in_check()) {
          status += ', ' + moveColor + ' is in check'

    // update html id tags

function removeHighlights (color) {
    $board.find('.' + squareClass).removeClass('highlight-' + color)

function onDragStart (source, piece, position, orientation) {
    // do not pick up pieces if the game is over
    if (game.game_over()) return false

    if (variation.length === 0) {
        if ((game.turn() === 'w' && piece.search(/^b/) !== -1) ||
            (game.turn() === 'b' && piece.search(/^w/) !== -1)) {
            return false
    } else {
        // only pick up pieces for White
        if (piece.search(/^b/) !== -1) return false

function onDrop (source, target) {
    // see if the move is legal
    let move = game.move({
        from: source,
        to: target,

        // not necessary to have this i think
        // promotion: 'q' // NOTE: always promote to a queen for example simplicity

    // illegal move
    if (move === null) return 'snapback'

    attempt = game.history()

    if (variation.length !== 0) {
        if (attempt[attempt.length-1] !== variation[attempt.length-1]) {
        } else {
            // highlight white's move
            $board.find('.square-' + source).addClass('highlight-white')
            $board.find('.square-' + target).addClass('highlight-white')

            // make random move for black
            window.setTimeout(makeBlackMove, 250)
    } else {
        if (move.color === 'w') {
            $board.find('.square-' + move.from).addClass('highlight-white')
            squareToHighlight = move.to
            colorToHighlight = 'white'
        if (move.color === "b") {
            $board.find('.square-' + move.from).addClass('highlight-black')
            squareToHighlight = move.to
            colorToHighlight = 'black'


function highlightSquare() {
    // will possibly use this later

function makeBlackMove() {
    let blackMove = game.history({verbose: true})
    // console.log(blackMove)

    // highlight black's move
    $board.find('.square-' + blackMove[attempt.length].from).addClass('highlight-black')
    squareToHighlight = blackMove[attempt.length].to

    // update the board to the new position

    attempt = game.history()

function onMoveEnd() {
    $board.find('.square-' + squareToHighlight).addClass('highlight-black')

// update the board position after the piece snap
// for castling, en passant, pawn promotion
function onSnapEnd() {
    if (variation.length === 0) {
        $board.find('.square-' + squareToHighlight).addClass('highlight-'+ colorToHighlight)

function showHint() {
    if (variation.length !== 0 && game.turn() === "w") {
        let hintSquare = game.move(variation[attempt.length])
        hintSquare = hintSquare.from
        $board.find('.' + squareClass).removeClass('highlight-hint')
        $board.find('.square-' + hintSquare).addClass('highlight-hint')

function flipBoard() {
    if (board.orientation() === "white") {
        $board.find('.square-' + squareToHighlight).addClass('highlight-'+colorToHighlight)
    } else {
        $board.find('.square-' + squareToHighlight).addClass('highlight-'+colorToHighlight)

function startGame() {
    let config = {
        draggable: true,
        position: 'start',
        onDragStart: onDragStart,
        onDrop: onDrop,
        onSnapEnd: onSnapEnd,
        onMoveEnd: onMoveEnd
    variation = []
    attempt = []
    board = Chessboard('board', config)
    totalMoves = 0

// this function is called after every move is made and updates the turn status,
// FEN and PGN

// when page loads, initialize the chess board to the starting position

// when the reset button is pressed it resets the game state,
// and resets the status variables



Lastly, here is the JQuery code for each time the menu item opening variation is clicked on. The fact that the code is over 1000 lines (but I'm only going to show a portion of it because it's very repetitive code) of just almost the same JQuery functions but with different opening variation names makes me think I can shorten it.

// openings menu scripts
$("#kings-pawn-opening").click(function() {
    // $("#kings-pawn-arrow").toggleClass("rotate");

$("#sicilian-defence").click(function() {

$("#open-sicilian").click(function() {
$("#najdorf-variation").click(function() {

$("#sicilian-najdorf-classical").click(function() {
    variation = sicilianNajdorfClassicalMainLine

$("#sicilian-najdorf-english").click(function() {
    variation = sicilianNajdorfEnglishAttack

$("#sicilian-najdorf-lipnitzky").click(function() {
    variation = sicilianNajdorfLipnitzkyAttack
$("#sicilian-najdorf-opocensky").click(function() {
    variation = sicilianNajdorfOpocensky
$("#sicilian-najdorf-amsterdam").click(function() {
    variation = sicilianNajdorfAmsterdam

Here is a snippet of the chess opening variation arrays that I am using:

// ----------------------- OPEN SICILIAN -----------------------
// sicilian najdorf 
const sicilianNajdorfClassicalMainLine = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Bg5", "e6", "f4", "Be7", "Qf3", "Qc7", "O-O-O", "Nbd7", "g4"]
const sicilianNajdorfArgentine = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Bg5", "e6", "f4", "Be7", "Qf3", "Qc7", "h6", "Bh4", "g5", "fxg5", "Nfd7"] // maybe not include this one
const sicilianNajdorfEnglishAttack = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Be3", "e5", "Nb3", "Be6", "f3"]
const sicilianNajdorfLipnitzkyAttack = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Bc4", "e6", "Bb3", "b5"]
const sicilianNajdorfOpocensky = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "Be2", "e6"] // maybe not include this one
const sicilianNajdorfAmsterdam = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "f4", "e5", "Nf3", "Nbd7", "a4", "Be7", "Bd3", "O-O"]
const sicilianNajdorfAdams = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "a6", "h3", "e5", "Nde2", "h5"]

// sicilian dragon 
const sicilianDragonPositional = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'g6', 'Be3', 'Bg7', 'f3', 'O-O', 'Qd2', 'Nc6', 'O-O-O']
const sicilianDragonYugoslav = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "g6", "Be3", "Bg7", "f3", "O-O", "Qd2", "Nc6", "Bc4", "Bd7", "O-O-O", "Rc8", "Bb3", "Ne5", "h4", "Nc4", "Bxc4", "Rxc4", "h5", "Nxh5", "g4", "Nf6", "Bh6"]
const sicilianDragonSoltis = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'g6', 'Be3', 'Bg7', 'f3', 'O-O', 'Qd2', 'Nc6', 'Bc4', 'Bd7', 'O-O-O', 'Rc8', 'Bb3', 'Ne5', 'h4', 'h5']
const sicilianDragonClassical = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "g6", "Be2", "Bg7", "Be3", "Nc6", "O-O", "O-O", "Nb3", "d5"]
const sicilianDragonLevenfish = ["e4", "c5", "Nf3", "d6", "d4", "cxd4", "Nxd4", "Nf6", "Nc3", "g6", "f4", "Nc6", "e5"]
const sicilianDragonHarrington = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'g6', 'Be3', 'Bg7', 'Be2', 'O-O', 'Qd2', 'Nc6', 'O-O-O']

// sicilian classical
const sicilianRichter = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Bg5', 'e6', 'Qd2']
const sicilianFischerSozin = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Bc4', 'e6', 'Bb3', 'a6', 'O-O']
const sicilianVelimirovic = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Bc4', 'e6', 'Be3', 'Be7', 'Qe2']
const sicilianBoleslavsky = ['e4', 'c5', 'Nf3', 'd6', 'd4', 'cxd4', 'Nxd4', 'Nf6', 'Nc3', 'Nc6', 'Be2', 'e5', 'Nf3', 'h6', 'O-O', 'Be7', 'Re1', 'O-O', 'h3']
  • 1
    \$\begingroup\$ Welcome to Code Review! I changed the title so that it describes what the code does per site goals: "State what your code does in your title, not your main concerns about it.". Please check that I haven't misrepresented your code, and correct it if I have. \$\endgroup\$ Sep 30 at 7:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.