1<!DOCTYPE HTML>
2<html>
3
4<!--
5  pgn4web javascript chessboard
6  copyright (C) 2009-2015 Paolo Casaschi
7  see README file and http://pgn4web.casaschi.net
8  for credits, license and more details
9-->
10
11<head>
12
13<title>pgn4web live broadcast</title>
14
15<link rel="icon" sizes="16x16" href="pawn.ico" />
16
17<script src="pgn4web.js" type="text/javascript"></script>
18
19<script type="text/javascript">
20  "use strict";
21
22  var readyToSendPgn = false;
23
24  var pgnData_default = "live/live.pgn";
25  var maxBoards_default = 8;
26  var displayGame_default = 1;
27  var refreshMinutes_default = 1;
28  var boardTool_default = "tile";
29  var flipBoards_default = "none";
30
31  var thisRegExp = /(&|\?)(help|h)=(true|t)(&|$)/i;
32  if (window.location.search.match(thisRegExp) !== null) {
33    alert("pgn4web live-mosaic.html parameters" + "\n\n" +
34      " - pgnData = file.pgn" + "\n\n" +
35      " - maxBoards = max number of boards to display in a page (default " + maxBoards_default + ")" + "\n\n" +
36      " - displayGame = number of game for display, negative counts backwards (default " + displayGame_default + ")" + "\n\n" +
37      " - refreshMinutes = live broadcast delay (default " + refreshMinutes_default + ")" + "\n\n" +
38      " - refreshDemo = if set true sets live demo mode (default false)" + "\n\n" +
39      // " - demoPly = comma separated list of starting plies for each of the live demo games (default blank)" + "\n\n" +
40      " - boardTool = tile|stone (default " + boardTool_default + ")" + "\n\n" +
41      " - flipBoards = none|even|odd|all (default " + flipBoards_default + ")" + "\n\n" +
42      " - hideFinishedGamesClocks = if set treu hides clocks for finished games (default false)" + "\n\n" +
43      " - headlessPage = if set true displays a page without heading (default false)" + "\n\n" +
44      // " - barePadding = if not null, displays a page with given padding and without header/footer (default null)" + "\n\n" +
45      // " - backgroundColorHex = if not null and barePadding also not null, background color hex code, like FF0000 (default null)" + "\n\n" +
46      " - help = true");
47  }
48
49  var pgnData = pgnData_default;
50  thisRegExp = /(&|\?)(pgnData|pd)=([^&]*)(&|$)/i;
51  if (window.location.search.match(thisRegExp) !== null) {
52    pgnData = unescape(window.location.search.match(thisRegExp)[3]);
53  } else {
54    // accepts pgnData as alias for pgnFile for consistency with board.html
55    thisRegExp = /(&|\?)(pgnFile|pf)=([^&]*)(&|$)/i;
56    if (window.location.search.match(thisRegExp) !== null) {
57      pgnData = unescape(window.location.search.match(thisRegExp)[3]);
58    }
59  }
60
61  SetPgnUrl(pgnData); // if set, this has precedence over the inline PGN in the HTML file
62
63  var maxBoards = getMaxBoardFromLocalStorage();
64  thisRegExp = /(&|\?)(maxBoards|mb)=([\d]*)(&|$)/i;
65  if (window.location.search.match(thisRegExp) !== null) {
66    maxBoards = unescape(window.location.search.match(thisRegExp)[3]);
67  }
68  maxBoards = parseInt(maxBoards, 10);
69  if (isNaN(maxBoards) || (maxBoards < 1)) { maxBoards = maxBoards_default; }
70
71  var displayGame = displayGame_default;
72  thisRegExp = /(&|\?)(displayGame|dg)=([+-]?[\d]+)(&|$)/i;
73  if (window.location.search.match(thisRegExp) !== null) {
74    displayGame = unescape(window.location.search.match(thisRegExp)[3]);
75  }
76  displayGame = parseInt(displayGame, 10);
77  if (displayGame === 0) { displayGame = 1; }
78
79  var alertFlag = false;
80  var demoFlag = false;
81  thisRegExp = /(&|\?)(refreshDemo|rd)=([^&]*)(&|$)/i;
82  if (window.location.search.match(thisRegExp) !== null) {
83    var refreshDemo = unescape(window.location.search.match(thisRegExp)[3]);
84    if ((refreshDemo == "true") || (refreshDemo == "t")) { alertFlag = demoFlag = true; }
85  }
86
87  thisRegExp = /(&|\?)(demoPly|dp)=([^&]*)(&|$)/i;
88  if (window.location.search.match(thisRegExp) !== null) {
89    gameDemoMaxPly = unescape(window.location.search.match(thisRegExp)[3]).split(",");
90    var p;
91    for (var g in gameDemoMaxPly) { gameDemoMaxPly[g] = isNaN(p = parseInt(gameDemoMaxPly[g], 10)) ? 0 : p; }
92  }
93
94  var refreshMinutes = refreshMinutes_default;
95  var stepFlag = true;
96  thisRegExp = /(&|\?)(refreshMinutes|rm)=([^&]*)(&|$)/i;
97  if (window.location.search.match(thisRegExp) !== null) {
98    refreshMinutes = parseFloat(unescape(window.location.search.match(thisRegExp)[3]));
99    if (isNaN(refreshMinutes)) { refreshMinutes = refreshMinutes_default; }
100    if (refreshMinutes <= 0) { refreshMinutes = refreshMinutes_default; }
101  }
102
103  SetLiveBroadcast(refreshMinutes, alertFlag, demoFlag, stepFlag);
104
105  function getMaxBoardFromLocalStorage() {
106    var mb;
107    try { mb = localStorage.getItem("pgn4web_chess_live_mosaic_viewer_maxBoards"); }
108    catch(e) { return maxBoards_default; }
109    return mb === null ? maxBoards_default : mb;
110  }
111
112  function setMaxBoardToLocalStorage(mb) {
113    try { localStorage.setItem("pgn4web_chess_live_mosaic_viewer_maxBoards", mb); }
114    catch(e) { return false; }
115    return true;
116  }
117
118  var boardTool = boardTool_default;
119  thisRegExp = /(&|\?)(boardTool|bt)=(tile|t|stone|s)(&|$)/i;
120  if (window.location.search.match(thisRegExp) !== null) {
121    boardTool = unescape(window.location.search.match(thisRegExp)[3]);
122    if (boardTool == "t") { boardTool = "tile"; }
123    if (boardTool == "s") { boardTool = "stone"; }
124  }
125  var boardToolFrameHeight = (boardTool == "tile") ? 306 : 318;
126  var boardToolFrameWidth = 256;
127
128  var flipBoards = flipBoards_default;
129  thisRegExp = /(&|\?)(flipBoards|fb)=(none|n|even|e|odd|o|all|a)(&|$)/i;
130  if (window.location.search.match(thisRegExp) !== null) {
131    flipBoards = unescape(window.location.search.match(thisRegExp)[3]);
132    if (flipBoards == "n") { flipBoards = "none"; }
133    if (flipBoards == "e") { flipBoards = "even"; }
134    if (flipBoards == "o") { flipBoards = "odd"; }
135    if (flipBoards == "a") { flipBoards = "all"; }
136  }
137
138  var hideFinishedGamesClocks = false;
139  thisRegExp = /(&|\?)(hideFinishedGamesClocks|hfgc)=([^&]*)(&|$)/i;
140  if (window.location.search.match(thisRegExp) !== null) {
141    var hideFinishedGamesClocksValue = unescape(window.location.search.match(thisRegExp)[3]);
142    if ((hideFinishedGamesClocksValue == "true") || (hideFinishedGamesClocksValue == "t")) { hideFinishedGamesClocks = true; }
143  }
144
145  var headlessPage = false;
146  thisRegExp = /(&|\?)(headlessPage|hp)=([^&]*)(&|$)/i;
147  if (window.location.search.match(thisRegExp) !== null) {
148    var headlessPageValue = unescape(window.location.search.match(thisRegExp)[3]);
149    if ((headlessPageValue == "true") || (headlessPageValue == "t")) { headlessPage = true; }
150  }
151
152  // undocumented features
153
154  var barePadding = "";
155  thisRegExp = /(&|\?)(barePadding|bp)=([^&]*)(&|$)/i;
156  if (window.location.search.match(thisRegExp) !== null) {
157    barePadding = unescape(window.location.search.match(thisRegExp)[3]);
158  }
159  barePadding = barePadding.replace(/[^a-zA-Z0-9%\s]/g, "");
160
161  var backgroundColorHex = "";
162  thisRegExp = /(&|\?)(backgroundColorHex|bch)=([0-9A-Fa-f]{6})(&|$)/i;
163  if (window.location.search.match(thisRegExp) !== null) {
164    backgroundColorHex = unescape(window.location.search.match(thisRegExp)[3]);
165  }
166
167  SetImagePath("images/alpha/24"); // just to avoid console errors
168
169  // disable FlipBoard function
170  function FlipBoard() { }
171
172</script>
173
174
175<style type="text/css">
176
177@import url("fonts/pgn4web-font-LiberationSans.css");
178
179html,
180body {
181  margin: 0px;
182  padding: 0px;
183}
184
185body {
186  color: black;
187  background: white;
188  font-family: sans-serif;
189  padding: 1.75em;
190  overflow-x: hidden;
191  overflow-y: auto;
192
193  -webkit-user-select: none;
194  -moz-user-select: none;
195  -ms-user-select: none;
196  -o-user-select: none;
197  user-select: none;
198  -webkit-text-size-adjust: none;
199  -moz-text-size-adjust: none;
200  -ms-text-size-adjust: none;
201  -o-text-size-adjust: none;
202  text-size-adjust: none;
203  -webkit-touch-callout: none;
204}
205
206a {
207  color: black;
208  text-decoration: none;
209}
210
211a:hover {
212  color: red;
213}
214
215.header {
216  color: red;
217  text-decoration: none;
218}
219
220.beforeBoards {
221  display: inline-block;
222  text-align: right;
223  margin-top: 10px;
224  height: 15px;
225  width: 100%;
226  overflow: hidden;
227}
228
229.afterBoards {
230  display: inline-block;
231  text-align: right;
232  height: 40px;
233  width: 100%;
234  overflow: hidden;
235}
236
237.menuLine {
238  font-size: 12px;
239  font-family: 'pgn4web Liberation Sans', sans-serif;
240  line-height: 20px;
241}
242
243.menuLink {
244  display: inline-block;
245  width: 2em;
246}
247
248.commandLink:hover {
249  text-transform: uppercase;
250}
251
252.hiddenFrame,
253.visibleFrame {
254  margin-left: 20px;
255  margin-right: 20px;
256  margin-top: 15px;
257  margin-bottom: 5px;
258}
259
260.hiddenFrame {
261  display: none;
262}
263
264.visibleFrame {
265  display: inline;
266}
267
268.infoMessage {
269  font-weight: bold;
270  text-align: center;
271}
272
273</style>
274
275</head>
276
277<body id="body">
278
279<script type="text/javascript">
280"use strict";
281
282function fixCSSforBackgroundColorHex() {
283  document.body.style.backgroundColor = "#" + backgroundColorHex;
284}
285
286function fixCSSforHeadelessPage() {
287  document.write("<style type='text/css'> body { color: #AAAAAA; } a { color: #AAAAAA; } a:hover { color: black; } .beforeBoards { margin-top: 15px; } </style>");
288}
289
290function fixCSSforBarePadding() {
291  document.write("<style type='text/css'> body { padding: " + barePadding + "; } .beforeBoards, .afterBoards { display: none; } .menuLine { height: 0; visibility: hidden; } </style>");
292}
293
294function printHeader() {
295  document.write("<h1 style='margin-top:0px; padding-top:0px; text-align:right;'><span style='float:left; color:red;'>pgn4web chess live broadcast</span><a href='.' onfocus='this.blur();' style='width:49px; height:29px; background:url(pawns.png) -47px -15px; vertical-align:baseline; display:inline-block;'></a></h1>");
296}
297
298function printMenu() {
299  document.write("<div id='rightMenu' class='menuLine' style='text-align:right; float:right;'></div><div id='leftMenu' class='menuLine' style='text-align:left; float:left;'><span id='GameLiveStatusDemo' title='this is a simulation of the live broadcast functionality'></span><span id='GameLiveStatus' style='display:none;'></span></div><div id='infoMessage' class='menuLine infoMessage'>...loading PGN data...</div>");
300}
301
302function replayLastMoves() {
303  var wf, rpmm;
304  for (var thisBoard in boardId) {
305    if ((wf = window.frames["board" + boardId[thisBoard]]) && (rpmm = wf.replayPreviousMovesMosaic)) {
306      rpmm(LiveBroadcastEnded);
307    }
308  }
309}
310
311var nextBoardId = 1000;
312var boardId = new Array();
313
314function updateBoardFrames(newMaxBoards) {
315  var theObj = document.getElementById("boardFrames");
316  if (theObj) {
317    theObj.innerHTML = "";
318    for (var board = 0; board < newMaxBoards; board++) {
319      theObj.innerHTML += "<iframe src='live-mosaic-" + boardTool + ".html?ut=t&amp;rm=" + refreshMinutes + "' class='hiddenFrame' id='board" + nextBoardId + "' name='board" + nextBoardId + "' width='" + boardToolFrameWidth + "' height='" + boardToolFrameHeight + "' frameborder='0' marginheight='0' marginwidth='0' scrolling='no'>your web browser and/or your host do not support iframes as required to display the chessboard</iframe>";
320      boardId[board] = nextBoardId++;
321    }
322  }
323  maxBoards = newMaxBoards;
324  setMaxBoardToLocalStorage(maxBoards);
325}
326
327if (headlessPage || (barePadding !== "")) {
328  fixCSSforHeadelessPage();
329  if (barePadding !== "") {
330    fixCSSforBarePadding();
331    if (backgroundColorHex !== "") {
332      fixCSSforBackgroundColorHex();
333    }
334  }
335  printMenu();
336} else {
337  printHeader();
338}
339
340</script>
341
342<center>
343<a class="beforeBoards" name="boards" href="javascript:void(0);" onclick="goToHash('boards');" onfocus="this.blur();">&nbsp;</a>
344<div id="boardFrames"></div>
345<a class="afterBoards" name="bottom" href="javascript:void(0);" onclick="goToHash('');" onfocus="this.blur();">&nbsp;</a>
346</center>
347
348<script type="text/javascript">
349"use strict";
350
351
352if (!headlessPage && (barePadding === "")) { printMenu(); }
353
354
355var pgn4webClearShortCutSquaresForChildFrames = [ ["DH", "8"], ["H", "7"], ["ABH", "6"] ];
356
357var filteredGames = new Array();
358var unfilteredGames = new Array();
359var numberOfGamesForDisplay = 0;
360var firstGame;
361var startGame;
362var firstBoardDisplayGame = 0;
363var gamesForHiding;
364
365function firstFromDisplayGame(dGame) {
366  if (dGame > numberOfGames) { dGame = numberOfGames; }
367  else if (dGame < -numberOfGames) { dGame = -numberOfGames; }
368
369  if (dGame > 0) { dGame--; } // positive displayGame starts from +1 as first game
370
371  var dGameAdjustment = 0;
372  if (filteredGames.length > 0) {
373    var g;
374    if (dGame >= 0) {
375      for (g = 0; g < dGame; g++) {
376        if (checkForHiddenGame(gameEvent[g], gameSite[g], gameDate[g], gameRound[g], gameWhite[g], gameBlack[g])) {
377          dGameAdjustment--;
378        }
379      }
380    } else {
381      for (g = numberOfGames - 1; g > numberOfGames + dGame; g--) {
382        if (checkForHiddenGame(gameEvent[g], gameSite[g], gameDate[g], gameRound[g], gameWhite[g], gameBlack[g])) {
383          dGameAdjustment++;
384        }
385      }
386    }
387  }
388
389  return (dGame + dGameAdjustment);
390}
391
392function gameKey(event, site, date, round, white, black) {
393  var key = "";
394  key += "[" + (typeof(event) == "string" ? event : "") + "]";
395  key += "[" + (typeof(site) == "string" ? site : "") + "]";
396  key += "[" + (typeof(round) == "string" ? round : "") + "]";
397  key += "[" + (typeof(white) == "string" ? white : "") + "]";
398  key += "[" + (typeof(black) == "string" ? black : "") + "]";
399  return key;
400}
401
402function pgn4webHideChildFrameGame(event, site, date, round, white, black, test) {
403  var res = false;
404  if (numberOfGamesForDisplay > 1) {
405    res = hideGame(event, site, date, round, white, black, test);
406    if (res && (test !== true)) {
407      firstGame = firstFromDisplayGame(firstBoardDisplayGame);
408      customFunctionOnPgnTextLoad();
409    }
410  }
411  return res;
412}
413
414function hideGame(event, site, date, round, white, black, test) {
415  var key = gameKey(event, site, date, round, white, black);
416  var meaningful = (key.match(/[A-Za-z0-9]/) !== null);
417  if (meaningful && (test !== true)) {
418    for (var f in filteredGames) { if (key == filteredGames[f]) { return false; } }
419    filteredGames.push(key);
420  }
421  return meaningful;
422}
423
424function checkForHiddenGame(event, site, date, round, white, black) {
425  var key = gameKey(event, site, date, round, white, black);
426  for (var f in filteredGames) {
427    if (key == filteredGames[f]) { return true; }
428  }
429  return false;
430}
431
432function hideEndedGames() {
433  for (var g = 0; g < numberOfGames; g++) {
434    if ((typeof(gameResult[g]) == "undefined") || (gameResult[g].indexOf("*") == -1)) {
435      hideGame(gameEvent[g], gameSite[g], gameDate[g], gameRound[g], gameWhite[g], gameBlack[g]);
436    }
437  }
438  firstGame = firstFromDisplayGame(firstBoardDisplayGame);
439  customFunctionOnPgnTextLoad();
440}
441
442function restoreHiddenGames() {
443  filteredGames = new Array();
444  firstGame = firstFromDisplayGame(firstBoardDisplayGame);
445  customFunctionOnPgnTextLoad();
446}
447
448function pgnGameForBoard(gameNum) {
449  if (!LiveBroadcastDemo) { return fullPgnGame(gameNum); }
450
451  if (gameDemoMaxPly[gameNum] > gameDemoLength[gameNum]) { return fullPgnGame(gameNum); }
452
453  Init(gameNum);
454
455  var localPgnGame = "";
456  if (gameEvent[gameNum]) { localPgnGame += "[Event \"" + gameEvent[gameNum] + "\"]\n"; }
457  if (gameSite[gameNum]) { localPgnGame += "[Site \"" + gameSite[gameNum] + "\"]\n"; }
458  if (gameDate[gameNum]) { localPgnGame += "[Date \"" + gameDate[gameNum] + "\"]\n"; }
459  if (gameRound[gameNum]) { localPgnGame += "[Round \"" + gameRound[gameNum] + "\"]\n"; }
460  if (gameWhite[gameNum]) { localPgnGame += "[White \"" + gameWhite[gameNum] + "\"]\n"; }
461  if (gameBlack[gameNum]) { localPgnGame += "[Black \"" + gameBlack[gameNum] + "\"]\n"; }
462  if (gameResult[gameNum]) { localPgnGame += "[Result \"" + gameResult[gameNum] + "\"]\n"; }
463  if (gameFEN[gameNum]) { localPgnGame += "[FEN \"" + gameFEN[gameNum] + "\"]\n"; }
464  if (gameSetUp[gameNum]) { localPgnGame += "[SetUp \"" + gameSetUp[gameNum] + "\"]\n"; }
465  if (gameVariant[gameNum]) { localPgnGame += "[Variant \"" + gameVariant[gameNum] + "\"]\n"; }
466  if (gameInitialWhiteClock[gameNum]) { localPgnGame += "[WhiteClock \"" + gameInitialWhiteClock[gameNum] + "\"]\n"; }
467  if (gameInitialBlackClock[gameNum]) { localPgnGame += "[BlackClock \"" + gameInitialBlackClock[gameNum] + "\"]\n"; }
468  var theseTags = ["WhiteTeam", "BlackTeam", "WhiteFideId", "BlackFideId", "TimeControl"];
469  var thisTagValue;
470  for (var ii in theseTags) {
471    thisTagValue = customPgnHeaderTag(theseTags[ii]);
472    if (thisTagValue) { localPgnGame += "[" + theseTags[ii] + " \"" + thisTagValue + "\"]\n"; }
473  }
474  localPgnGame += "\n";
475
476  var gameDemoPlyNumber = gameDemoMaxPly[gameNum] <= gameDemoLength[gameNum] ? gameDemoMaxPly[gameNum] : gameDemoLength[gameNum] + 1;
477  for (var thisPly = StartPly; thisPly < StartPly + gameDemoPlyNumber; thisPly++) {
478    if (thisPly % 2) {
479      if (thisComment = MoveComments[thisPly].replace(/{/g, "")) {
480        localPgnGame += "{" + thisComment + "} " + ((thisPly+1)/2) + "... ";
481      }
482      localPgnGame += Moves[thisPly] + " \n";
483    } else {
484      if (thisComment = MoveComments[thisPly].replace(/{/g, "")) { localPgnGame += "{" + thisComment + "} "; }
485      localPgnGame += (thisPly/2+1) + ". " + Moves[thisPly] + " ";
486    }
487  }
488  var thisComment = MoveComments[thisPly].replace(/{/g, "");
489  if (thisComment) { localPgnGame += "{" + thisComment + "} "; }
490  localPgnGame += " *";
491
492  return localPgnGame;
493}
494
495function updateBoard(thisBoardId) {
496  var gameNum = -1;
497  var thisBoard = -1;
498  var thisFrame, gameForBoard, thisPgnGame, thisFlipped, thisFrameClass;
499  for (thisBoard in boardId) { if (thisBoardId === boardId[thisBoard]) { break; } }
500  thisBoard = parseInt(thisBoard, 10);
501  if ((thisBoard < boardId.length) && (thisFrame = document.getElementById("board" + thisBoardId))) {
502    if (thisBoard < numberOfGamesForDisplay) {
503      startGame = startFromFirstGame(firstGame);
504      if (startGame >= 0) { gameForBoard = (startGame + thisBoard) % numberOfGamesForDisplay; }
505      else { gameForBoard = (2 * numberOfGamesForDisplay + startGame - thisBoard) % numberOfGamesForDisplay; }
506      gameNum = unfilteredGames[gameForBoard];
507      thisPgnGame = simpleHtmlentitiesDecode(pgnGameForBoard(gameNum));
508      thisFlipped = (((flipBoards == "even") && (gameNum % 2 === 1)) || ((flipBoards == "odd") && (gameNum % 2 === 0)) || (flipBoards == "all"));
509      thisFrameClass = "visibleFrame";
510    } else {
511      thisPgnGame = "";
512      thisFlipped = (flipBoards == "all");
513      thisFrameClass = "hiddenFrame";
514    }
515    try {
516      if (window.frames["board" + thisBoardId].readyToReceivePgn) {
517        window.frames["board" + thisBoardId].pauseLiveBroadcast();
518        window.frames["board" + thisBoardId].document.getElementById("pgnText").value = thisPgnGame;
519        if (thisFlipped !== window.frames["board" + thisBoardId].IsRotated) { window.frames["board" + thisBoardId].FlipBoard(); }
520        window.frames["board" + thisBoardId].hideFinishedGamesClocks = hideFinishedGamesClocks;
521        window.frames["board" + thisBoardId].refreshPgnSource();
522        window.frames["board" + thisBoardId].clearShortcutSquares("A","8");
523      } // else { myAlert("warning: board #" + thisBoard + " not ready"); }
524    } catch(e) { myAlert("error: failed accessing iframe for board #" + thisBoard, true); }
525    thisFrame.className = thisFrameClass;
526  }
527  return gameNum;
528}
529
530var firstLoadNewBoards = true;
531var firstLoadPgnText = true;
532var liveBroadcastUpdateTicker = 0;
533var previousPgnGameLength = new Array();
534
535function customFunctionOnPgnTextLoad() {
536  var theObj;
537
538  if (firstLoadNewBoards) { newBoards(maxBoards); }
539  if (firstLoadPgnText) { firstGame = firstFromDisplayGame(displayGame); }
540
541  unfilteredGames = new Array();
542  var newMovesInShownGames = false;
543  gamesForHiding = 0;
544  for (var g = 0; g < numberOfGames; g++) {
545    if (!checkForHiddenGame(gameEvent[g], gameSite[g], gameDate[g], gameRound[g], gameWhite[g], gameBlack[g])) {
546      unfilteredGames.push(g);
547      if ((typeof(gameResult[g]) == "undefined") || (gameResult[g].indexOf("*") == -1)) { gamesForHiding++; }
548    }
549  }
550  numberOfGamesForDisplay = unfilteredGames.length;
551
552  readyToSendPgn = true;
553  if (!firstLoadNewBoards) {
554    for (var board = 0; board < maxBoards; board++) {
555      if ((g = updateBoard(boardId[board])) != -1) {
556        if (board === 0) { firstBoardDisplayGame = displayGame >=0 ? g + 1 : numberOfGames - g; }
557        var found_g = false; for (var f in unfilteredGames) { if (unfilteredGames[f] === g) { found_g = true; break; } }
558        if (found_g) {
559          var currentPgnGameLength;
560          if (LiveBroadcastDemo) {
561            currentPgnGameLength = gameDemoMaxPly[g] > gameDemoLength[g] ? gameDemoLength[g] + 1 : gameDemoMaxPly[g];
562          } else {
563            currentPgnGameLength = pgnGame[g].replace(/{[^}]*}/g, " ").replace(/\([^)]*\)/g, " ").length;
564          }
565          newMovesInShownGames = newMovesInShownGames || (typeof(previousPgnGameLength[g]) == "undefined") || (previousPgnGameLength[g] !== currentPgnGameLength);
566          previousPgnGameLength[g] = currentPgnGameLength;
567        }
568      }
569    }
570  }
571
572  if (theObj = document.getElementById("GameLiveStatus")) {
573    if (alertNumSinceReset) {
574      theObj.title += " - " + alertNumSinceReset + " new alert" + (alertNumSinceReset > 1 ? "s" : "");
575    }
576    if (firstLoadPgnText) { theObj.style.display = "inline"; }
577  }
578
579  if (newMovesInShownGames) { liveBroadcastUpdateTicker++; }
580  document.title = liveBroadcastUpdateTicker + "." + LiveBroadcastGamesRunning + "." + numberOfGames + " live broadcast" + (demoFlag ? " demo" : "");
581
582  if (theObj = document.getElementById("GameLiveStatusDemo")) { theObj.innerHTML = LiveBroadcastDemo ? "demo &nbsp; &nbsp; " : ""; }
583
584  updateMenu();
585
586  if (firstLoadNewBoards) { firstLoadNewBoards = false; }
587  if (firstLoadPgnText) { firstLoadPgnText = false; }
588}
589
590function customDebugInfo() {
591  var dbg = "maxBoards=" + maxBoards;
592  dbg += " filtered=" + filteredGames.length;
593  return dbg;
594}
595
596function updateMenu() {
597  var theRightObject, theLeftObject, theInfoObject;
598
599  if (theRightObject = document.getElementById("rightMenu")) {
600    theRightObject.innerHTML = "";
601
602    theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' class='commandLink' href='javascript:void(0);' onclick='replayLastMoves();' title='replaY last moves' onfocus='this.blur();'>&nbsp;y&nbsp;</a></span>";
603
604    if (numberOfGamesForDisplay > maxBoards) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='previousPage();' title='showing from game " + (Math.abs(firstGame)+1) + "/" + numberOfGamesForDisplay + ": view the Earlier games' onfocus='this.blur();'>&nbsp;e&nbsp;</a></span><span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='nextPage();' title='showing from game " + (Math.abs(firstGame)+1) + "/" + numberOfGamesForDisplay + ": view the Next games' onfocus='this.blur();'>&nbsp;n&nbsp;</a></span>"; }
605
606    if (maxBoards > 1 && numberOfGamesForDisplay > 1) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='newBoards(" + Math.min(maxBoards - 1, numberOfGamesForDisplay - 1) + ");' title='show one chessboard Less' onfocus='this.blur();'>&nbsp;l&nbsp;</a></span>"; }
607    if (numberOfGamesForDisplay > maxBoards) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='newBoards(" + (maxBoards + 1) + ");' title='show one chessboard More' onfocus='this.blur();'>&nbsp;m&nbsp;</a></span>"; }
608
609    if (LiveBroadcastStarted && !LiveBroadcastEnded && gamesForHiding && numberOfGamesForDisplay > 1) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='hideEndedGames();' title='Hide games finished so far' onfocus='this.blur();'>&nbsp;h&nbsp;</a></span>"; }
610    if (filteredGames.length > 0) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='restoreHiddenGames();' title='Unhide games previously hidden: " + filteredGames.length + "/" + numberOfGames + "' onfocus='this.blur();'>&nbsp;u&nbsp;</a></span>"; }
611
612    if (LiveBroadcastDelay > 0) {
613      if (LiveBroadcastEnded) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='restartLiveBroadcast();' title='Check for the start of a new live broadcast event' onfocus='this.blur();'>&nbsp;c&nbsp;</a></span>"; }
614      else {
615        if (LiveBroadcastPaused && LiveBroadcastStarted) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='restartLiveBroadcast(); updateMenu();' title='Restart live broadcast automatic refresh of games' onfocus='this.blur();'>&nbsp;r&nbsp;</a></span>"; }
616        else if (LiveBroadcastPaused && !LiveBroadcastStarted) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='restartLiveBroadcast(); updateMenu();' title='Restart polling for a new live broadcast' onfocus='this.blur();'>&nbsp;r&nbsp;</a></span>"; }
617        else if (LiveBroadcastStarted) { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='pauseLiveBroadcast(); updateMenu();' title='Pause live broadcast automatic refresh of games' onfocus='this.blur();'>&nbsp;p&nbsp;</a></span>"; }
618        else { theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' href='javascript:void(0);' onclick='pauseLiveBroadcast(); updateMenu();' title='Pause polling for a new live broadcast' onfocus='this.blur();'>&nbsp;p&nbsp;</a></span>"; }
619        theRightObject.innerHTML += "<span class='menuLink'><a class='commandLink' class='commandLink' href='javascript:void(0);' onclick='refreshPgnSource();' title='Force games refresh" + (LiveBroadcastStarted ? ": last moves received on " + LiveBroadcastLastReceivedLocal : "") + "' onfocus='this.blur();'>&nbsp;f&nbsp;</a></span>";
620      }
621    }
622
623    if (theRightObject && (theLeftObject = document.getElementById("leftMenu"))) {
624      theRightObject.style.minWidth = 0;
625      theLeftObject.style.minWidth = 0;
626      theRightObject.style.minWidth = theLeftObject.offsetWidth + "px";
627      theLeftObject.style.minWidth = theRightObject.offsetWidth + "px";
628    }
629  }
630
631  if (theInfoObject = document.getElementById("infoMessage")) {
632    if (numberOfGamesForDisplay < 1) {
633      theInfoObject.innerHTML = "warning: all games hidden: <a href='javascript:void(0);' onclick='restoreHiddenGames();' onfocus='this.blur();'>unhide games</a> or <a href='javascript:void(0);' onclick='refreshPgnSource();' onfocus='this.blur();'>force live refresh</a>";
634    } else {
635      var theEvent = "";
636      var theSite = "";
637      for (var n = 0; n < numberOfGames; n++) {
638        if ((theEvent !== false) && (theEvent !== gameEvent[n])) {
639          if (theEvent) { theEvent = false; }
640          else { theEvent = gameEvent[n]; }
641        }
642        if ((theSite !== false) && (theSite !== gameSite[n])) {
643          if (theSite) { theSite = false; }
644          else { theSite = gameSite[n]; }
645        }
646      }
647      if (theEvent == "?") { theEvent = ""; }
648      if (theSite == "?") { theSite = ""; }
649      if (theEvent) { theEvent = theEvent.replace(/\s/g, "&nbsp;").replace(/-/g, "&#8209;"); }
650      if (theSite) { theSite = theSite.replace(/\s/g, "&nbsp;").replace(/-/g, "&#8209;"); }
651
652      if (theEvent || theSite) {
653        var theInfoObjectText = "<span class='notranslate'>&nbsp;&nbsp;&nbsp;";
654        if (theEvent) { theInfoObjectText += theEvent; }
655        if (theEvent && theSite) { theInfoObjectText += "&nbsp;&nbsp;&nbsp;"; }
656        if (theSite) { theInfoObjectText += theSite; }
657        theInfoObjectText += "&nbsp;&nbsp;&nbsp;</span>";
658        theInfoObject.innerHTML = theInfoObjectText;
659        theInfoObject.title = "event currently on display: hover the mouse below each chessboard for more details";
660      } else {
661        theInfoObject.innerHTML = "&nbsp;";
662        theInfoObject.title = "";
663      }
664    }
665  }
666
667}
668
669function startFromFirstGame(fGame) {
670  if (fGame >= numberOfGamesForDisplay) { return numberOfGamesForDisplay - 1; }
671  if (fGame < -numberOfGamesForDisplay) { return 0; }
672  if (fGame < 0) { return numberOfGamesForDisplay + fGame; }
673  else { return fGame; }
674}
675
676function nextPage() {
677  firstGame = (startFromFirstGame(firstGame) + maxBoards) % numberOfGamesForDisplay;
678  firstGame -= (firstGame < 0 ? numberOfGamesForDisplay : 0);
679  customFunctionOnPgnTextLoad();
680}
681
682function previousPage() {
683  firstGame = (startFromFirstGame(firstGame) - maxBoards + numberOfGamesForDisplay) % numberOfGamesForDisplay;
684  firstGame -= (firstGame < 0 ? numberOfGamesForDisplay : 0);
685  customFunctionOnPgnTextLoad();
686}
687
688function newBoards(newMaxBoards) {
689  updateBoardFrames(newMaxBoards);
690  updateMenu();
691}
692
693function cycleHash() {
694  switch (location.hash) {
695    case "#boards": goToHash("bottom"); break;
696    case "#bottom": goToHash(""); break;
697    default: goToHash("boards"); break;
698  }
699}
700
701function goToHash(hash) {
702  if (hash) { location.hash = ""; }
703  else { location.hash = "boards"; }
704  location.hash = hash;
705}
706
707function customShortcutKey_Shift_3() { cycleHash(); }
708
709function customShortcutKey_Shift_5() {
710  displayGame = displayGame_default;
711  firstLoadPgnText = true;
712  customFunctionOnPgnTextLoad();
713}
714
715function customShortcutKey_Shift_6() {
716  firstLoadPgnText = true;
717  customFunctionOnPgnTextLoad();
718}
719
720function customShortcutKey_Shift_7() {
721  restoreHiddenGames();
722}
723
724function customShortcutKey_Shift_8() {
725  newBoards(maxBoards_default);
726}
727
728function pgn4web_onload(e) {
729  start_pgn4web();
730  if (location.hash) { setTimeout("goToHash('" + location.hash + "');", 333 * maxBoards); }
731}
732
733</script>
734
735</body>
736
737</html>
738