diff --git a/public/vendor/pgn4web/pgn4web.js b/public/vendor/pgn4web/pgn4web.js index 8e2af01000..ca89af4211 100644 --- a/public/vendor/pgn4web/pgn4web.js +++ b/public/vendor/pgn4web/pgn4web.js @@ -1,29 +1,29 @@ /* * pgn4web javascript chessboard - * copyright (C) 2009-2012 Paolo Casaschi + * copyright (C) 2009-2013 Paolo Casaschi * see README file and http://pgn4web.casaschi.net * for credits, license and more details */ -var pgn4web_version = '2.61'; +"use strict"; + +var pgn4web_version = '2.77'; var pgn4web_project_url = "http://pgn4web.casaschi.net"; var pgn4web_project_author = "Paolo Casaschi"; var pgn4web_project_email; // preassigned in pgn4web-server-config.js if (typeof(pgn4web_project_email) == "undefined") { pgn4web_project_email = "pgn4web@casaschi.net"; } -var helpWin=null; +var helpWin; function displayHelp(section) { - section = !section ? "" : "?" + section; if (helpWin && !helpWin.closed) { helpWin.close(); } - helpWin = window.open(detectHelpLocation() + section, "pgn4web_help", + helpWin = window.open(detectHelpLocation() + (section ? "?" + section : ""), "pgn4web_help", "resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no"); if (helpWin && window.focus) { helpWin.focus(); } } -// custom functions for given events -// to be redefined AFTER pgn4web.js +// empty event APIs to be redefined function customFunctionOnPgnTextLoad() {} function customFunctionOnPgnGameLoad() {} @@ -31,47 +31,58 @@ function customFunctionOnMove() {} function customFunctionOnAlert(msg) {} function customFunctionOnCheckLiveBroadcastStatus() {} -// custom header tags APIs for customFunctionOnPgnGameLoad() +// custom header tags APIs for customFunctionOnPgnGameLoad -function customPgnHeaderTag(customTagString, htmlElementIdString, gameNum) { - customTagString = customTagString.replace(/\W+/g, ""); +function customPgnHeaderTag(customTag, htmlElementId, gameNum) { + var matches, tag = ""; + customTag = customTag.replace(/\W+/g, ""); if (gameNum === undefined) { gameNum = currentGame; } - if ((pgnHeader[gameNum]) && (tagValues = pgnHeader[gameNum].match('\\[\\s*' + customTagString + '\\s*\"([^\"]+)\"\\s*\\]'))) { - tagValue = tagValues[1]; - } else { tagValue = ""; } - if ((htmlElementIdString) && (theObj = document.getElementById(htmlElementIdString)) && (typeof(theObj.innerHTML) == "string")) { - theObj.innerHTML = tagValue; + if ((pgnHeader[gameNum]) && (matches = pgnHeader[gameNum].match('\\[\\s*' + customTag + '\\s*\"([^\"]+)\"\\s*\\]'))) { tag = matches[1]; } + if (htmlElementId) { + var theObj = document.getElementById(htmlElementId); + if ((theObj) && (typeof(theObj.innerHTML) == "string")) { theObj.innerHTML = tag; } } - return tagValue; + return tag; } -// custom comment tags APIS for customFunctionOnMove() +// custom comment tags API for customFunctionOnMove -function customPgnCommentTag(customTagString, htmlElementIdString, plyNum, varId) { - customTagString = customTagString.replace(/\W+/g, ""); +function customPgnCommentTag(customTag, htmlElementId, plyNum, varId) { + var matches, tag = "", theObj; + customTag = customTag.replace(/\W+/g, ""); if (typeof(varId) == "undefined") { varId = 0; } if (typeof(plyNum) == "undefined") { plyNum = CurrentPly; } - if ((MoveCommentsVar[varId][plyNum]) && (tagValues = MoveCommentsVar[varId][plyNum].match('\\[%' + customTagString + '\\s+((?:,?(?:"[^"]*"|[^,\\]]*))*)\\s*\\]'))) { - tagValue = tagValues[1].replace(/\s+$/, ""); - } else { tagValue = ""; } - if ((htmlElementIdString) && (theObj = document.getElementById(htmlElementIdString)) && (typeof(theObj.innerHTML) == "string")) { - theObj.innerHTML = tagValue; - } - return tagValue; + if ((MoveCommentsVar[varId][plyNum]) && (matches = MoveCommentsVar[varId][plyNum].match('\\[%' + customTag + '\\s+((?:,?(?:"[^"]*"|[^,\\]]*))*)\\s*\\]'))) { tag = matches[1].replace(/\s+$/, ""); } + if ((htmlElementId) && (theObj = document.getElementById(htmlElementId)) && (typeof(theObj.innerHTML) == "string")) { theObj.innerHTML = tag; } + return tag; } -window.onload = start_pgn4web; +function simpleAddEvent(obj, evt, cbk) { + if (obj.addEventListener) { obj.addEventListener(evt, cbk, false); } + else if (obj.attachEvent) { obj.attachEvent("on" + evt, cbk); } // IE8- +} -document.onkeydown = handlekey; +simpleAddEvent(document, "keydown", pgn4web_handleKey_event); +simpleAddEvent(window, "load", pgn4web_onload_event); + + +function pgn4web_onload_event(e) { + pgn4web_onload(e); +} + +function pgn4web_onload(e) { + start_pgn4web(); +} function start_pgn4web() { - // keep startup logs at first run, reset when reloading start_pgn4web + // keep startup logs at the very first run, otherwise reset if (alertFirstResetLoadingPgn) { alertFirstResetLoadingPgn = false; } else { resetAlert(); } InitImages(); createBoard(); if (LiveBroadcastDelay > 0) { restartLiveBroadcastTimeout(); } + pgn4web_initTouchEvents(); } var alertLog; @@ -95,16 +106,14 @@ function resetAlert() { } } -function myAlert(msg, fatalError) { +function myAlert(msg, fatalError, doNotPrompt) { alertNum++; alertNumSinceReset++; if (fatalError) { fatalErrorNumSinceReset++; } alertLast = (alertLast + 1) % alertLog.length; alertLog[alertLast] = msg + "\n" + (new Date()).toLocaleString(); if (boardIsDefault(debugShortcutSquare)) { boardShortcut(debugShortcutSquare, "pgn4web v" + pgn4web_version + " debug info, " + alertNum + " alert" + (alertNum > 1 ? "s" : ""), null, true); } - if (((LiveBroadcastDelay === 0) || (LiveBroadcastAlert === true)) && (boardIsDefault(debugShortcutSquare))) { - startAlertPrompt(); - } + if ((!doNotPrompt) && ((LiveBroadcastDelay === 0) || (LiveBroadcastAlert === true)) && (boardIsDefault(debugShortcutSquare))) { startAlertPrompt(); } customFunctionOnAlert(msg); } @@ -127,13 +136,16 @@ function alertPromptTick(restart) { clearTimeout(alertPromptInterval); alertPromptInterval = null; } - var debugColRow = colRowFromSquare(debugShortcutSquare); - if (!debugColRow) { return; } - if (theObj = document.getElementById('tcol' + debugColRow.col + 'trow' + debugColRow.row)) { + var colRow = colRowFromSquare(debugShortcutSquare); + if (!colRow) { return; } + + var alertPromptDelay = 1500; // for alerts before the board is printed + var theObj = document.getElementById('tcol' + colRow.col + 'trow' + colRow.row); + if (theObj) { if (alertPromptOn) { if ((highlightOption) && - ((lastColFromHighlighted === 0 && lastRowFromHighlighted === 7) || - (lastColToHighlighted === 0 && lastRowToHighlighted === 7))) { + ((colFromHighlighted === 0 && rowFromHighlighted === 7) || + (colToHighlighted === 0 && rowToHighlighted === 7))) { theObj.className = 'highlightWhiteSquare'; } else { theObj.className = 'whiteSquare'; } } else { theObj.className = 'blackSquare'; } @@ -141,12 +153,12 @@ function alertPromptTick(restart) { alertPromptOn = !alertPromptOn; if (alertPromptOn) { alertPromptDelay = 500; } else { alertPromptDelay = 3000; } - } else { alertPromptDelay = 1500; } // alerts before the baord is drawn + } if (restart) { alertPromptInterval = setTimeout("alertPromptTick(true);", alertPromptDelay); } } -function stopKeyProp(e) { +function stopEvProp(e) { e.cancelBubble = true; if (e.stopPropagation) { e.stopPropagation(); } if (e.preventDefault) { e.preventDefault(); } @@ -176,9 +188,13 @@ function customShortcutKey_Shift_7() {} function customShortcutKey_Shift_8() {} function customShortcutKey_Shift_9() {} +function pgn4web_handleKey_event(e) { + pgn4web_handleKey(e); +} + var shortcutKeysEnabled = false; -function handlekey(e) { - var keycode, oldPly, oldVar; +function pgn4web_handleKey(e) { + var keycode, oldPly, oldVar, colRow, colRowList; if (!e) { e = window.event; } @@ -197,10 +213,10 @@ function handlekey(e) { case 17: // ctrl case 18: // alt case 32: // space - case 35: // end - case 36: // home case 33: // page-up case 34: // page-down + case 35: // end + case 36: // home case 92: // super case 93: // menu case 188: // comma @@ -211,6 +227,16 @@ function handlekey(e) { else { displayHelp(); } break; + case 189: // dash + if (colRowList = prompt("Enter shortcut square coordinates to click:", "")) { + colRowList = colRowList.toUpperCase().replace(/[^A-Z0-9]/g,""); + while (colRow = colRowFromSquare(colRowList)) { + boardOnClick[colRow.col][colRow.row]({"id": "img_tcol" + colRow.col + "trow" + colRow.row}, e); + colRowList = colRowList.substr(2); + } + } + break; + case 90: // z if (e.shiftKey) { window.open(pgn4web_project_url); } else { displayDebugInfo(); } @@ -263,7 +289,8 @@ function handlekey(e) { break; case 83: // s - searchPgnGamePrompt(); + if (e.shiftKey) { searchPgnGame(""); } + else { searchPgnGamePrompt(); } break; case 13: // enter @@ -273,7 +300,11 @@ function handlekey(e) { case 68: // d if (e.shiftKey) { displayFenData(); } - else { displayPgnData(false); } + else { displayPgnData(true); } + break; + + case 187: // equal + SwitchAutoPlay(); break; case 65: // a @@ -328,7 +359,7 @@ function handlekey(e) { case 57: // 9 if (e.shiftKey) { customShortcutKey_Shift_9(); } - else { SetAutoplayDelayAndStart( 9*1000); } + else { setCustomAutoplayDelay(); } break; case 81: // q @@ -353,7 +384,7 @@ function handlekey(e) { break; case 89: // y - resumeLiveBroadcast(); + restartLiveBroadcast(); break; case 70: // f @@ -400,13 +431,13 @@ function handlekey(e) { default: return true; } - return stopKeyProp(e); + return stopEvProp(e); } -boardOnClick = new Array(8); -boardTitle = new Array(8); -boardDefault = new Array(8); -for (col=0; col<8; col++) { +var boardOnClick = new Array(8); +var boardTitle = new Array(8); +var boardDefault = new Array(8); +for (var col=0; col<8; col++) { boardOnClick[col] = new Array(8); boardTitle[col] = new Array(8); boardDefault[col] = new Array(8); @@ -414,7 +445,7 @@ for (col=0; col<8; col++) { clearShortcutSquares("ABCDEFGH", "12345678"); function colRowFromSquare(square) { - if (square.charCodeAt === null) { return -1; } + if ((typeof(square) != "string") || (!square)) { return null; } var col = square.charCodeAt(0) - 65; // 65="A" if ((col < 0) || (col > 7)) { return null; } var row = 56 - square.charCodeAt(1); // 56="8" @@ -423,9 +454,9 @@ function colRowFromSquare(square) { } function clearShortcutSquares(cols, rows) { - if ((typeof cols != "string") || (typeof rows != "string")) { return; } - for (c=0; c 1) { Init(0); } }, true); -boardShortcut("B3", "jump to previous games decile", function(t,e){ if (currentGame > 0) { calculateDeciles(); for (ii=(deciles.length-2); ii>=0; ii--) { if (currentGame > deciles[ii]) { Init(deciles[ii]); break; } } } }, true); +boardShortcut("B3", "jump to previous games decile", function(t,e){ if (currentGame > 0) { calculateDeciles(); for (var ii=(deciles.length-2); ii>=0; ii--) { if (currentGame > deciles[ii]) { Init(deciles[ii]); break; } } } }, true); boardShortcut("C3", "load previous game", function(t,e){ Init(currentGame - 1); }, true); @@ -546,7 +576,7 @@ boardShortcut("E3", "load random game at random position", function(t,e){ random boardShortcut("F3", "load next game", function(t,e){ Init(currentGame + 1); }, true); -boardShortcut("G3", "jump to next games decile", function(t,e){ if (currentGame < numberOfGames - 1) { calculateDeciles(); for (ii=1; ii 1) { Init(numberOfGames - 1); } }, true); @@ -568,21 +598,37 @@ boardShortcut("H2", "replay the previous half-move, then autoplay forward", func boardShortcut("A1", "go to game start", function(t,e){ startButton(e); }, true); -boardShortcut("B1", "", function(t,e){}, true); // see setB1C1F1G1boardShortcuts() +boardShortcut("B1", "", function(t,e){}, true); // see setB1C1F1G1... -boardShortcut("C1", "", function(t,e){}, true); // see setB1C1F1G1boardShortcuts() +boardShortcut("C1", "", function(t,e){}, true); // see setB1C1F1G1... boardShortcut("D1", "move backward", function(t,e){ GoToMove(CurrentPly - 1); }, true); boardShortcut("E1", "move forward", function(t,e){ GoToMove(CurrentPly + 1); }, true); -boardShortcut("F1", "", function(t,e){}, true); // see setB1C1F1G1boardShortcuts() +boardShortcut("F1", "", function(t,e){}, true); // see setB1C1F1G1... -boardShortcut("G1", "", function(t,e){}, true); // see setB1C1F1G1boardShortcuts() +boardShortcut("G1", "", function(t,e){}, true); // see setB1C1F1G1... boardShortcut("H1", "go to game end", function(t,e){ endButton(e); }, true); +setG7A6B6H7boardShortcuts(); + +function setG7A6B6H7boardShortcuts() { + if (LiveBroadcastDelay > 0) { + if (boardIsDefault("G7")) { boardShortcut("G7", "", function(t,e){}, true); } + if (boardIsDefault("A6")) { boardShortcut("A6", "pause live broadcast automatic games refresh", function(t,e){ pauseLiveBroadcast(); }, true); } + if (boardIsDefault("B6")) { boardShortcut("B6", "restart live broadcast automatic games refresh", function(t,e){ restartLiveBroadcast(); }, true); } + if (boardIsDefault("H6")) { boardShortcut("H6", "force live broadcast games refresh", function(t,e){ refreshPgnSource(); }, true); } + } else { + if (boardIsDefault("G7")) { boardShortcut("G7", "toggle autoplay next game", function(t,e){ SetAutoplayNextGame(!autoplayNextGame); }, true); } + if (boardIsDefault("A6")) { boardShortcut("A6", "", function(t,e){}, true); } + if (boardIsDefault("B6")) { boardShortcut("B6", "", function(t,e){}, true); } + if (boardIsDefault("H6")) { boardShortcut("H6", "", function(t,e){}, true); } + } +} + setB1C1F1G1boardShortcuts(); function setB1C1F1G1boardShortcuts() { @@ -602,19 +648,20 @@ function setB1C1F1G1boardShortcuts() { } } + var deciles = new Array(11); function calculateDeciles() { - for (ii=0; ii 0) { - for (ii = 0; iipgn4web debug info" + "" + "\n
\n" + dbg1 + location.href + " " + dbg3 +
-        "\n
\n"; - debugWin.document.open("text/html", "replace"); - debugWin.document.write(text); + "\n\n"); debugWin.document.close(); if (window.focus) { debugWin.focus(); } } @@ -705,16 +755,15 @@ function liveStatusDebug() { function customDebugInfo() { return ""; } -pgnWin = null; -function displayPgnData(allGames) { - if (typeof(allGames) == "undefined") { allGames = true; } +var pgnWin; +function displayPgnData(oneGameOnly) { if (pgnWin && !pgnWin.closed) { pgnWin.close(); } - pgnWin = window.open("", "pgn_data", "resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no"); + pgnWin = window.open("", "pgn4web_pgn_data", "resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no"); if (pgnWin) { - text = "pgn4web PGN source" + + var text = "pgn4web PGN source" + "\n
\n";
-    if (allGames) { for (ii = 0; ii < numberOfGames; ++ii) { text += fullPgnGame(ii) + "\n\n"; } }
-    else { text += fullPgnGame(currentGame); }
+    if (oneGameOnly) { text += fullPgnGame(currentGame) + "\n\n"; }
+    else { for (var ii = 0; ii < numberOfGames; ++ii) { text += fullPgnGame(ii) + "\n\n"; } }
     text += "\n
\n"; pgnWin.document.open("text/html", "replace"); pgnWin.document.write(text); @@ -723,108 +772,112 @@ function displayPgnData(allGames) { } } -function CurrentFEN() { - currentFEN = ""; +function savePgnData(oneGameOnly) { + if (pgnUrl && !oneGameOnly) { location.href = pgnUrl; } + else { + displayPgnData(oneGameOnly); // fallback on displayPgnData for now + } +} - emptyCounterFen = 0; - for (row=7; row>=0; row--) { - for (col=0; col<=7; col++) { - if (Board[col][row] === 0) { emptyCounterFen++; } +function CurrentFEN() { + var thisFEN = ""; + + var emptySquares = 0; + for (var row=7; row>=0; row--) { + for (var col=0; col<=7; col++) { + if (Board[col][row] === 0) { emptySquares++; } else { - if (emptyCounterFen > 0) { - currentFEN += "" + emptyCounterFen; - emptyCounterFen = 0; + if (emptySquares) { + thisFEN += emptySquares; + emptySquares = 0; } - if (Board[col][row] > 0) { currentFEN += FenPieceName.charAt(Board[col][row]-1).toUpperCase(); } - else if (Board[col][row] < 0) { currentFEN += FenPieceName.charAt(-Board[col][row]-1).toLowerCase(); } + if (Board[col][row] > 0) { thisFEN += FenPieceName.charAt(Board[col][row]-1).toUpperCase(); } + else if (Board[col][row] < 0) { thisFEN += FenPieceName.charAt(-Board[col][row]-1).toLowerCase(); } } } - if (emptyCounterFen > 0) { - currentFEN += "" + emptyCounterFen; - emptyCounterFen = 0; + if (emptySquares) { + thisFEN += emptySquares; + emptySquares = 0; } - if (row>0) { currentFEN += "/"; } + if (row>0) { thisFEN += "/"; } } - // active color - currentFEN += CurrentPly%2 === 0 ? " w" : " b"; + thisFEN += CurrentPly%2 ? " b" : " w"; - // castling availability, always in the KQkq form - // (wrong FEN for for Chess960 positions with an inner castling rook) - CastlingFEN = ""; + // castling availability: always in the KQkq form + // note: wrong FEN for Chess960 positions with inner castling rook + var CastlingFEN = ""; if (RookForOOCastling(0) !== null) { CastlingFEN += FenPieceName.charAt(0).toUpperCase(); } if (RookForOOOCastling(0) !== null) { CastlingFEN += FenPieceName.charAt(1).toUpperCase(); } if (RookForOOCastling(1) !== null) { CastlingFEN += FenPieceName.charAt(0).toLowerCase(); } if (RookForOOOCastling(1) !== null) { CastlingFEN += FenPieceName.charAt(1).toLowerCase(); } - currentFEN += " " + (CastlingFEN ? CastlingFEN : "-"); + thisFEN += " " + (CastlingFEN || "-"); - // en-passant square if (HistEnPassant[CurrentPly]) { - currentFEN += " " + String.fromCharCode(HistEnPassantCol[CurrentPly] + 97); - currentFEN += CurrentPly%2 === 0 ? "6" : "3"; - } else { currentFEN += " -"; } + thisFEN += " " + String.fromCharCode(HistEnPassantCol[CurrentPly] + 97); + thisFEN += CurrentPly%2 ? "3" : "6"; + } else { thisFEN += " -"; } - // halfmove clock - HalfMoveClock = InitialHalfMoveClock; - for (thisPly = StartPly; thisPly < CurrentPly; thisPly++) { + var HalfMoveClock = InitialHalfMoveClock; + for (var thisPly = StartPly; thisPly < CurrentPly; thisPly++) { if ((HistType[0][thisPly] == 6) || (HistPieceId[1][thisPly] >= 16)) { HalfMoveClock = 0; } else { HalfMoveClock++; } } - currentFEN += " " + HalfMoveClock; + thisFEN += " " + HalfMoveClock; - // fullmove number - currentFEN += " " + (Math.floor(CurrentPly/2)+1); + thisFEN += " " + (Math.floor(CurrentPly/2)+1); - return currentFEN; + return thisFEN; } -fenWin = null; -function displayFenData() { +var fenWin; +function displayFenData(addGametext) { if (fenWin && !fenWin.closed) { fenWin.close(); } - currentFEN = CurrentFEN(); + var thisFEN = CurrentFEN(); - currentMovesString = ""; - lastLineStart = 0; - for (var thisPly = CurrentPly; thisPly <= StartPlyVar[CurrentVar] + PlyNumberVar[CurrentVar]; thisPly++) { - addToMovesString = ""; - if (thisPly == StartPlyVar[CurrentVar] + PlyNumberVar[CurrentVar]) { - if (CurrentVar === 0 && gameResult[currentGame] && gameResult[currentGame] != "*") { - addToMovesString = gameResult[currentGame]; + var movesStr = ""; + var lineStart = 0; + if (addGametext) { + for (var thisPly = CurrentPly; thisPly <= StartPly + PlyNumber; thisPly++) { + var addStr = ""; + if (thisPly == StartPly + PlyNumber) { + addStr = (CurrentVar ? "*" : gameResult[currentGame] || "*"); + } else { + if (thisPly%2 === 0) { addStr = (Math.floor(thisPly/2)+1) + ". "; } + else if (thisPly == CurrentPly) { addStr = (Math.floor(thisPly/2)+1) + "... "; } + addStr += Moves[thisPly]; } - } else { - if (thisPly%2 === 0) { addToMovesString = (Math.floor(thisPly/2)+1) + ". "; } - else if (thisPly == CurrentPly) { - addToMovesString = (Math.floor(thisPly/2)+1) + "... "; + if (movesStr.length + addStr.length + 1 > lineStart + 80) { + lineStart = movesStr.length; + movesStr += "\n" + addStr; + } else { + if (movesStr.length > 0) { movesStr += " "; } + movesStr += addStr; } - addToMovesString += Moves[thisPly]; - } - if (currentMovesString.length + addToMovesString.length + 1 > lastLineStart + 80) { - lastLineStart = currentMovesString.length; - currentMovesString += "\n" + addToMovesString; - } else { - if (currentMovesString.length > 0) { currentMovesString += " "; } - currentMovesString += addToMovesString; } } - fenWin = window.open("", "fen_data", "resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no"); + fenWin = window.open("", "pgn4web_fen_data", "resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no"); if (fenWin) { - text = "" + + var text = "" + "pgn4web FEN string" + - "\n
\n\n" + currentFEN + "\n\n
\n
\n
\n\n" +
-      "[Event \"" + (gameEvent[currentGame] ? gameEvent[currentGame] : "?") + "\"]\n" +
-      "[Site \"" + (gameSite[currentGame] ? gameSite[currentGame] : "?") + "\"]\n" +
-      "[Date \"" + (gameDate[currentGame] ? gameDate[currentGame] : "????.??.??") + "\"]\n" +
-      "[Round \"" + (gameRound[currentGame] ? gameRound[currentGame] : "?") + "\"]\n" +
-      "[White \"" + (gameWhite[currentGame] ? gameWhite[currentGame] : "?") + "\"]\n" +
-      "[Black \"" + (gameBlack[currentGame] ? gameBlack[currentGame] : "?") + "\"]\n" +
-      "[Result \"" + (gameResult[currentGame] ? gameResult[currentGame] : "*") + "\"]\n";
-    if (currentFEN != FenStringStart) {
-      text += "[SetUp \"1\"]\n" + "[FEN \"" + CurrentFEN() + "\"]\n";
+      "\n
\n\n" + thisFEN + "\n\n
\n
\n
\n\n";
+    if (addGametext) {
+      text += "[Event \""  + ((CurrentVar ? "" : gameEvent[currentGame])  || "?") + "\"]\n" +
+      "[Site \""   + ((CurrentVar ? "" : gameSite[currentGame])   || "?") + "\"]\n" +
+      "[Date \""   + ((CurrentVar ? "" : gameDate[currentGame])   || "????.??.??") + "\"]\n" +
+      "[Round \""  + ((CurrentVar ? "" : gameRound[currentGame])  || "?") + "\"]\n" +
+      "[White \""  + ((CurrentVar ? "" : gameWhite[currentGame])  || "?") + "\"]\n" +
+      "[Black \""  + ((CurrentVar ? "" : gameBlack[currentGame])  || "?") + "\"]\n" +
+      "[Result \"" + ((CurrentVar ? "" : gameResult[currentGame]) || "*") + "\"]\n";
+    }
+    if ((thisFEN != FenStringStart) || (!addGametext)) {
+      text += "[SetUp \"1\"]\n" + "[FEN \"" + thisFEN + "\"]\n";
     }
     if (gameVariant[currentGame] !== "") { text += "[Variant \"" + gameVariant[currentGame] + "\"]\n"; }
-    text += "\n" + currentMovesString + "\n
\n"; + if (addGametext) { text += "\n" + movesStr + "\n"; } + text += "
\n"; fenWin.document.open("text/html", "replace"); fenWin.document.write(text); fenWin.document.close(); @@ -836,7 +889,7 @@ function displayFenData() { var pgnHeader = new Array(); var pgnGame = new Array(); var numberOfGames = -1; -var currentGame = -1; +var currentGame = -1; var firstStart = true; @@ -853,7 +906,7 @@ var gameInitialWhiteClock = new Array(); var gameInitialBlackClock = new Array(); var gameVariant = new Array(); -var oldAnchorName = ""; +var highlightedMoveId = ""; var isAutoPlayOn = false; var AutoPlayInterval = null; @@ -903,24 +956,24 @@ var mvCaptured = -1; var mvCapturedId = -1; var mvIsNull = 0; -Board = new Array(8); -for (i=0; i<8; ++i) { Board[i] = new Array(8); } +var Board = new Array(8); +for (var i=0; i<8; ++i) { Board[i] = new Array(8); } // HistCol, HistRow: move history up to last replayed ply -// HistCol[0], HistRow[0]: "square from" (0..7, 0..7 from square a1) +// HistCol[0], HistRow[0]: "square from"; 0..7, 0..7 from A1 // HistCol[1], HistRow[1]: castling/capture -// HistCol[2], HistRow[2]: "square to" (0..7, 0..7 from square a1) +// HistCol[2], HistRow[2]: "square to"; 0..7, 0..7 from A1 -HistCol = new Array(3); -HistRow = new Array(3); -HistPieceId = new Array(2); -HistType = new Array(2); -HistVar = new Array(); +var HistCol = new Array(3); +var HistRow = new Array(3); +var HistPieceId = new Array(2); +var HistType = new Array(2); +var HistVar = new Array(); -PieceCol = new Array(2); -PieceRow = new Array(2); -PieceType = new Array(2); -PieceMoveCounter = new Array(2); +var PieceCol = new Array(2); +var PieceRow = new Array(2); +var PieceType = new Array(2); +var PieceMoveCounter = new Array(2); for (i=0; i<2; ++i) { PieceCol[i] = new Array(16); @@ -936,28 +989,24 @@ for (i=0; i<3; ++i) { HistRow[i] = new Array(); } -HistEnPassant = new Array(); +var HistEnPassant = new Array(); HistEnPassant[0] = false; -HistEnPassantCol = new Array(); +var HistEnPassantCol = new Array(); HistEnPassantCol[0] = -1; -HistNull = new Array(); +var HistNull = new Array(); HistNull[0] = 0; var FenPieceName = "KQRBNP"; -var PieceCode = new Array(); // IE needs array for [index] -for (i=0; i<6; i++) { PieceCode[i] = FenPieceName.charAt(i); } +var PieceCode = FenPieceName.split(""); // IE needs array for [index] var FenStringStart = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; var columnsLetters = "ABCDEFGH"; var InitialHalfMoveClock = 0; -startingSquareSize = -1; -startingImageSize = -1; +var PieceImg = new Array(new Array(6), new Array(6)); +var ClearImg; -PiecePicture = new Array(2); -for (i=0; i<2; ++i) { PiecePicture[i] = new Array(6); } - -var ImagePath = ''; +var ImagePath = 'images'; var ImagePathOld = null; var imageType = 'png'; var defaultImagesSize = 40; @@ -969,10 +1018,10 @@ var commentsOnSeparateLines = false; var pgnUrl = ''; -CastlingLong = new Array(2); -CastlingShort = new Array(2); -Moves = new Array(); -MoveComments = new Array(); +var CastlingLong = new Array(2); +var CastlingShort = new Array(2); +var Moves = new Array(); +var MoveComments = new Array(); var MoveColor; var MoveCount; @@ -985,10 +1034,9 @@ var IsRotated = false; var pgnHeaderTagRegExp = /\[\s*(\w+)\s*"([^"]*)"\s*\]/; var pgnHeaderTagRegExpGlobal = /\[\s*(\w+)\s*"([^"]*)"\s*\]/g; var pgnHeaderBlockRegExp = /\s*(\[\s*\w+\s*"[^"]*"\s*\]\s*)+/; -var dummyPgnHeader = '[x""]'; -var emptyPgnHeader = '[Event ""]\n[Site ""]\n[Date ""]\n[Round ""]\n[White ""]\n[Black ""]\n[Result ""]\n\n'; -var templatePgnHeader = '[Event "?"]\n[Site "?"]\n[Date "?"]\n[Round "?"]\n[White "?"]\n[Black "?"]\n[Result "?"]\n'; -var alertPgnHeader = '[Event ""]\n[Site ""]\n[Date ""]\n[Round ""]\n[White ""]\n[Black ""]\n[Result ""]\n\n{error: click on the top left chessboard square for debug info}'; + +var emptyPgnHeader = '[Event ""]\n[Site ""]\n[Date ""]\n[Round ""]\n[White ""]\n[Black ""]\n[Result ""]\n'; +var alertPgn = emptyPgnHeader + "\n{error: click on the top left chessboard square for debug info}"; var pgn4webVariationRegExp = /\[%pgn4web_variation (\d+)\]/; var pgn4webVariationRegExpGlobal = /\[%pgn4web_variation (\d+)\]/g; @@ -1013,7 +1061,7 @@ function CheckLegality(what, plyCount) { return true; } - // castling move? + // castling if (what == 'O-O') { if (!CheckLegalityOO()) { return false; } for (thisCol = PieceCol[MoveColor][0]; thisCol < 7; thisCol++) { @@ -1046,8 +1094,7 @@ function CheckLegality(what, plyCount) { } // piece move: which same type piece could move there? - var pieceId; - for (pieceId = 0; pieceId < 16; ++pieceId) { + for (var pieceId = 0; pieceId < 16; ++pieceId) { if (PieceType[MoveColor][pieceId] == mvPiece) { if (mvPiece == 1) { retVal = CheckLegalityKing(pieceId); } else if (mvPiece == 2) { retVal = CheckLegalityQueen(pieceId); } @@ -1127,8 +1174,8 @@ function RookForOOCastling(color) { if (CastlingShort[color] < 0) { return null; } if (PieceMoveCounter[color][0] > 0) { return null; } - legal = false; - for (thisRook = 0; thisRook < 16; thisRook++) { + var legal = false; + for (var thisRook = 0; thisRook < 16; thisRook++) { if ((PieceCol[color][thisRook] == CastlingShort[color]) && (PieceCol[color][thisRook] > PieceCol[color][0]) && (PieceRow[color][thisRook] == color*7) && @@ -1145,7 +1192,8 @@ function RookForOOCastling(color) { function CheckLegalityOO() { - if ((thisRook = RookForOOCastling(MoveColor)) === null) { return false; } + var thisRook = RookForOOCastling(MoveColor); + if (thisRook === null) { return false; } // check no piece between king and rook // clear king/rook squares for Chess960 @@ -1165,8 +1213,8 @@ function RookForOOOCastling(color) { if (CastlingLong[color] < 0) { return null; } if (PieceMoveCounter[color][0] > 0) { return null; } - legal = false; - for (thisRook = 0; thisRook < 16; thisRook++) { + var legal = false; + for (var thisRook = 0; thisRook < 16; thisRook++) { if ((PieceCol[color][thisRook] == CastlingLong[color]) && (PieceCol[color][thisRook] < PieceCol[color][0]) && (PieceRow[color][thisRook] == color*7) && @@ -1183,7 +1231,8 @@ function RookForOOOCastling(color) { function CheckLegalityOOO() { - if ((thisRook = RookForOOOCastling(MoveColor)) === null) { return false; } + var thisRook = RookForOOOCastling(MoveColor); + if (thisRook === null) { return false; } // check no piece between king and rook // clear king/rook squares for Chess960 @@ -1213,7 +1262,7 @@ function CheckClearWay(thisPiece) { } function CleanMove(move) { - move = move.replace(/[^a-zA-Z0-9#=-]*/g, ''); // patch here adding '+' after '0-8' to pass through check signs + move = move.replace(/[^a-wyzA-WYZ0-9#-]*/g, ''); // patch: remove/add '+' 'x' '=' chars for full chess informant style or pgn style for the game text if (move.match(/^[Oo0]/)) { move = move.replace(/[o0]/g, 'O').replace(/O(?=O)/g, 'O-'); } move = move.replace(/ep/i, ''); return move; @@ -1236,7 +1285,7 @@ function GoToMove(thisPly, thisVar) { if (diff > 0) { MoveForward(diff); } else { MoveBackward(-diff); } } else { - backStart = StartPly; + var backStart = StartPly; loopCommonPredecessor: for (var ii = PredecessorsVars[CurrentVar].length - 1; ii >= 0; ii--) { for (var jj = PredecessorsVars[thisVar].length - 1; jj >= 0; jj--) { @@ -1281,9 +1330,8 @@ function SetInitialHalfmove(number_or_string, always) { alwaysInitialHalfmove = (always === true); if (number_or_string === undefined) { initialHalfmove = 0; return; } initialHalfmove = number_or_string; - if ((typeof number_or_string == "string") && - (number_or_string.match(/^(start|end|random|comment)$/))) { return; } - if ((initialHalfmove = parseInt(initialHalfmove,10)) == NaN) { initialHalfmove = 0; } + if ((typeof number_or_string == "string") && (number_or_string.match(/^(start|end|random|comment)$/))) { return; } + if (isNaN(initialHalfmove = parseInt(initialHalfmove,10))) { initialHalfmove = 0; } } function SetInitialVariation(number) { @@ -1305,63 +1353,63 @@ function randomGameRandomPly() { } -// clock detection: DGT format [%clk 01:02] +// clock detection as [%clk 01:02] function clockFromComment(plyNum) { return customPgnCommentTag("clk", null, plyNum); } function clockFromHeader(whiteToMove) { - clockHeaderString = customPgnHeaderTag("Clock") + ""; - if (tagValues = clockHeaderString.match("^" + (whiteToMove ? "W" : "B") + "/(.*)$")) { - return tagValues[1]; - } else { return null; } + var clockString = customPgnHeaderTag("Clock") + ""; + var matches = clockString.match("^" + (whiteToMove ? "W" : "B") + "/(.*)$"); + if (matches) { return matches[1]; } + else { return null; } } function HighlightLastMove() { - var anchorName, text; + var theObj, moveId, text, ii, clockString, clockRegExp, clockMatch; undoStackStore(); - // remove highlighting from old anchor - if (oldAnchorName) { - if (theObj = document.getElementById(oldAnchorName)) { - theObj.className = ( oldAnchorName.match(/Var0Mv/) ? 'move' : 'variation') + ' notranslate'; + // remove old move highlighting + if (highlightedMoveId) { + if (theObj = document.getElementById(highlightedMoveId)) { + theObj.className = (highlightedMoveId.match(/Var0Mv/) ? 'move' : 'variation') + ' notranslate'; } } - // halfmove to be highlighted, negative for starting position (nothing to highlight) + // halfmove to be highlighted, negative for starting position var showThisMove = CurrentPly - 1; if (showThisMove > StartPlyVar[CurrentVar] + PlyNumberVar[CurrentVar]) { showThisMove = StartPlyVar[CurrentVar] + PlyNumberVar[CurrentVar]; } - if (theShowCommentTextObject = document.getElementById("GameLastComment")) { + if (theObj = document.getElementById("GameLastComment")) { if (commentsIntoMoveText) { variationTextDepth = CurrentVar === 0 ? 0 : 1; text = '' + strippedMoveComment(showThisMove+1, CurrentVar, true).replace(/\sID="[^"]*"/g, '') + ''; } else { text = ''; } - theShowCommentTextObject.innerHTML = text; + theObj.innerHTML = text; } // side to move - whiteToMove = ((showThisMove+1)%2 === 0); + var whiteToMove = ((showThisMove+1)%2 === 0); text = whiteToMove ? 'white' : 'black'; if (theObj = document.getElementById("GameSideToMove")) { theObj.innerHTML = text; } // clock - lastMoverClockObject = document.getElementById(whiteToMove ? + var lastMoverClockObj = document.getElementById(whiteToMove ? "GameBlackClock" : "GameWhiteClock"); - initialLastMoverClock = whiteToMove ? + var initialLastMoverClock = whiteToMove ? gameInitialBlackClock[currentGame] : gameInitialWhiteClock[currentGame]; - beforeLastMoverClockObject = document.getElementById(whiteToMove ? + var beforeLastMoverClockObj = document.getElementById(whiteToMove ? "GameWhiteClock" : "GameBlackClock"); - initialBeforeLastMoverClock = whiteToMove ? + var initialBeforeLastMoverClock = whiteToMove ? gameInitialWhiteClock[currentGame] : gameInitialBlackClock[currentGame]; - if (lastMoverClockObject) { + if (lastMoverClockObj) { clockString = ((showThisMove+1 === StartPly+PlyNumber) && ((!LiveBroadcastDemo) || (gameResult[currentGame] !== "*"))) ? clockFromHeader(!whiteToMove) : null; @@ -1376,9 +1424,9 @@ function HighlightLastMove() { } } } - lastMoverClockObject.innerHTML = clockString; + lastMoverClockObj.innerHTML = clockString; } - if (beforeLastMoverClockObject) { + if (beforeLastMoverClockObj) { clockString = ((showThisMove+1 === StartPly+PlyNumber) && ((!LiveBroadcastDemo) || (gameResult[currentGame] !== "*"))) ? clockFromHeader(whiteToMove) : null; @@ -1386,27 +1434,26 @@ function HighlightLastMove() { clockString = showThisMove > StartPly ? clockFromComment(showThisMove) : initialBeforeLastMoverClock; if (!clockString && (CurrentPly === StartPly+PlyNumber)) { - // support for time info in the last comment as { White Time: 0h:12min Black Time: 1h:23min } + // see comment above clockRegExp = new RegExp((whiteToMove ? "White" : "Black") + "\\s+Time:\\s*(\\S+)", "i"); if (clockMatch = strippedMoveComment(StartPly+PlyNumber).match(clockRegExp)) { clockString = clockMatch[1]; } } } - beforeLastMoverClockObject.innerHTML = clockString; + beforeLastMoverClockObj.innerHTML = clockString; } - if (lastMoverClockObject && beforeLastMoverClockObject) { - if (lastMoverClockObject.innerHTML && !beforeLastMoverClockObject.innerHTML) { - beforeLastMoverClockObject.innerHTML = "-"; - } else if (!lastMoverClockObject.innerHTML && beforeLastMoverClockObject.innerHTML) { - lastMoverClockObject.innerHTML = "-"; + if (lastMoverClockObj && beforeLastMoverClockObj) { + if (lastMoverClockObj.innerHTML && !beforeLastMoverClockObj.innerHTML) { + beforeLastMoverClockObj.innerHTML = "-"; + } else if (!lastMoverClockObj.innerHTML && beforeLastMoverClockObj.innerHTML) { + lastMoverClockObj.innerHTML = "-"; } } // next move - var theShowMoveTextObject; - if (theShowMoveTextObject = document.getElementById("GameNextMove")) { + if (theObj = document.getElementById("GameNextMove")) { if (CurrentVar === 0 && showThisMove + 1 >= StartPly + PlyNumber) { text = '' + gameResult[currentGame] + ''; } else if (typeof(Moves[showThisMove+1]) == "undefined") { @@ -1414,25 +1461,25 @@ function HighlightLastMove() { } else { text = printMoveText(showThisMove+1, CurrentVar, (CurrentVar !== 0), true, false); } - theShowMoveTextObject.innerHTML = text; + theObj.innerHTML = text; } // next variations - if (theShowMoveTextObject = document.getElementById("GameNextVariations")) { + if (theObj = document.getElementById("GameNextVariations")) { text = ''; if (commentsIntoMoveText) { - var childVars = childrenVars(showThisMove+1, CurrentVar); - for (ii = 0; ii < childVars.length; ii++) { - if (childVars[ii] !== CurrentVar) { - text += ' ' + printMoveText(showThisMove+1, childVars[ii], (childVars[ii] !== 0), true, false); + var children = childrenVars(showThisMove+1, CurrentVar); + for (ii = 0; ii < children.length; ii++) { + if (children[ii] !== CurrentVar) { + text += ' ' + printMoveText(showThisMove+1, children[ii], (children[ii] !== 0), true, false); } } } - theShowMoveTextObject.innerHTML = text; + theObj.innerHTML = text; } // last move - if (theShowMoveTextObject = document.getElementById("GameLastMove")) { + if (theObj = document.getElementById("GameLastMove")) { if ((showThisMove >= StartPly) && Moves[showThisMove]) { text = printMoveText(showThisMove, CurrentVar, (CurrentVar !== 0), true, false); } else if (showThisMove === StartPly - 1) { @@ -1440,41 +1487,42 @@ function HighlightLastMove() { (Math.floor((showThisMove+1)/2) + 1) + (((showThisMove+1) % 2) ? "..." : ".") + ''; } else { text = ''; } - theShowMoveTextObject.innerHTML = text; + theObj.innerHTML = text; } // last variations - if (theShowMoveTextObject = document.getElementById("GameLastVariations")) { + if (theObj = document.getElementById("GameLastVariations")) { text = ''; if (commentsIntoMoveText) { - var siblingVars = childrenVars(showThisMove, HistVar[showThisMove]); - for (ii = 0; ii < siblingVars.length; ii++) { - if (siblingVars[ii] !== CurrentVar) { - text += ' ' + printMoveText(showThisMove, siblingVars[ii], (siblingVars[ii] !== 0), true, false); + var siblings = childrenVars(showThisMove, HistVar[showThisMove]); + for (ii = 0; ii < siblings.length; ii++) { + if (siblings[ii] !== CurrentVar) { + text += ' ' + printMoveText(showThisMove, siblings[ii], (siblings[ii] !== 0), true, false); } } } - theShowMoveTextObject.innerHTML = text; + theObj.innerHTML = text; } if (showThisMove >= (StartPlyVar[CurrentVar]-1)) { - anchorName = 'Var' + CurrentVar + 'Mv' + (showThisMove + 1); - if (theObj = document.getElementById(anchorName)) { + moveId = 'Var' + CurrentVar + 'Mv' + (showThisMove + 1); + if (theObj = document.getElementById(moveId)) { theObj.className = (CurrentVar ? 'variation variationOn' : 'move moveOn') + ' notranslate'; } - oldAnchorName = anchorName; + highlightedMoveId = moveId; if (highlightOption) { + var colFrom, rowFrom, colTo, rowTo; if ((showThisMove < StartPly) || HistNull[showThisMove]) { - highlightColFrom = highlightRowFrom = -1; - highlightColTo = highlightRowTo = -1; + colFrom = rowFrom = -1; + colTo = rowTo = -1; } else { - highlightColFrom = HistCol[0][showThisMove] === undefined ? -1 : HistCol[0][showThisMove]; - highlightRowFrom = HistRow[0][showThisMove] === undefined ? -1 : HistRow[0][showThisMove]; - highlightColTo = HistCol[2][showThisMove] === undefined ? -1 : HistCol[2][showThisMove]; - highlightRowTo = HistRow[2][showThisMove] === undefined ? -1 : HistRow[2][showThisMove]; + colFrom = HistCol[0][showThisMove] === undefined ? -1 : HistCol[0][showThisMove]; + rowFrom = HistRow[0][showThisMove] === undefined ? -1 : HistRow[0][showThisMove]; + colTo = HistCol[2][showThisMove] === undefined ? -1 : HistCol[2][showThisMove]; + rowTo = HistRow[2][showThisMove] === undefined ? -1 : HistRow[2][showThisMove]; } - highlightMove(highlightColFrom, highlightRowFrom, highlightColTo, highlightRowTo); + highlightMove(colFrom, rowFrom, colTo, rowTo); } } } @@ -1489,29 +1537,30 @@ function SetHighlight(on) { else { highlightMove(-1, -1, -1, -1); } } -var lastColFromHighlighted = -1; -var lastRowFromHighlighted = -1; -var lastColToHighlighted = -1; -var lastRowToHighlighted = -1; +var colFromHighlighted = -1; +var rowFromHighlighted = -1; +var colToHighlighted = -1; +var rowToHighlighted = -1; function highlightMove(colFrom, rowFrom, colTo, rowTo) { - highlightSquare(lastColFromHighlighted, lastRowFromHighlighted, false); - highlightSquare(lastColToHighlighted, lastRowToHighlighted, false); + highlightSquare(colFromHighlighted, rowFromHighlighted, false); + highlightSquare(colToHighlighted, rowToHighlighted, false); if ( highlightSquare(colFrom, rowFrom, true) ) { - lastColFromHighlighted = colFrom; - lastRowFromHighlighted = rowFrom; - } else { lastColFromHighlighted = lastRowFromHighlighted = -1; } + colFromHighlighted = colFrom; + rowFromHighlighted = rowFrom; + } else { colFromHighlighted = rowFromHighlighted = -1; } if ( highlightSquare(colTo, rowTo, true) ) { - lastColToHighlighted = colTo; - lastRowToHighlighted = rowTo; - } else { lastColToHighlighted = lastRowToHighlighted = -1; } + colToHighlighted = colTo; + rowToHighlighted = rowTo; + } else { colToHighlighted = rowToHighlighted = -1; } } function highlightSquare(col, row, on) { if ((col === undefined) || (row === undefined)) { return false; } if (!SquareOnBoard(col, row)) { return false; } - if (IsRotated) { trow = row; tcol = 7 - col; } - else { trow = 7 - row; tcol = col; } - if (!(theObj = document.getElementById('tcol' + tcol + 'trow' + trow))) { return false; } + var trow = IsRotated ? row : 7 - row; + var tcol = IsRotated ? 7 - col : col; + var theObj = document.getElementById('tcol' + tcol + 'trow' + trow); + if (!theObj) { return false; } if (on) { theObj.className = (trow+tcol)%2 === 0 ? "highlightWhiteSquare" : "highlightBlackSquare"; } else { theObj.className = (trow+tcol)%2 === 0 ? "whiteSquare" : "blackSquare"; } return true; @@ -1570,19 +1619,18 @@ function undoStackRedo() { } -// align to chrome-extension/background.html function fixCommonPgnMistakes(text) { - text = text.replace(/[\u00A0\u180E\u2000-\u200A\u202F\u205F\u3000]/g," "); // some "space" to plain space + text = text.replace(/[\u00A0\u180E\u2000-\u200A\u202F\u205F\u3000]/g," "); // some spaces to plain space text = text.replace(/\u00BD/g,"1/2"); // "half fraction" to "1/2" text = text.replace(/[\u2010-\u2015]/g,"-"); // "hyphens" to "-" text = text.replace(/\u2024/g,"."); // "one dot leader" to "." text = text.replace(/[\u2025-\u2026]/g,"..."); // "two dot leader" and "ellipsis" to "..." - text = text.replace(/\\"/g,"'"); // fix parsing headers like: [Opening "King\"s Indian Attack"] + text = text.replace(/\\"/g,"'"); // fix [Opening "Queen\"s Gambit"] return text; } function fullPgnGame(gameNum) { - res = pgnHeader[gameNum] ? pgnHeader[gameNum].replace(/^[^[]*/g, "") : ""; + var res = pgnHeader[gameNum] ? pgnHeader[gameNum].replace(/^[^[]*/g, "") : ""; res = res.replace(/\[\s*(\w+)\s*"([^"]*)"\s*\][^[]*/g, '[$1 "$2"]\n'); res += "\n"; res += pgnGame[gameNum] ? pgnGame[gameNum].replace(/(^[\s]*|[\s]*$)/g, "") : ""; @@ -1593,11 +1641,7 @@ function pgnGameFromPgnText(pgnText) { var headMatch, prevHead, newHead, startNew, afterNew, lastOpen, checkedGame, validHead; - pgnText = fixCommonPgnMistakes(pgnText); - - // avoid html injection - pgnText = pgnText.replace(//g, ">"); + pgnText = simpleHtmlentities(fixCommonPgnMistakes(pgnText)); // PGN standard: ignore lines starting with % pgnText = pgnText.replace(/(^|\n)%.*(\n|$)/g, "\n"); @@ -1636,44 +1680,16 @@ function pgnGameFromPgnText(pgnText) { function pgnGameFromHttpRequest(httpResponseData) { - if (pgnUrl && pgnUrl.match(/\.zip(\?|#|$)/i)) { - var unzippedPgnText = ""; - try { - // requires js-unzip/js-unzip.js and js-unzip/js-inflate.js - var unzipper = new JSUnzip(httpResponseData); - if (unzipper.isZipFile()) { - unzipper.readEntries(); - for (u in unzipper.entries) { - if (unzipper.entries[u].fileName.match(/\.pgn$/i)) { - switch (unzipper.entries[u].compressionMethod) { - case 0: - unzippedPgnText += "\n" + unzipper.entries[u].data + "\n"; - break; - case 8: - unzippedPgnText += "\n" + JSInflate.inflate(unzipper.entries[u].data) + "\n"; - break; - default: - myAlert("warning: unsupported compression method " + unzipper.entries[u].compressionMethod + " for ZIP archive at URL\n" + pgnUrl, false); - break; - } - } - } - if (!unzippedPgnText) { myAlert("error: no PGN games found in ZIP archive at URL\n" + pgnUrl, true); } - } else { myAlert("error: invalid ZIP archive at URL\n" + pgnUrl, true); } - if (!unzippedPgnText) { unzippedPgnText = alertPgnHeader; } - } catch(e) { - myAlert("error: missing unzip library or unzip error for ZIP archive at URL\n" + pgnUrl, true); - unzippedPgnText = httpResponseData; // passing through the data for backward compatibility - } - } else { - unzippedPgnText = httpResponseData; - } + // process here any special file types, for instance zipfiles: + // if (pgnUrl && pgnUrl.replace(/[?#].*/, "").match(/\.zip$/i)) { return pgnGameFromPgnText(unzipPgnFiles(httpResponseData)); } + // remember to fix function loadPgnFromPgnUrl() for binary data - return pgnGameFromPgnText(unzippedPgnText); + return pgnGameFromPgnText(httpResponseData); } var http_request_last_processed_id = 0; function updatePgnFromHttpRequest(this_http_request, this_http_request_id) { + var res = LOAD_PGN_FAIL; if (this_http_request.readyState != 4) { return; } @@ -1684,68 +1700,62 @@ function updatePgnFromHttpRequest(this_http_request, this_http_request_id) { if (this_http_request.status == 304) { if (LiveBroadcastDelay > 0) { - loadPgnFromPgnUrlResult = LOAD_PGN_UNMODIFIED; + res = LOAD_PGN_UNMODIFIED; } else { myAlert('error: unmodified PGN URL when not in live mode'); - loadPgnFromPgnUrlResult = LOAD_PGN_FAIL; } -// patch Opera's failure reporting 304 status +// patch Opera's failure reporting 304 status (up to Opera v12) } else if (window.opera && (!this_http_request.responseText) && (this_http_request.status === 0)) { this_http_request.abort(); - loadPgnFromPgnUrlResult = LOAD_PGN_UNMODIFIED; + res = LOAD_PGN_UNMODIFIED; // end of patch } else if (!this_http_request.responseText) { myAlert('error: no data received from PGN URL\n' + pgnUrl, true); - loadPgnFromPgnUrlResult = LOAD_PGN_FAIL; } else if (!pgnGameFromHttpRequest(this_http_request.responseText)) { myAlert('error: no games found at PGN URL\n' + pgnUrl, true); - loadPgnFromPgnUrlResult = LOAD_PGN_FAIL; } else { if (LiveBroadcastDelay > 0) { - LiveBroadcastLastModifiedHeader = this_http_request.getResponseHeader("Last-Modified"); - if (LiveBroadcastLastModifiedHeader) { + LiveBroadcastLastReceivedLocal = (new Date()).toLocaleString(); + if (LiveBroadcastLastModifiedHeader = this_http_request.getResponseHeader("Last-Modified")) { LiveBroadcastLastModified = new Date(LiveBroadcastLastModifiedHeader); - LiveBroadcastLastReceivedLocal = (new Date()).toLocaleString(); - } - else { LiveBroadcastLastModified_Reset(); } + } else { LiveBroadcastLastModified_Reset(); } } - loadPgnFromPgnUrlResult = LOAD_PGN_OK; + res = LOAD_PGN_OK; } } else { myAlert('error: failed reading PGN URL\n' + pgnUrl, true); - loadPgnFromPgnUrlResult = LOAD_PGN_FAIL; } - if (LiveBroadcastDemo && (loadPgnFromPgnUrlResult == LOAD_PGN_UNMODIFIED)) { - loadPgnFromPgnUrlResult = LOAD_PGN_OK; + if (LiveBroadcastDemo && (res == LOAD_PGN_UNMODIFIED)) { + res = LOAD_PGN_OK; } - loadPgnCheckingLiveStatus(loadPgnFromPgnUrlResult); + loadPgnCheckingLiveStatus(res); } var LOAD_PGN_FAIL = 0; var LOAD_PGN_OK = 1; var LOAD_PGN_UNMODIFIED = 2; -function loadPgnCheckingLiveStatus(loadPgnResult) { +function loadPgnCheckingLiveStatus(res) { - switch (loadPgnResult) { + switch (res) { case LOAD_PGN_OK: if (LiveBroadcastDelay > 0) { firstStart = true; - oldParseLastMoveError = ParseLastMoveError; + var oldParseLastMoveError = ParseLastMoveError; if (!LiveBroadcastStarted) { LiveBroadcastStarted = true; } else { - oldGameWhite = gameWhite[currentGame]; - oldGameBlack = gameBlack[currentGame]; - oldGameEvent = gameEvent[currentGame]; - oldGameRound = gameRound[currentGame]; - oldGameSite = gameSite[currentGame]; - oldGameDate = gameDate[currentGame]; + var oldWhite = gameWhite[currentGame]; + var oldBlack = gameBlack[currentGame]; + var oldEvent = gameEvent[currentGame]; + var oldRound = gameRound[currentGame]; + var oldSite = gameSite[currentGame]; + var oldDate = gameDate[currentGame]; initialGame = currentGame + 1; @@ -1753,23 +1763,23 @@ function loadPgnCheckingLiveStatus(loadPgnResult) { LiveBroadcastOldCurrentPly = CurrentPly; LiveBroadcastOldCurrentPlyLast = (CurrentVar === 0 && CurrentPly === StartPlyVar[0] + PlyNumberVar[0]); - oldAutoplay = isAutoPlayOn; + var oldAutoplay = isAutoPlayOn; if (isAutoPlayOn) { SetAutoPlay(false); } LoadGameHeaders(); LiveBroadcastFoundOldGame = false; - for (ii=0; ii 0) && (pgnUrl.indexOf("?") == -1) && (pgnUrl.indexOf("#") == -1)) { - urlRandomizer = "?noCache=" + (0x1000000000 + Math.floor((Math.random() * 0xF000000000))).toString(16).toUpperCase(); - } else { urlRandomizer = ""; } - http_request.open("GET", pgnUrl + urlRandomizer); + randomizer = "?noCache=" + (0x1000000000 + Math.floor((Math.random() * 0xF000000000))).toString(16).toUpperCase(); + } + http_request.open("GET", pgnUrl + randomizer); // anti-caching #2 if (LiveBroadcastDelay > 0) { http_request.setRequestHeader( "If-Modified-Since", LiveBroadcastLastModifiedHeader ); @@ -1917,7 +1932,7 @@ function restartLiveBroadcast() { } function checkLiveBroadcastStatus() { - var liveBroadcastStatusTitle; + var theTitle, theObj, ii; var tick = " " + (LiveBroadcastTicker % 2 ? "<>" : "><") + " "; if (LiveBroadcastDelay === 0) { return; } @@ -1928,7 +1943,7 @@ function checkLiveBroadcastStatus() { LiveBroadcastEnded = false; LiveBroadcastGamesRunning = 0; LiveBroadcastStatusString = "0 " + tick + " 0"; - liveBroadcastStatusTitle = "live broadcast yet to start"; + theTitle = "live broadcast yet to start"; } else { // yes var lbgr = 0; @@ -1938,12 +1953,12 @@ function checkLiveBroadcastStatus() { LiveBroadcastEnded = (lbgr === 0); LiveBroadcastGamesRunning = lbgr; LiveBroadcastStatusString = lbgr + " " + tick + " " + numberOfGames; - liveBroadcastStatusTitle = LiveBroadcastEnded ? "live broadcast ended" : lbgr + " live game" + (lbgr > 1 ? "s" : "") + " out of " + numberOfGames; + theTitle = LiveBroadcastEnded ? "live broadcast ended" : lbgr + " live game" + (lbgr > 1 ? "s" : "") + " out of " + numberOfGames; } if (theObj = document.getElementById("GameLiveStatus")) { theObj.innerHTML = LiveBroadcastStatusString; - theObj.title = liveBroadcastStatusTitle; + theObj.title = theTitle; } if (theObj = document.getElementById("GameLiveLastRefreshed")) { theObj.innerHTML = LiveBroadcastLastRefreshedLocal; } @@ -1956,8 +1971,7 @@ function checkLiveBroadcastStatus() { function restartLiveBroadcastTimeout() { if (LiveBroadcastDelay === 0) { return; } if (LiveBroadcastInterval) { clearTimeout(LiveBroadcastInterval); LiveBroadcastInterval = null; } - needRestart = (!LiveBroadcastEnded); - if ((needRestart === true) && (!LiveBroadcastPaused)) { + if ((!LiveBroadcastEnded) && (!LiveBroadcastPaused)) { LiveBroadcastInterval = setTimeout("refreshPgnSource()", LiveBroadcastDelay * 60000); } LiveBroadcastTicker++; @@ -1971,13 +1985,10 @@ function refreshPgnSource() { if (LiveBroadcastDelay === 0) { return; } if (LiveBroadcastInterval) { clearTimeout(LiveBroadcastInterval); LiveBroadcastInterval = null; } if (LiveBroadcastDemo) { - addedPly = 0; - for (ii=0;ii used for pgnText - tmpText = document.getElementById(textareaId).innerHTML; + text = document.getElementById(textareaId).innerHTML; // fixes browser issue removing \n from innerHTML - if (tmpText.indexOf('\n') < 0) { tmpText = tmpText.replace(/((\[[^\[\]]*\]\s*)+)/g, "\n$1\n"); } - // fixes browser issue replacing quotes with " e.g. blackberry - if (tmpText.indexOf('"') < 0) { tmpText = tmpText.replace(/(")/g, '"'); } + if (text.indexOf('\n') < 0) { text = text.replace(/((\[[^\[\]]*\]\s*)+)/g, "\n$1\n"); } + // fixes browser issue replacing quotes with " + if (text.indexOf('"') < 0) { text = text.replace(/(")/g, '"'); } } // no header: add emptyPgnHeader - if (pgnHeaderTagRegExp.test(tmpText) === false) { tmpText = emptyPgnHeader + tmpText; } + if (pgnHeaderTagRegExp.test(text) === false) { text = emptyPgnHeader + "\n" + text; } - if ( pgnGameFromPgnText(tmpText) ) { - loadPgnFromTextareaResult = LOAD_PGN_OK; + if ( pgnGameFromPgnText(text) ) { + res = LOAD_PGN_OK; LiveBroadcastLastReceivedLocal = (new Date()).toLocaleString(); } else { - myAlert('error: no games found in ' + textareaId + 'object in the HTML file'); - loadPgnFromTextareaResult = LOAD_PGN_FAIL; + myAlert('error: no games found in ' + textareaId + ' object in the HTML file'); } } - loadPgnCheckingLiveStatus(loadPgnFromTextareaResult); + loadPgnCheckingLiveStatus(res); } function createBoard() { - if (theObj = document.getElementById("GameBoard")) { + var theObj = document.getElementById("GameBoard"); + if (theObj) { theObj.innerHTML = '
' + '...loading PGN data
please wait...
'; @@ -2045,7 +2056,7 @@ function createBoard() { } else if ( document.getElementById("pgnText") ) { loadPgnFromTextarea("pgnText"); } else { - pgnGameFromPgnText(alertPgnHeader); + pgnGameFromPgnText(alertPgn); undoStackReset(); Init(); customFunctionOnPgnTextLoad(); @@ -2142,6 +2153,7 @@ function Init(nextGame) { autoScrollToCurrentMoveIfEnabled(); // customFunctionOnMove here for consistency: null move starting new game customFunctionOnMove(); + if (typeof(engineWinOnMove) == "function") { engineWinOnMove(); } } if ((firstStart) && (autostartAutoplay)) { SetAutoPlay(true); } @@ -2157,21 +2169,20 @@ function myAlertFEN(FenString, text) { } function InitFEN(startingFEN) { - if (typeof(startingFEN) != "string") { FenString = FenStringStart; } - else { FenString = startingFEN.replace(/\\/g, "/").replace(/[^a-zA-Z0-9\s\/-]/g, " ").replace(/(^\s*|\s*$)/g, "").replace(/\s+/g, " "); } + var ii, jj, cc, color, castlingRookCol, fullMoveNumber; + + var FenString = typeof(startingFEN) != "string" ? FenStringStart : + startingFEN.replace(/\\/g, "/").replace(/[^a-zA-Z0-9\s\/-]/g, " ").replace(/(^\s*|\s*$)/g, "").replace(/\s+/g, " "); - var ii, jj; for (ii = 0; ii < 8; ++ii) { for (jj = 0; jj < 8; ++jj) { Board[ii][jj] = 0; } } - var color; StartPly = 0; MoveCount = StartPly; MoveColor = StartPly % 2; - StartMove = 0; var newEnPassant = false; var newEnPassantCol; @@ -2184,7 +2195,7 @@ function InitFEN(startingFEN) { if (FenString == FenStringStart) { for (color = 0; color < 2; color++) { - // K Q N B R p + // K Q N B R p PieceType[color] = [1, 2, 5, 5, 4, 4, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6]; PieceCol[color] = [4, 3, 1, 6, 2, 5, 0, 7, 0, 1, 2, 3, 4, 5, 6, 7]; PieceMoveCounter[color] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; @@ -2197,7 +2208,7 @@ function InitFEN(startingFEN) { } } } else { - var cc, kk, ll, nn, mm; + var kk, ll, nn, mm; for (ii = 0; ii < 2; ii++) { for (jj = 0; jj < 16; jj++) { PieceType[ii][jj] = -1; @@ -2297,7 +2308,6 @@ function InitFEN(startingFEN) { cc = FenString.charAt(ll++); if ((cc == "w") || (cc == "b")) { if (cc == "b") { - StartMove = 1; StartPly += 1; MoveColor = 1; } @@ -2413,22 +2423,22 @@ function InitFEN(startingFEN) { ll++; } - InitialFullMoveNumber = 0; + fullMoveNumber = 0; cc = FenString.charAt(ll++); while (cc != " ") { if (isNaN(cc)) { myAlertFEN(FenString, "invalid fullmove number"); - InitialFullMoveNumber = 1; + fullMoveNumber = 1; break; } - InitialFullMoveNumber=InitialFullMoveNumber*10+parseInt(cc,10); + fullMoveNumber = fullMoveNumber*10+parseInt(cc,10); cc = ll goToPly; --thisPly) { CurrentPly--; MoveColor = 1-MoveColor; - CurrentVar = HistVar[thisPly]; - - if (HistNull[thisPly]) { continue; } - - // moved piece back to original square - var chgPiece = HistPieceId[0][thisPly]; - Board[PieceCol[MoveColor][chgPiece]][PieceRow[MoveColor][chgPiece]] = 0; - - Board[HistCol[0][thisPly]][HistRow[0][thisPly]] = HistType[0][thisPly] * (1-2*MoveColor); - PieceType[MoveColor][chgPiece] = HistType[0][thisPly]; - PieceCol[MoveColor][chgPiece] = HistCol[0][thisPly]; - PieceRow[MoveColor][chgPiece] = HistRow[0][thisPly]; - PieceMoveCounter[MoveColor][chgPiece]--; - - // castling: rook back to original square - chgPiece = HistPieceId[1][thisPly]; - if ((chgPiece >= 0) && (chgPiece < 16)) { - Board[PieceCol[MoveColor][chgPiece]][PieceRow[MoveColor][chgPiece]] = 0; - Board[HistCol[1][thisPly]][HistRow[1][thisPly]] = HistType[1][thisPly] * (1-2*MoveColor); - PieceType[MoveColor][chgPiece] = HistType[1][thisPly]; - PieceCol[MoveColor][chgPiece] = HistCol[1][thisPly]; - PieceRow[MoveColor][chgPiece] = HistRow[1][thisPly]; - PieceMoveCounter[MoveColor][chgPiece]--; - } - - // capture: captured piece back to original square - chgPiece -= 16; - if ((chgPiece >= 0) && (chgPiece < 16)) { - Board[PieceCol[1-MoveColor][chgPiece]][PieceRow[1-MoveColor][chgPiece]] = 0; - Board[HistCol[1][thisPly]][HistRow[1][thisPly]] = HistType[1][thisPly] * (2*MoveColor-1); - PieceType[1-MoveColor][chgPiece] = HistType[1][thisPly]; - PieceCol[1-MoveColor][chgPiece] = HistCol[1][thisPly]; - PieceRow[1-MoveColor][chgPiece] = HistRow[1][thisPly]; - PieceMoveCounter[1-MoveColor][chgPiece]--; - } + UndoMove(thisPly); } if (scanOnly) { return; } @@ -2664,16 +2640,17 @@ function MoveBackward(diff, scanOnly) { } customFunctionOnMove(); + if (typeof(engineWinOnMove) == "function") { engineWinOnMove(); } } function MoveForward(diff, targetVar, scanOnly) { - + var nextVar, nextVarStartPly, move, text; var oldVar = -1; if (typeof(targetVar) == "undefined") { targetVar = CurrentVar; } // CurrentPly counts from 1, starting position 0 - goToPly = CurrentPly + parseInt(diff,10); + var goToPly = CurrentPly + parseInt(diff,10); if (goToPly > StartPlyVar[targetVar] + PlyNumberVar[targetVar]) { goToPly = StartPlyVar[targetVar] + PlyNumberVar[targetVar]; @@ -2687,7 +2664,7 @@ function MoveForward(diff, targetVar, scanOnly) { if (PredecessorsVars[targetVar][ii] === CurrentVar) { break; } } if (ii === PredecessorsVars[targetVar].length) { - myAlert("error: unknown path to reach variation " + targetVar + " from " + CurrentVar + " in game " + (currentGame+1), true); + myAlert("error: unknown path to variation " + targetVar + " from " + CurrentVar + " in game " + (currentGame+1), true); return; } else { nextVarStartPly = StartPlyVar[PredecessorsVars[targetVar][ii + 1]]; @@ -2742,10 +2719,12 @@ function MoveForward(diff, targetVar, scanOnly) { } customFunctionOnMove(); + if (typeof(engineWinOnMove) == "function") { engineWinOnMove(); } } -lastSynchCurrentVar = -1; +var lastSynchCurrentVar = -1; function synchMoves() { + var start, end; if (CurrentVar === lastSynchCurrentVar) { return; } Moves = new Array(); MoveComments = new Array(); @@ -2758,18 +2737,10 @@ function synchMoves() { } for (var jj = start; jj < end; jj++) { Moves[jj] = MovesVar[PredecessorsVars[CurrentVar][ii]][jj]; - if (theComment = MoveCommentsVar[PredecessorsVars[CurrentVar][ii]][jj]) { - MoveComments[jj] = theComment; - } else { - MoveComments[jj] = ""; - } + MoveComments[jj] = MoveCommentsVar[PredecessorsVars[CurrentVar][ii]][jj] || ""; } } - if (theComment = MoveCommentsVar[PredecessorsVars[CurrentVar][ii-1]][jj]) { - MoveComments[jj] = theComment; - } else { - MoveComments[jj] = ""; - } + MoveComments[jj] = MoveCommentsVar[PredecessorsVars[CurrentVar][ii-1]][jj] || ""; PlyNumber = StartPlyVar[CurrentVar] + PlyNumberVar[CurrentVar] - StartPly; lastSynchCurrentVar = CurrentVar; } @@ -2789,13 +2760,13 @@ function AutoplayNextGame() { } function MoveToNextComment(varOnly) { - for (ii=CurrentPly+1; ii<=StartPlyVar[CurrentVar] + PlyNumberVar[CurrentVar]; ii++) { + for (var ii=CurrentPly+1; ii<=StartPlyVar[CurrentVar] + PlyNumberVar[CurrentVar]; ii++) { if (MoveComments[ii].match(pgn4webVariationRegExp) || (!varOnly && strippedMoveComment(ii))) { GoToMove(ii); break; } } } function MoveToPrevComment(varOnly) { - for (ii=(CurrentPly-1); ii>=StartPly; ii--) { + for (var ii=(CurrentPly-1); ii>=StartPly; ii--) { if ((ii > 0 || CurrentVar > 0) && ii === StartPlyVar[HistVar[ii+1]]) { GoToMove(ii+1, HistVar[ii]); break; } if (MoveComments[ii].match(pgn4webVariationRegExp) || (!varOnly && strippedMoveComment(ii))) { GoToMove(ii); break; } } @@ -2820,6 +2791,7 @@ var numberOfVars; var MovesVar; var MoveCommentsVar; var GameHasComments; +var GameHasVariations; var StartPlyVar; var PlyNumberVar; var CurrentVarStack; @@ -2893,7 +2865,7 @@ function closeVar() { function childrenVars(thisPly, thisVar) { if (typeof(thisVar) == "undefined") { thisVar = CurrentVar; } if (typeof(thisPly) == "undefined") { thisPly = CurrentPly; } - children = new Array(); + var children = new Array(); for (var ii = thisVar; ii < numberOfVars; ii++) { if ((ii === thisVar && StartPlyVar[ii] + PlyNumberVar[ii] > thisPly) || (realParentVar(ii) === thisVar && StartPlyVar[ii] === thisPly && PlyNumberVar[ii] > 0)) { children.push(ii); @@ -2913,29 +2885,30 @@ function realParentVar(childVar) { function goToNextVariationSibling() { if (CurrentPly === StartPly) { return false; } - siblingVarList = childrenVars(CurrentPly - 1, HistVar[CurrentPly - 1]); - if (siblingVarList.length < 2) { return false; } - for (var ii = 0; ii < siblingVarList.length; ii++) { - if (siblingVarList[ii] === CurrentVar) { break; } + var siblings = childrenVars(CurrentPly - 1, HistVar[CurrentPly - 1]); + if (siblings.length < 2) { return false; } + for (var ii = 0; ii < siblings.length; ii++) { + if (siblings[ii] === CurrentVar) { break; } } - if (siblingVarList[ii] !== CurrentVar) { return false; } - GoToMove(CurrentPly, siblingVarList[(ii + 1) % siblingVarList.length]); + if (siblings[ii] !== CurrentVar) { return false; } + GoToMove(CurrentPly, siblings[(ii + 1) % siblings.length]); return true; } function goToFirstChild() { - childrenVarList = childrenVars(CurrentPly, CurrentVar); - if (childrenVarList.length < 1) { return false; } - if (childrenVarList[0] === CurrentVar) { - if (childrenVarList.length < 2) { return false; } - GoToMove(CurrentPly + 1, childrenVarList[1]); + var children = childrenVars(CurrentPly, CurrentVar); + if (children.length < 1) { return false; } + if (children[0] === CurrentVar) { + if (children.length < 2) { return false; } + GoToMove(CurrentPly + 1, children[1]); } else { - GoToMove(CurrentPly + 1, childrenVarList[0]); + GoToMove(CurrentPly + 1, children[0]); } return true; } function ParsePGNGameString(gameString) { + var ii, start, end, move, moveCount, needle, commentStart, commentEnd, isContinuation; var ssRep, ss = gameString, ssComm; ss = ss.replace(pgn4webVariationRegExpGlobal, "[%_pgn4web_variation_ $1]"); @@ -2965,7 +2938,7 @@ function ParsePGNGameString(gameString) { commentEnd = commentStart + 1; while ('0123456789'.indexOf(ss.charAt(commentEnd)) >= 0) { commentEnd++; - if (commentEnd == ss.length) { break; } + if (commentEnd >= ss.length) { break; } } if (MoveCommentsVar[CurrentVar][StartPly+PlyNumber]) { MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += ' '; } MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += translateNAGs(ss.substring(commentStart, commentEnd).replace(/(^\s*|\s*$)/, '')); @@ -2978,7 +2951,7 @@ function ParsePGNGameString(gameString) { commentEnd = commentStart + 1; while ('!?'.indexOf(ss.charAt(commentEnd)) >= 0) { commentEnd++; - if (commentEnd == ss.length) { break; } + if (commentEnd >= ss.length) { break; } } if (MoveCommentsVar[CurrentVar][StartPly+PlyNumber]) { MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += ' '; } MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += ss.substring(commentStart, commentEnd); @@ -2988,16 +2961,15 @@ function ParsePGNGameString(gameString) { case '{': commentStart = start+1; commentEnd = ss.indexOf('}',start+1); - if (commentEnd > 0) { - if (MoveCommentsVar[CurrentVar][StartPly+PlyNumber]) { MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += ' '; } - ssComm = translateNAGs(ss.substring(commentStart, commentEnd).replace(/(^\s*|\s*$)/, '')); - MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += ssComm; - GameHasComments = GameHasComments || ssComm.replace(/\[%[^\]]*\]\s*/g,'').replace(basicNAGs, '').replace(/^\s+$/,'') !== ''; - start = commentEnd; - } else { - myAlert('error: missing end comment char } while parsing game ' + (currentGame+1), true); - return; + if (commentEnd < 0) { + myAlert('error: missing end comment } in game ' + (currentGame+1), true); + commentEnd = ss.length; } + if (MoveCommentsVar[CurrentVar][StartPly+PlyNumber]) { MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += ' '; } + ssComm = translateNAGs(ss.substring(commentStart, commentEnd).replace(/(^\s*|\s*$)/, '')); + MoveCommentsVar[CurrentVar][StartPly+PlyNumber] += ssComm; + GameHasComments = GameHasComments || ssComm.replace(/\[%[^\]]*\]\s*/g,'').replace(basicNAGs, '').replace(/^\s+$/,'') !== ''; + start = commentEnd; break; case '%': @@ -3040,14 +3012,14 @@ function ParsePGNGameString(gameString) { default: - searchThis = new Array('1-0', '0-1', '1/2-1/2', '*'); - for (ii=0; ii 0) { closeVar(); } } @@ -3173,12 +3143,13 @@ NAG[134] = 'White has decisive counterplay'; // NAG[135] = '<=>'; NAG[136] = 'White has moderate time control pressure'; // NAG[137] = '(+)'; NAG[138] = 'White has severe time control pressure'; // NAG[139] = '(+)'; -for (ii = 14; ii < 139; ii += 2) { NAG[ii+1] = NAG[ii].replace("White", "Black"); } +for (i=14; i<139; i+=2) { NAG[i+1] = NAG[i].replace("White", "Black"); } function translateNAGs(comment) { - if (matches = comment.match(/\$+[0-9]+/g)) { + var matches = comment.match(/\$+[0-9]+/g); + if (matches) { for (var ii = 0; ii < matches.length; ii++) { - nag = matches[ii].substr(1); + var nag = matches[ii].substr(1); if (NAG[nag] !== undefined) { comment = comment.replace(new RegExp("\\$+" + nag + "(?!\\d)"), NAG[nag]); } @@ -3209,6 +3180,9 @@ function ParseMove(move, plyCount) { if (typeof(move) == "undefined") { return false; } + HistEnPassant[plyCount+1] = false; + HistEnPassantCol[plyCount+1] = -1; + if (move.indexOf('--') === 0) { mvIsNull = 1; CheckLegality('--', plyCount); @@ -3259,7 +3233,7 @@ function ParseMove(move, plyCount) { mvPiece = -1; // make sure mvPiece is properly assigned later if (ll === 0) { mvPiece = 6; } else { - for (ii = 1; ii < 6; ++ii) { if (rem.charAt(0) == PieceCode[ii-1]) { mvPiece = ii; } } + for (ii = 5; ii > 0; ii--) { if (rem.charAt(0) == PieceCode[ii-1]) { mvPiece = ii; break; } } if (mvPiece == -1) { if (columnsLetters.toLowerCase().indexOf(rem.charAt(0)) >= 0) { mvPiece = 6; } } if (mvPiece == -1) { return false; } if (rem.charAt(ll-1) == 'x') { mvCapture = 1; } @@ -3281,14 +3255,12 @@ function ParseMove(move, plyCount) { mvPieceOnTo = mvPiece; // "square to" occupied: capture (note en-passant case) - if (Board[mvToCol][mvToRow] !== 0) { mvCapture = 1; } - else { - if ((mvPiece == 6) && (HistEnPassant[plyCount]) && - (mvToCol == HistEnPassantCol[plyCount]) && - (mvToRow == 5-3*MoveColor)) { - mvCapture = 1; - } - } + if ((Board[mvToCol][mvToRow] !== 0) || + ((mvPiece == 6) && + (HistEnPassant[plyCount]) && + (mvToCol == HistEnPassantCol[plyCount]) && + (mvToRow == 5-3*MoveColor))) + { mvCapture = 1; } if (mvPiece == 6) { // move contains '=' or char after destination row: might be a promotion @@ -3332,8 +3304,6 @@ function ParseMove(move, plyCount) { if (!CheckLegality(PieceCode[mvPiece-1], plyCount)) { return false; } // pawn moved: check en-passant possibility - HistEnPassant[plyCount+1] = false; - HistEnPassantCol[plyCount+1] = -1; if (mvPiece == 6) { if (Math.abs(HistRow[0][plyCount]-mvToRow) == 2) { HistEnPassant[plyCount+1] = true; @@ -3344,30 +3314,33 @@ function ParseMove(move, plyCount) { } function SetGameSelectorOptions(head, num, chEvent, chSite, chRound, chWhite, chBlack, chResult, chDate) { - if (head !== null) { gameSelectorHead = head; } - if (num !== null) { gameSelectorNum = num; } - if (chEvent !== null) { gameSelectorChEvent = chEvent > 32 ? 32 : chEvent; } - if (chSite !== null) { gameSelectorChSite = chSite > 32 ? 32 : chSite; } - if (chRound !== null) { gameSelectorChRound = chRound > 32 ? 32 : chRound; } - if (chWhite !== null) { gameSelectorChWhite = chWhite > 32 ? 32 : chWhite; } - if (chBlack !== null) { gameSelectorChBlack = chBlack > 32 ? 32 : chBlack; } - if (chResult !== null) { gameSelectorChResult = chResult > 32 ? 32 : chResult; } - if (chDate !== null) { gameSelectorChDate = chDate > 32 ? 32 : chDate; } + if (typeof(head) == "string") { gameSelectorHead = head; } + gameSelectorNum = (num === true); + gameSelectorChEvent = Math.max(Math.min(chEvent , 32) || 0, 0) || 0; + gameSelectorChSite = Math.max(Math.min(chSite , 32) || 0, 0) || 0; + gameSelectorChRound = Math.max(Math.min(chRound , 32) || 0, 0) || 0; + gameSelectorChWhite = Math.max(Math.min(chWhite , 32) || 0, 0) || 0; + gameSelectorChBlack = Math.max(Math.min(chBlack , 32) || 0, 0) || 0; + gameSelectorChResult = Math.max(Math.min(chResult, 32) || 0, 0) || 0; + gameSelectorChDate = Math.max(Math.min(chDate , 32) || 0, 0) || 0; } var clickedSquareInterval = null; function clickedSquare(ii, jj) { if (clickedSquareInterval) { return; } // dont trigger twice - squareId = 'tcol' + jj + 'trow' + ii; - if (theObj = document.getElementById(squareId)) { + var squareId = 'tcol' + jj + 'trow' + ii; + var theObj = document.getElementById(squareId); + if (theObj) { var oldClass = theObj.className; theObj.className = (ii+jj)%2 === 0 ? "blackSquare" : "whiteSquare"; clickedSquareInterval = setTimeout("reset_after_click(" + ii + "," + jj + ",'" + oldClass + "','" + theObj.className + "')", 66); + clearSelectedText(); } } function reset_after_click (ii, jj, oldClass, newClass) { - if (theObj = document.getElementById('tcol' + jj + 'trow' + ii)) { + var theObj = document.getElementById('tcol' + jj + 'trow' + ii); + if (theObj) { // square class changed again by pgn4web already: dont touch it anymore e.g. autoplay if (theObj.className == newClass) { theObj.className = oldClass; } clickedSquareInterval = null; @@ -3377,38 +3350,37 @@ function reset_after_click (ii, jj, oldClass, newClass) { var lastSearchPgnExpression = ""; function gameNumberSearchPgn(searchExpression, backward, includeCurrent) { - var searchThis; lastSearchPgnExpression = searchExpression; if (searchExpression === "") { return false; } // replace newline with spaces so that we can use regexp "." on whole game - newlinesRegExp = new RegExp("[\n\r]", "gm"); - searchExpressionRegExp = new RegExp(searchExpression, "im"); + var newlinesRegExp = new RegExp("[\n\r]", "gm"); + var searchExpressionRegExp = new RegExp(searchExpression, "im"); // at start currentGame might still be -1 - currentGameSearch = (currentGame < 0) || (currentGame >= numberOfGames) ? 0 : currentGame; - searchThis = fullPgnGame(currentGameSearch); - if (includeCurrent && searchThis.replace(newlinesRegExp, " ").match(searchExpressionRegExp)) { - return currentGameSearch; + var thisCurrentGame = (currentGame < 0) || (currentGame >= numberOfGames) ? 0 : currentGame; + var needle = fullPgnGame(thisCurrentGame); + if (includeCurrent && needle.replace(newlinesRegExp, " ").match(searchExpressionRegExp)) { + return thisCurrentGame; } - delta = backward ? -1 : +1; - for (checkGame = (currentGameSearch + delta + numberOfGames) % numberOfGames; - checkGame != currentGameSearch; - checkGame = (checkGame + delta + numberOfGames) % numberOfGames) { - searchThis = fullPgnGame(checkGame); - if (searchThis.replace(newlinesRegExp, " ").match(searchExpressionRegExp)) { - return checkGame; + var delta = backward ? -1 : +1; + for (var thisGame = (thisCurrentGame + delta + numberOfGames) % numberOfGames; + thisGame != thisCurrentGame; + thisGame = (thisGame + delta + numberOfGames) % numberOfGames) { + needle = fullPgnGame(thisGame); + if (needle.replace(newlinesRegExp, " ").match(searchExpressionRegExp)) { + return thisGame; } } return false; } function searchPgnGame(searchExpression, backward) { + if (typeof(searchExpression) == "undefined") { searchExpression = ""; } lastSearchPgnExpression = searchExpression; - if (theObj = document.getElementById('searchPgnExpression')) - { theObj.value = searchExpression; } - if ((searchExpression === "") || (!searchExpression)) { return; } - if (numberOfGames < 2) { return; } - checkGame = gameNumberSearchPgn(searchExpression, backward, false); - if ((checkGame !== false) && (checkGame != currentGame)) { Init(checkGame); } + var theObj = document.getElementById('searchPgnExpression'); + if (theObj) { theObj.value = searchExpression; } + if ((searchExpression === "") || (numberOfGames < 2)) { return; } + var thisGame = gameNumberSearchPgn(searchExpression, backward, false); + if ((thisGame !== false) && (thisGame != currentGame)) { Init(thisGame); } } function searchPgnGamePrompt() { @@ -3416,25 +3388,24 @@ function searchPgnGamePrompt() { alert("info: search prompt disabled with less than 2 games"); return; } - searchExpression = prompt("Please enter search pattern for PGN games:", lastSearchPgnExpression); + var searchExpression = prompt("Please enter search pattern for PGN games:", lastSearchPgnExpression); if (searchExpression) { searchPgnGame(searchExpression); } } function searchPgnGameForm() { - if (theObj = document.getElementById('searchPgnExpression')) - { searchPgnGame(document.getElementById('searchPgnExpression').value); } + var theObj = document.getElementById('searchPgnExpression'); + if (theObj) { searchPgnGame(document.getElementById('searchPgnExpression').value); } } +var chessMovesRegExp = new RegExp("\\b((\\d+(\\.{1,3}|\\s)\\s*)?((([KQRBN][a-h1-8]?)|[a-h])?x?[a-h][1-8](=[QRNB])?|O-O-O|O-O)\\b[!?+#]*)", "g"); function fixCommentForDisplay(comment) { - chessMovesRegExp = new RegExp("((\\d+(\\.|\\.\\.\\.)?\\s*)?([KQRBNP]?[a-h1-8]?x?[a-h][1-8](=[QRNB])?|O-O-O|O-O)[!?+#]?)", "g"); - return comment.replace(chessMovesRegExp, '$1'); + return comment.replace(chessMovesRegExp, '$1'); } var tableSize = 0; +var textSelectOptions = ''; function PrintHTML() { - var ii, jj; - var text; - var theObj; + var ii, jj, text, theObj, squareId, imageId, squareCoord, squareTitle, numText, textSO; // chessboard @@ -3454,7 +3425,7 @@ function PrintHTML() { squareTitle = squareCoord; if (boardTitle[jj][ii] !== '') { squareTitle += ': ' + boardTitle[jj][ii]; } text += '' + ''; @@ -3476,9 +3447,9 @@ function PrintHTML() { // control buttons if (theObj = document.getElementById("GameButtons")) { - numberOfButtons = 5; - spaceSize = 3; - buttonSize = (tableSize - spaceSize*(numberOfButtons - 1)) / numberOfButtons; + var numButtons = 5; + var spaceSize = 3; + var buttonSize = (tableSize - spaceSize*(numButtons - 1)) / numButtons; text = '
' + '' + '
' + @@ -3542,13 +3513,9 @@ function PrintHTML() { '> ' + '