1<!DOCTYPE HTML>
2<html>
3
4<!--
5  pgn4web javascript chessboard
6  copyright (C) 2009-2016 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 board generator</title>
14
15<style type="text/css">
16
17html,
18body {
19  margin: 0px;
20  padding: 0px;
21}
22
23body {
24  font-family: sans-serif;
25  color: black;
26  background: white;
27  padding: 10px;
28  overflow-x: hidden;
29}
30
31a {
32  text-decoration: none;
33  color: black;
34}
35
36a:hover {
37  text-decoration: underline;
38}
39
40.helptext, .helplink {
41  color: gray;
42}
43
44.helplink {
45  font-weight: bold;
46}
47
48.labeltext, .largeDropdown, .configtext {
49  margin-right: 1.0em;
50}
51
52.labeltext {
53  margin-left: 1.3em;
54}
55
56.helptext {
57  font-size: 80%;
58  margin-right: 0px;
59  margin-left: 0px;
60}
61
62.input, .textbox {
63  border-width: 1px;
64  border-style: inset;
65  border-color: #CCCCCC;
66}
67
68.input, .checkbox, .dropdown, .largeDropdown, .configtext {
69/* if the margin-left value below is changed from 22px
70   then the corresponding value at the end of the file needs changing accordingly */
71  margin-left: 22px;
72}
73
74.input, .checkbox, .checkbox {
75  margin-right: 0px;
76}
77
78.textbox {
79  width: 100%;
80  box-sizing: border-box;
81  -moz-box-sizing: border-box;
82  -webkit-box-sizing: border-box;
83}
84
85.shortUrl {
86  font-weight: bold;
87  color: goldenrod;
88  white-space: nowrap;
89}
90
91</style>
92
93<link rel="icon" sizes="16x16" href="pawn.ico" />
94
95</head>
96
97<body>
98<script type="text/javascript" src="libs/jscolor/jscolor.js"></script>
99<script src="pgn4web-server-config.js" type="text/javascript"></script>
100<script src="pgn4web.js" type="text/javascript"></script>
101
102<script src="pgn-decoder.js" type="text/javascript"></script>
103<script src="pgn-encoder.js" type="text/javascript"></script>
104<script src="crc32.js" type="text/javascript"></script>
105
106<script type="text/javascript">
107"use strict";
108
109// this should have been defined in pgn4web-server-config.js
110// setting default value here just in case
111var pgn4web_bitly_login;
112if (pgn4web_bitly_login === undefined) { pgn4web_bitly_login = ""; }
113var pgn4web_bitly_apiKey;
114if (pgn4web_bitly_apiKey === undefined) { pgn4web_bitly_apiKey = ""; }
115
116var shorturlWin = null;
117function shorten_pgn4web_url() {
118  if (!document.board.useTextarea.checked) {
119    //
120    // pick the short URL service: bitly is used if login/key pair
121    // is defined in pgn4web-server-config.js, tinyurl otherwise
122    //
123    if (pgn4web_bitly_login && pgn4web_bitly_apiKey) {
124      shorten_url_with_bitly(pgn4web_bitly_login, pgn4web_bitly_apiKey);
125    } else { shorten_url_with_tinyurl(); }
126  } else {
127    alert('URL sharing creation unavailable when useTextarea is enabled');
128  }
129}
130
131// use this in shorten_pgn4web_url() to generate short urls with bitly
132// using bitly apis version 3, correct here if apis are changed
133function shorten_url_with_bitly(bitly_login, bitly_apiKey) {
134  var bitly_post_request = "http://api.bitly.com/v3/shorten";
135  var bitly_params = "login=" + bitly_login + "&apiKey=" + bitly_apiKey + "&format=txt" + "&longUrl=" + encodeURIComponent(iframeUrl);
136  var bitly_get_request = bitly_post_request + "?" + bitly_params;
137
138  var bitly_link = null;
139  try {
140    document.getElementById("shorturl_link_separator").innerHTML = "<b>:</b> ";
141    var xhr = new XMLHttpRequest();
142    xhr.open("POST", bitly_post_request);
143    xhr.setRequestHeader("Content-type", "text/plain");
144    xhr.onreadystatechange = function() {
145      if (xhr.readyState == 4) {
146        if (xhr.status==200) {
147          if (xhr.responseText.match(/^http/)) {
148            bitly_link = xhr.responseText;
149          }
150        }
151        bitly_link = bitly_link.replace(/\s/g, "");
152        if (bitly_link) {
153          document.getElementById("html_code").value = document.getElementById("html_code").value.replace(/src='.+?'/, "src='" + bitly_link + "'");
154          document.getElementById("shorturl_link_pointer").innerHTML = bitly_link;
155          document.getElementById("shorturl_link_pointer").href = bitly_link;
156          document.getElementById("shorturl_link_pointer").target = "_blank";
157          document.getElementById("shorturl_link_pointer").title = "right-click, copy and share the chessboard short url";
158        } else {
159          document.getElementById("shorturl_link_pointer").innerHTML = "failed generating short url";
160          document.getElementById("shorturl_link_pointer").href = "";
161          document.getElementById("shorturl_link_pointer").target = "";
162          document.getElementById("shorturl_link_pointer").title = "possible failure causes: url shortening service unavailable, network error, outdated login/apiKey pair, outdated apis or something else; try again later and eventually file a pgn4web board generator bug report";
163        }
164      }
165    };
166    xhr.send(bitly_params);
167  } catch(e) {
168    document.getElementById('bitly_form_login').value = bitly_login;
169    document.getElementById('bitly_form_apiKey').value = bitly_apiKey;
170    document.getElementById('bitly_form_longUrl').value = iframeUrl;
171    document.getElementById('bitly_form_format').value = "txt";
172
173    shorturl_window_close();
174    shorturlWin = window.open('', 'pgn4web_shorturl_window');
175
176    document.forms['bitly_form_shorturl'].submit();
177
178    document.getElementById("shorturl_link_pointer").innerHTML = "see pb.casaschi.net window";
179    document.getElementById("shorturl_link_pointer").href = "javascript:shorturl_window_focus();";
180    document.getElementById("shorturl_link_pointer").target = "";
181    document.getElementById("shorturl_link_pointer").title = "the chessboard short url should be available in a separate browser window from pb.casaschi.net";
182
183    shorturl_window_focus();
184  }
185
186}
187
188// use this in shorten_pgn4web_url() to generate short urls with tinyurl
189function shorten_url_with_tinyurl() {
190  document.getElementById("shorturl_link_separator").innerHTML = "<b>:</b> ";
191
192  var thisLink = document.createElement("a");
193  thisLink.href = iframeUrl;
194  var thisIframeUrl = thisLink.href;
195  var thisShortUrlCrc32 = printHex(crc32(thisIframeUrl));
196  document.getElementById('tinyurl_form_shorturl_url').value = thisIframeUrl;
197  document.getElementById('tinyurl_form_shorturl_alias').value = "pgn4web-" + thisShortUrlCrc32;
198  document.getElementById('shorturl_link').title = "pgn4web board short url #" + thisShortUrlCrc32;
199
200  shorturl_window_close();
201  shorturlWin = window.open('', 'pgn4web_shorturl_window');
202
203  document.forms['tinyurl_form_shorturl'].submit();
204
205  document.getElementById("shorturl_link_pointer").innerHTML = "see tinyurl window";
206  document.getElementById("shorturl_link_pointer").href = "javascript:shorturl_window_focus();";
207  document.getElementById("shorturl_link_pointer").target = "";
208  document.getElementById("shorturl_link_pointer").title = "the chessboard short url should be available in a separate browser window from tinyurl.com";
209
210  shorturl_window_focus();
211}
212
213function shorturl_window_focus() {
214  try {
215    if (shorturlWin && window.focus) { shorturlWin.focus(); }
216  } catch(e) { }
217}
218
219function shorturl_window_close() {
220  try {
221    if (shorturlWin && !shorturlWin.closed) { shorturlWin.close(); }
222    shorturlWin = null;
223  } catch(e) { }
224}
225
226function shorturl_link_clean() {
227  document.getElementById("shorturl_link_separator").innerHTML = "";
228  document.getElementById("shorturl_link_pointer").innerHTML = "";
229  document.getElementById("shorturl_link_pointer").href = "";
230  document.getElementById("shorturl_link_pointer").target = "";
231  document.getElementById("shorturl_link_pointer").title = "";
232}
233
234</script>
235
236<script type="text/javascript">
237"use strict";
238
239// this should have been defined in pgn4web-server-config.js
240// setting default value here just in case
241var pgn4web_board_url;
242if (pgn4web_board_url == undefined) { pgn4web_board_url = location.protocol + "//" + location.hostname + location.pathname.substr(0, location.pathname.lastIndexOf("/")) + "/board.html"; }
243</script>
244
245<script type="text/javascript">
246"use strict";
247
248// CUSTOMIZATION INSTRUCTIONS
249// if you customize the board-generator.html file for your site
250// you probably want to customize the default values
251
252var pgnText_default = emptyPgnHeader + '\n';
253var encodePgn_default = "t";
254var autoplayMode_default = "game";
255var delay_default = 3000;
256var initialGame_default = "first";
257var initialVariation_default = "";
258var initialHalfmove_default = "start";
259var initialHalfmoveSelect_default = initialHalfmove_default;
260var initialHalfmoveNumber_default = "0";
261var pieceFont_default = "default";
262var pieceSize_default = "default";
263var squareSize_default = 40;
264var lightColorHex_default = "EFF4EC";
265var darkColorHex_default = "C6CEC3";
266var boardBorderColorHex_default = "000000";
267var boardShadowColorHex_default = "transparent";
268var highlightMode_default = "square";
269var highlightColorHex_default = "DAF4D7";
270var buttonsDisplay_default = "hidden";
271var controlBackgroundColorHex_default = "EFF4EC";
272var controlTextColorHex_default = "000000";
273var textMargin_default = 0;
274var headerDisplay_default = "justified";
275var movesDisplay_default = "figurine";
276var horizontalLayout_default = "f";
277var frameHeight_default = "";
278var frameWidth_default = "";
279var framePadding_default = 0;
280var commentsDisplay_default = "inline";
281var fontHeaderColorHex_default = "000000";
282var fontMovesColorHex_default = "000000";
283var fontCommentsColorHex_default = "808080";
284var fontVariationsColorHex_default = "comments";
285var highlightMoveColorHex_default = "DAF4D7";
286var fontHeaderSize_default = "16";
287var fontMovesSize_default = "16";
288var fontCommentsSize_default = "moves";
289var fontVariationsSize_default = "comments";
290var backgroundColorHex_default = "FFFFFF";
291var previewBackgroundColorHex_default = "DDDDDD";
292var boardUrl_default = pgn4web_board_url;
293var useTextarea_default = "f";
294
295// end of default values
296
297var pgnText_value;
298var encodePgn_value;
299var autoplayMode_value;
300var delay_value;
301var initialGame_value;
302var initialVariation_value;
303var initialHalfmove_value;
304var initialHalfmoveSelect_value;
305var initialHalfmoveNumber_value;
306var pieceFont_value;
307var pieceSize_value;
308var squareSize_value;
309var lightColorHex_value;
310var darkColorHex_value;
311var boardBorderColorHex_value;
312var boardShadowColorHex_value;
313var highlightMode_value;
314var highlightColorHex_value;
315var buttonsDisplay_value;
316var controlBackgroundColorHex_value;
317var controlTextColorHex_value;
318var textMargin_value;
319var headerDisplay_value;
320var movesDisplay_value;
321var horizontalLayout_value;
322var frameHeight_value;
323var frameWidth_value;
324var framePadding_value;
325var commentsDisplay_value;
326var fontHeaderColorHex_value;
327var fontMovesColorHex_value;
328var fontCommentsColorHex_value;
329var fontVariationsColorHex_value;
330var highlightMoveColorHex_value;
331var fontHeaderSize_value;
332var fontMovesSize_value;
333var fontCommentsSize_value;
334var fontVariationsSize_value;
335var backgroundColorHex_value;
336var previewBackgroundColorHex_value;
337var boardUrl_value;
338var useTextarea_value;
339
340var pgnTextEncoded;
341var previousPgnTextToEncode;
342
343var iframeUrl;
344
345// max length of the iframeUrl, if this is exceeded a warning is issued
346var iframeUrl_max = 2000;
347
348var suggested_frameHeight;
349var suggested_frameWidth;
350var min_frameHeight;
351var min_frameWidth;
352
353var pgnId;
354
355
356function gup(name) {
357
358  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
359  var regexS = "[\\?&]"+name+"=([^&#]*)";
360  regexS = regexS+"(?!.*"+regexS+")"; // matches the LAST occurrence
361  var regex = new RegExp( regexS, "i" );
362  var results = regex.exec( window.location.href );
363  if (results !== null) { return decodeURIComponent(results[1]); }
364
365  // allows for short version of the URL parameters, for instance sC matches squareColor
366  var compact_name = name.charAt(0);
367  for (var i=1; i<name.length; i++) {
368    if (name.charAt(i).match(/[A-Z]/)) { compact_name = compact_name + name.charAt(i).toLowerCase(); }
369  }
370  name = compact_name;
371
372  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
373  regexS = "[\\?&]"+name+"=([^&#]*)";
374  regexS = regexS+"(?!.*"+regexS+")"; // matches the LAST occurrence
375  regex = new RegExp( regexS, "i" );
376  results = regex.exec( window.location.href );
377  if (results !== null) { return decodeURIComponent(results[1]); }
378
379  return "";
380}
381
382var newStyleSheet = '<style type="text/css"> \n';
383if ((gup("extendedOptions") == "true") || (gup("extendedOptions") == "t")) {
384  newStyleSheet += '.extendedOption { display: inline; } \n';
385  newStyleSheet += '.noExtendedOption { display: none; } \n';
386} else {
387  newStyleSheet += '.extendedOption { display: none; } \n';
388  newStyleSheet += '.noExtendedOption { display: inline; } \n';
389}
390newStyleSheet += '</style> \n';
391document.write(newStyleSheet);
392
393function new_onLoad() {
394  jscolor.bind(); // bugfix: IE issue
395  set_defaults();
396}
397
398function set_defaults() {
399
400  load_templates();
401  document.getElementById('templatesList').options[1].value = location.search.replace(/&(pe|pt)=.*(&|$)/,"");
402
403  document.getElementById('html_code').value = '';
404  document.getElementById('html_code_status').innerHTML = '&nbsp;';
405
406  if ((pgnTextEncoded = gup("pgnEncoded")) !== "") {
407    pgnText_value = DecodePGN(pgnTextEncoded);
408    previousPgnTextToEncode = pgnText_value;
409  } else {
410    if ((pgnText_value = gup("pgnText")) === "") { pgnText_value = pgnText_default; }
411    previousPgnTextToEncode = "";
412  }
413  document.getElementById('pgnText').value = pgnText_value;
414  update_pgnTextLength();
415
416  if ((encodePgn_value = gup("encodePgn")) === "") { encodePgn_value = encodePgn_default; }
417  document.board.encodePgn.checked = (encodePgn_value == "t");
418
419  var oldAutoplayMode_value = "";
420  //kept for backward compatibility
421  if ((gup("loop") == "true") || (gup("loop") == "t")) { oldAutoplayMode_value = "loop"; }
422  //kept for backward compatibility
423  if ((gup("auto") == "false") || (gup("loop") == "f")) { oldAutoplayMode_value = "none"; }
424
425  if ((autoplayMode_value = gup("autoplayMode")) === "") {
426    autoplayMode_value = oldAutoplayMode_value === "" ? autoplayMode_default : oldAutoplayMode_value;
427  }
428  if (autoplayMode_value == "g") { autoplayMode_value = "game"; }
429  if (autoplayMode_value == "l") { autoplayMode_value = "loop"; }
430  if (autoplayMode_value == "n") { autoplayMode_value = "none"; }
431    document.board.autoplayMode.value = autoplayMode_value;
432  if (!((autoplayMode_value == "game") || (autoplayMode_value == "loop") ||
433        (autoplayMode_value == "none")) ) {
434    alert("error: autoplay mode must be either 'game', 'loop', 'none' or their initials");
435    document.board.autoplayMode.value = autoplayMode_value = autoplayMode_default;
436  }
437
438  if ((delay_value = gup("delay")) === "") { delay_value = delay_default; }
439  document.board.delay.value = delay_value;
440
441  if ((initialGame_value = gup("initialGame")) === "") { initialGame_value = initialGame_default; }
442  if ((initialGame_value == "f") || (initialGame_value == "false")) { initialGame_value = "first"; }
443  if (initialGame_value == "l") { initialGame_value = "last"; }
444  if (initialGame_value == "r") { initialGame_value = "random"; }
445  document.board.initialGame.value = initialGame_value;
446  if (!((initialGame_value == "first") || (initialGame_value == "last") ||
447        (initialGame_value == "random")) ) {
448    alert("error: initial game must be either 'first', 'last', 'random' or their initials");
449    document.board.initialGame.value = initialGame_value = initialGame_default;
450  }
451
452  if ((initialVariation_value = gup("initialVariation")) === "") { initialVariation_value = initialVariation_default; }
453
454  if ((initialHalfmove_value = gup("initialHalfmove")) === "") { initialHalfmove_value = initialHalfmove_default; }
455  if (initialHalfmove_value == "s") { initialHalfmove_value = "start"; }
456  if (initialHalfmove_value == "e") { initialHalfmove_value = "end"; }
457  if (initialHalfmove_value == "r") { initialHalfmove_value = "random"; }
458  if (initialHalfmove_value == "c") { initialHalfmove_value = "comment"; }
459  if (initialHalfmove_value == "v") { initialHalfmove_value = "variation"; }
460  document.board.initialHalfmove.value = initialHalfmove_value;
461  checkInitialHalfmove();
462
463  if ((pieceFont_value = gup("pieceFont")) === "") { pieceFont_value = pieceFont_default; }
464  if (pieceFont_value == "a") { pieceFont_value = "alpha"; }
465  if (pieceFont_value == "m") { pieceFont_value = "merida"; }
466  if (pieceFont_value == "u") { pieceFont_value = "uscf"; }
467  if (pieceFont_value == "r") { pieceFont_value = "random"; }
468  if (pieceFont_value == "d") { pieceFont_value = "default"; }
469  document.board.pieceFont.value = pieceFont_value;
470  if (!((pieceFont_value == "alpha") || (pieceFont_value == "merida") ||
471        (pieceFont_value == "uscf")  || (pieceFont_value == "random") ||
472        (pieceFont_value == "default")) ) {
473    alert("error: piece font must be either 'alpha', 'merida', 'uscf', 'random', 'default' or their initials");
474    document.board.pieceFont.value = pieceFont_value = pieceFont_default;
475  }
476
477  if ((squareSize_value = gup("squareSize")) === "") { squareSize_value = squareSize_default; }
478  document.getElementById('squareSize').value = squareSize_value = parseInt(squareSize_value, 10);
479  // value validation done later in validate_ss_ps_hm();
480
481  if ((pieceSize_value = gup("pieceSize")) === "") { pieceSize_value = pieceSize_default; }
482  if (pieceSize_value == "d") { pieceSize_value = "default"; }
483  if (pieceSize_value == "default") {
484    document.getElementById('pieceSize').value = pieceSize_value;
485  } else {
486    document.getElementById('pieceSize').value = pieceSize_value = parseInt(pieceSize_value, 10);
487  }
488  // value validation done later in validate_ss_ps_hm();
489
490  if ((lightColorHex_value = gup("lightColorHex")) === "") {
491    if ((lightColorHex_value = sex2hex(gup("lightColorSex"), 'light squares color')) === "") {
492      lightColorHex_value = lightColorHex_default;
493    }
494  }
495  document.board.lightColorHex.color.fromString(lightColorHex_value);
496  validate_color(document.board.lightColorHex, 'light squares color', lightColorHex_default);
497
498  if ((darkColorHex_value = gup("darkColorHex")) === "") {
499    if ((darkColorHex_value = sex2hex(gup("darkColorSex"), 'dark squares color')) === "") {
500      darkColorHex_value = darkColorHex_default;
501    }
502  }
503  document.board.darkColorHex.color.fromString(darkColorHex_value);
504  validate_color(document.board.darkColorHex, 'dark squares color', darkColorHex_default);
505
506  if ((boardBorderColorHex_value = gup("boardBorderColorHex")) === "") {
507    if ((boardBorderColorHex_value = sex2hex(gup("boardBorderColorSex"), 'board border color')) === "") {
508      boardBorderColorHex_value = boardBorderColorHex_default;
509    }
510  }
511  document.board.boardBorderColorHex.color.fromString(boardBorderColorHex_value);
512  validate_color(document.board.boardBorderColorHex, 'board border color', boardBorderColorHex_default);
513
514  if ((highlightMode_value = gup("highlightMode")) === "") { highlightMode_value = highlightMode_default; }
515  if (highlightMode_value == "b") { highlightMode_value = "border"; }
516  if (highlightMode_value == "n") { highlightMode_value = "none"; }
517  if (highlightMode_value == "s") { highlightMode_value = "square"; }
518  document.board.highlightMode.value = highlightMode_value;
519  if (!((highlightMode_value == "border") || (highlightMode_value == "none") ||
520        (highlightMode_value == "square")) ) {
521    alert("error: highlight mode must be either 'border', 'square', 'none' or their initials");
522    document.board.highlightMode.value = highlightMode_value = highlightMode_default;
523  }
524  validate_ss_ps_hm();
525
526  if ((highlightColorHex_value = gup("highlightColorHex")) === "") {
527    if ((highlightColorHex_value = sex2hex(gup("highlightColorSex"), 'highlight squares color')) === "") {
528      highlightColorHex_value = highlightColorHex_default;
529    }
530  }
531  if (highlightColorHex_value == 'n') { highlightColorHex_value = 'none'; }
532  if (highlightColorHex_value == 'none') {
533    document.board.highlightMode.value = highlightMode_value = "none";
534    highlightColorHex_value = highlightColorHex_default;
535  }
536  document.board.highlightColorHex.color.fromString(highlightColorHex_value);
537  validate_color(document.board.highlightColorHex, 'highlight squares color', highlightColorHex_default);
538
539  var oldButtonsDisplay_value = "";
540  //kept for backward compatibility
541  if (gup("showButtons") == "t") { oldButtonsDisplay_value = "custom"; }
542  //kept for backward compatibility
543  if (gup("showButtons") == "f") { oldButtonsDisplay_value = "hidden"; }
544
545  if ((buttonsDisplay_value = gup("buttonsDisplay")) === "") {
546    buttonsDisplay_value = oldButtonsDisplay_value === "" ? buttonsDisplay_default : oldButtonsDisplay_value;
547  }
548  if (buttonsDisplay_value == "c") { buttonsDisplay_value = "custom"; }
549  if (buttonsDisplay_value == "h") { buttonsDisplay_value = "hidden"; }
550  if (buttonsDisplay_value == "s") { buttonsDisplay_value = "standard"; }
551  document.board.buttonsDisplay.value = buttonsDisplay_value;
552  if (!((buttonsDisplay_value == "custom") || (buttonsDisplay_value == "hidden") ||
553        (buttonsDisplay_value == "standard")) ) {
554    alert("error: buttons display must be either 'custom', 'hidden', 'standard' or their initials");
555    document.board.buttonsDisplay.value = buttonsDisplay_value = buttonsDisplay_default;
556  }
557
558  if ((controlBackgroundColorHex_value = gup("controlBackgroundColorHex")) === "") {
559    var controlBackgroundColorSex = gup("controlBackgroundColorSex");
560    if ((controlBackgroundColorHex_value = sex2hex(controlBackgroundColorSex, 'control buttons background color')) === "") {
561      controlBackgroundColorHex_value = controlBackgroundColorHex_default;
562    }
563  }
564  if (controlBackgroundColorHex_value == 'd') { controlBackgroundColorHex_value = 'default'; }
565  if (controlBackgroundColorHex_value == 'default') {
566    document.board.buttonsDisplay.value = buttonsDisplay_value = "standard";
567    controlBackgroundColorHex_value = controlBackgroundColorHex_default;
568  }
569  document.board.controlBackgroundColorHex.color.fromString(controlBackgroundColorHex_value);
570  validate_color(document.board.controlBackgroundColorHex, 'control buttons background color', 'default');
571
572  if ((controlTextColorHex_value = gup("controlTextColorHex")) === "") {
573    if ((controlTextColorHex_value = sex2hex(gup("controlTextColorSex"), 'control buttons text color')) === "") {
574      controlTextColorHex_value = controlTextColorHex_default;
575    }
576  }
577  document.board.controlTextColorHex.color.fromString(controlTextColorHex_value);
578  validate_color(document.board.controlTextColorHex, 'control buttons text color', controlTextColorHex_default);
579
580  if ((textMargin_value = gup("textMargin")) === "") { textMargin_value = textMargin_default; }
581  document.getElementById('textMargin').value = textMargin_value;
582  validate_number(document.getElementById('textMargin'), 'text margin', textMargin_default);
583
584  var oldHeaderDisplay_value = "";
585  //kept for backward compatibility
586  if (gup("showHeader") == "t") { oldHeaderDisplay_value = "justified"; }
587  //kept for backward compatibility
588  if (gup("showHeader") == "f") { oldHeaderDisplay_value = "hidden"; }
589
590  if ((headerDisplay_value = gup("headerDisplay")) === "") {
591    headerDisplay_value = oldHeaderDisplay_value === "" ? headerDisplay_default : oldHeaderDisplay_value;
592  }
593  if (headerDisplay_value == "c") { headerDisplay_value = "centered"; }
594  if (headerDisplay_value == "h") { headerDisplay_value = "hidden"; }
595  if (headerDisplay_value == "j") { headerDisplay_value = "justified"; }
596  if (headerDisplay_value == "l") { headerDisplay_value = "live"; }
597  if (headerDisplay_value == "v") { headerDisplay_value = "variations"; }
598  document.board.headerDisplay.value = headerDisplay_value;
599  if (!((headerDisplay_value == "centered") || (headerDisplay_value == "hidden") ||
600        (headerDisplay_value == "justified") || (headerDisplay_value == "live") ||
601        (headerDisplay_value == "variations")) ) {
602    alert("error: header display must be either 'centered', 'hidden', 'justified', 'live', 'variations' or their initials");
603    document.board.headerDisplay.value = headerDisplay_value = headerDisplay_default;
604  }
605
606  var oldMovesDisplay_value = "";
607  //kept for backward compatibility
608  if (gup("showMoves") === "t") { oldMovesDisplay_value = "figurine"; }
609  //kept for backward compatibility
610  if (gup("showMoves") === "f") { oldMovesDisplay_value = "hidden"; }
611
612  if ((movesDisplay_value = gup("movesDisplay")) === "") {
613    movesDisplay_value = oldMovesDisplay_value === "" ? movesDisplay_default : oldMovesDisplay_value;
614  }
615  if (movesDisplay_value == "h") { movesDisplay_value = "hidden"; }
616  if (movesDisplay_value == "f") { movesDisplay_value = "figurine"; }
617  if (movesDisplay_value == "t") { movesDisplay_value = "text"; }
618  // "nosymbols" option is undocumented
619  if (movesDisplay_value == "n") { movesDisplay_value = "nosymbols"; }
620  if (movesDisplay_value == "p") { movesDisplay_value = "puzzle"; }
621  //kept for backward compatibility
622  if ((movesDisplay_value == "justified") || (movesDisplay_value == "j")) { movesDisplay_value = "figurine"; }
623  document.board.movesDisplay.value = movesDisplay_value;
624  if (!((movesDisplay_value == "hidden") || (movesDisplay_value == "figurine") || (movesDisplay_value == "nosymbols") || (movesDisplay_value == "puzzle") || (movesDisplay_value == "text"))) {
625    alert("error: moves display must be either 'hidden', 'figurine', 'puzzle', 'text' or their initials");
626    document.board.movesDisplay.value = movesDisplay_value = movesDisplay_default;
627  }
628
629  var oldCommentsDisplay_value = "";
630  //kept for backward compatibility
631  if (gup("showCommentsOnSeparateLines") === "t") { oldCommentsDisplay_value = "newline"; }
632  //kept for backward compatibility
633  if (gup("showComments") === "f") { oldCommentsDisplay_value = "hidden"; }
634
635  if ((commentsDisplay_value = gup("commentsDisplay")) === "") {
636    commentsDisplay_value = oldCommentsDisplay_value === "" ? commentsDisplay_default : oldCommentsDisplay_value;
637  }
638  if (commentsDisplay_value == "h") { commentsDisplay_value = "hidden"; }
639  if (commentsDisplay_value == "i") { commentsDisplay_value = "inline"; }
640  if (commentsDisplay_value == "n") { commentsDisplay_value = "newline"; }
641  document.board.commentsDisplay.value = commentsDisplay_value;
642  if (!((commentsDisplay_value == "hidden") || (commentsDisplay_value == "inline") ||
643        (commentsDisplay_value == "newline")) ) {
644    alert("error: comment display must be either 'hidden', 'inline', 'newline' or their initials");
645    document.board.commentsDisplay.value = commentsDisplay_value = commentsDisplay_default;
646  }
647
648  if ((fontHeaderColorHex_value = gup("fontHeaderColorHex")) === "") {
649    if ((fontHeaderColorHex_value = sex2hex(gup("fontHeaderColorSex"), 'header font color')) === "") {
650      fontHeaderColorHex_value = fontHeaderColorHex_default;
651    }
652  }
653  document.board.fontHeaderColorHex.color.fromString(fontHeaderColorHex_value);
654  validate_color(document.board.fontHeaderColorHex, 'header font color', fontHeaderColorHex_default);
655
656  if ((fontMovesColorHex_value = gup("fontMovesColorHex")) === "") {
657    if ((fontMovesColorHex_value = sex2hex(gup("fontMovesColorSex"), 'moves font color')) === "") {
658      fontMovesColorHex_value = fontMovesColorHex_default;
659    }
660  }
661  document.board.fontMovesColorHex.color.fromString(fontMovesColorHex_value);
662  validate_color(document.board.fontMovesColorHex, 'moves font color', fontMovesColorHex_default);
663
664  if ((fontCommentsColorHex_value = gup("fontCommentsColorHex")) === "") {
665    if ((fontCommentsColorHex_value = sex2hex(gup("fontCommentsColorSex"), 'comments font color')) === "") {
666      fontCommentsColorHex_value = fontCommentsColorHex_default;
667    }
668  }
669  document.board.fontCommentsColorHex.color.fromString(fontCommentsColorHex_value);
670  validate_color(document.board.fontCommentsColorHex, 'comments font color', fontCommentsColorHex_default);
671
672  if ((fontVariationsColorHex_value = gup("fontVariationsColorHex")) === "") {
673    var fontVariationsColorSex = gup("fontVariationsColorSex");
674    if ((fontVariationsColorSex == "comments") || (fontVariationsColorSex == "c")) {
675      fontVariationsColorHex_value = "comments";
676    } else {
677      if ((fontVariationsColorHex_value = sex2hex(fontVariationsColorSex, 'font variations color')) === "") {
678        fontVariationsColorHex_value = fontVariationsColorHex_default;
679      }
680    }
681  }
682  if (fontVariationsColorHex_value == "c") {
683    fontVariationsColorHex_value = "comments";
684  }
685  if (fontVariationsColorHex_value == "comments") {
686    document.board.fontVariationsColorHex.value = fontVariationsColorHex_value;
687  } else {
688    document.board.fontVariationsColorHex.color.fromString(fontVariationsColorHex_value);
689  }
690
691  if ((highlightMoveColorHex_value = gup("highlightMoveColorHex")) === "") {
692    var highlightMoveColorSex = gup("highlightMoveColorSex");
693    if ((highlightMoveColorSex == "background") || (highlightMoveColorSex == "b")) {
694      highlightMoveColorHex_value = "background";
695    } else {
696      if ((highlightMoveColorHex_value = sex2hex(highlightMoveColorSex, 'move highlight color')) === "") {
697        highlightMoveColorHex_value = highlightMoveColorHex_default;
698      }
699    }
700  }
701  if (highlightMoveColorHex_value == "b") { highlightMoveColorHex_value = "background"; }
702  if (highlightMoveColorHex_value == "background") {
703    document.board.highlightMoveColorHex.value = highlightMoveColorHex_value;
704  } else {
705    document.board.highlightMoveColorHex.color.fromString(highlightMoveColorHex_value);
706    validate_color(document.board.highlightMoveColorHex, 'move highlight color', highlightMoveColorHex_default);
707  }
708
709  if ((fontHeaderSize_value = percentFixFromUrl( gup("fontHeaderSize") )) === "") { fontHeaderSize_value = fontHeaderSize_default; }
710  document.board.fontHeaderSize.value = fontHeaderSize_value;
711  validate_number_percentage(document.board.fontHeaderSize, 'header font size', fontHeaderSize_default);
712
713  if ((fontMovesSize_value = percentFixFromUrl( gup("fontMovesSize") )) === "") { fontMovesSize_value = fontMovesSize_default; }
714  document.board.fontMovesSize.value = fontMovesSize_value;
715  validate_number_percentage(document.board.fontMovesSize, 'moves font size', fontMovesSize_default);
716
717  if ((fontCommentsSize_value = percentFixFromUrl( gup("fontCommentsSize") )) === "") { fontCommentsSize_value = fontCommentsSize_default; }
718  if (fontCommentsSize_value == "m") { fontCommentsSize_value = "moves"; }
719  document.board.fontCommentsSize.value = fontCommentsSize_value;
720  validate_fontCommentsSize();
721
722  if ((fontVariationsSize_value = percentFixFromUrl( gup("fontVariationsSize") )) === "") { fontVariationsSize_value = fontVariationsSize_default; }
723  if (fontVariationsSize_value == "c") { fontVariationsSize_value = "comments"; }
724  document.board.fontVariationsSize.value = fontVariationsSize_value;
725  validate_fontVariationsSize();
726
727  if ((backgroundColorHex_value = gup("backgroundColorHex")) === "") {
728    var backgroundColorSex = gup("backgroundColorSex");
729    if ((backgroundColorSex == "transparent") || (backgroundColorSex == "t")) {
730      backgroundColorHex_value = "transparent";
731    } else {
732      if ((backgroundColorHex_value = sex2hex(backgroundColorSex, 'background color')) === "") {
733        backgroundColorHex_value = backgroundColorHex_default;
734      }
735    }
736  }
737  if (backgroundColorHex_value == "t") {
738    backgroundColorHex_value = "transparent";
739  }
740  if (backgroundColorHex_value == "transparent") {
741    document.board.backgroundColorHex.value = backgroundColorHex_value;
742  } else {
743    document.board.backgroundColorHex.color.fromString(backgroundColorHex_value);
744    validate_color(document.board.backgroundColorHex, 'background color', backgroundColorHex_default);
745  }
746
747  if ((boardShadowColorHex_value = gup("boardShadowColorHex")) === "") {
748    var boardShadowColorSex = gup("boardShadowColorSex");
749    if ((boardShadowColorSex == "transparent") || (boardShadowColorSex == "t")) {
750      boardShadowColorHex_value = "transparent";
751    } else if ((boardShadowColorSex == "border") || (boardShadowColorSex == "b")) {
752      boardShadowColorHex_value = "border";
753    } else {
754      if ((boardShadowColorHex_value = sex2hex(boardShadowColorSex, 'board shadow color')) === "") {
755        boardShadowColorHex_value = boardShadowColorHex_default;
756      }
757    }
758  }
759  if (boardShadowColorHex_value == "t") {
760    boardShadowColorHex_value = "transparent";
761  }
762  if (boardShadowColorHex_value == "b") {
763    boardShadowColorHex_value = "border";
764  }
765  if ((boardShadowColorHex_value == "transparent") || (boardShadowColorHex_value == "border")) {
766    document.board.boardShadowColorHex.value = boardShadowColorHex_value;
767  } else {
768    document.board.boardShadowColorHex.color.fromString(boardShadowColorHex_value);
769  }
770
771  if ((horizontalLayout_value = gup("horizontalLayout")) === "") { horizontalLayout_value = horizontalLayout_default; }
772  document.board.horizontalLayout.value = horizontalLayout_value == "t" ? "t" : "f";
773
774  if ((frameHeight_value = gup("frameHeight")) === "") { frameHeight_value = frameHeight_default; }
775  if (frameHeight_value == "b") { frameHeight_value = "board"; }
776  document.board.frameHeight.value = frameHeight_value;
777  validate_frameHeight();
778
779  if ((frameWidth_value = gup("frameWidth")) === "") { frameWidth_value = frameWidth_default; }
780  if (frameWidth_value == "p") { frameWidth_value = "page"; }
781  if (frameWidth_value == "b") { frameWidth_value = "board"; }
782  document.board.frameWidth.value = frameWidth_value;
783  validate_frameWidth();
784
785  if ((framePadding_value = gup("framePadding")) === "") { framePadding_value = framePadding_default; }
786  document.board.framePadding.value = framePadding_value;
787  validate_number(document.board.framePadding, 'frame padding', framePadding_default);
788
789  if ((previewBackgroundColorHex_value = gup("previewBackgroundColorHex")) === "") {
790    if ((previewBackgroundColorHex_value = sex2hex(gup("previewBackgroundColorSex"), 'preview background color')) === "") {
791      previewBackgroundColorHex_value = previewBackgroundColorHex_default;
792    }
793  }
794  document.board.previewBackgroundColorHex.color.fromString(previewBackgroundColorHex_value);
795  validate_color(document.board.previewBackgroundColorHex, 'preview background color', previewBackgroundColorHex_default);
796
797  if ((boardUrl_value = gup("boardUrl")) === "") { boardUrl_value = boardUrl_default; }
798  document.board.boardUrl.value = boardUrl_value;
799
800  if ((useTextarea_value = gup("useTextarea")) === "") { useTextarea_value = useTextarea_default; }
801  document.board.useTextarea.checked = ((useTextarea_value == "t") || (useTextarea_value == "true"));
802  validate_useTextarea();
803
804  generate_html_code();
805  update_controls();
806  update_help();
807}
808
809function reset_form() {
810  if (confirm("do you really want to reset the board generator to the default values?\nAll your settings including the PGN text might be lost!")) { set_defaults(); }
811}
812
813function update_help() {
814  var theObj;
815  if (theObj = document.getElementById("help_pgn_short")) {
816    theObj.style.display = document.board.useTextarea.checked ? "none" : "";
817  }
818  if (theObj = document.getElementById("help_pgn_compressed")) {
819    theObj.style.display = (document.board.useTextarea.checked || !document.board.encodePgn.checked) ? "none" : "";
820  }
821}
822
823function update_controls() {
824  update_disabled_controls();
825  update_suggested_iframe_dimensions();
826}
827
828function update_disabled_controls() {
829
830  document.board.highlightColorHex.disabled = (document.board.highlightMode.value == 'none');
831
832  document.board.controlBackgroundColorHex.disabled = document.board.controlTextColorHex.disabled = (document.board.buttonsDisplay.value != 'custom');
833
834  document.board.textMargin.disabled = ((document.board.movesDisplay.value == 'hidden') && (document.board.headerDisplay.value == 'hidden'));
835
836  document.board.fontHeaderSize.disabled = document.board.fontHeaderColorHex.disabled = (document.board.headerDisplay.value == 'hidden');
837
838  document.board.fontMovesSize.disabled = document.board.fontMovesColorHex.disabled = document.board.highlightMoveColorHex.disabled = document.getElementById('highlightMoveColor_background').disabled = ((document.board.movesDisplay.value == 'hidden') && (document.board.headerDisplay.value != 'live') && (document.board.headerDisplay.value != 'variations'));
839
840  document.board.commentsDisplay.disabled = document.getElementById('commentsDisplay_inline').disabled = document.getElementById('commentsDisplay_newline').disabled = document.getElementById('commentsDisplay_hidden').disabled = ((document.board.movesDisplay.value == 'hidden') && (document.board.headerDisplay.value != 'live') && (document.board.headerDisplay.value != 'variations'));
841
842  document.board.fontCommentsSize.disabled = document.getElementById('fontCommentsSize_moves').disabled = document.board.fontCommentsColorHex.disabled = (((document.board.movesDisplay.value == 'hidden') || (document.board.commentsDisplay.value == 'hidden')) && (document.board.headerDisplay.value != 'live') && (document.board.headerDisplay.value != 'variations'));
843
844  document.board.fontVariationsSize.disabled = document.getElementById('fontVariationsSize_comments').disabled = document.board.fontVariationsColorHex.disabled = document.getElementById('fontVariationsColor_comments').disabled = (((document.board.movesDisplay.value == 'hidden') && (document.board.headerDisplay.value != 'live') && (document.board.headerDisplay.value != 'variations')) || (document.board.commentsDisplay.value == 'hidden') || (!document.board.useTextarea.checked));
845
846  document.board.encodePgn.disabled = document.getElementById('encodePgn_enabled').disabled = document.board.useTextarea.checked;
847
848}
849
850function update_suggested_iframe_dimensions() {
851
852  var boardWidth = 8 * document.board.squareSize.value + 6;
853  var estimated_boardHeight = boardWidth;
854
855  var multiGamesRegexp = /\s*\[\s*\w+\s*"[^"]*"\s*\]\s*[^\s\[\]]+[\s\S]*\[\s*\w+\s*"[^"]*"\s*\]\s*/m;
856  var selectDropdownShown = multiGamesRegexp.test(pgnTextFixFromInput(document.getElementById('pgnText').value));
857
858  if (document.board.buttonsDisplay.value != 'hidden') {
859    if (document.board.buttonsDisplay.value == "standard") {
860      // in this case control padding grows with squareSize
861      // while the size of the controls cant be predicted, so a safe number is set
862      estimated_boardHeight += selectDropdownShown ?
863                               2 * (25 + parseInt(document.board.squareSize.value, 10) / 2) :
864                               25 + parseInt(document.board.squareSize.value, 10) / 2;
865    } else {
866      // in this case both control size and control padding grow with squareSize
867      estimated_boardHeight += selectDropdownShown ?
868                               2 * (5 + 1.1 * parseInt(document.board.squareSize.value, 10)) :
869                               5 + 1.1 * parseInt(document.board.squareSize.value, 10);
870    }
871  }
872  estimated_boardHeight = Math.floor(estimated_boardHeight);
873
874  min_frameWidth = boardWidth + 2 * parseInt(document.board.framePadding.value, 10);
875  min_frameHeight = estimated_boardHeight + 2 * parseInt(document.board.framePadding.value, 10);
876
877  if (document.board.horizontalLayout.value == "t") {
878    suggested_frameHeight = "board";
879    suggested_frameWidth = "page";
880    document.getElementById('frameHeight_helpText').innerHTML = "a number or <a id='frameHeight_board' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameHeight.value = \"board\"; update_controls(); } return false;'>board</a>; min " + min_frameHeight + "; when <a id='frameHeight_blank' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameHeight.value = \"\"; update_controls(); } return false;'>blank</a>, assigned to " + suggested_frameHeight;
881    document.getElementById('frameWidth_helpText').innerHTML = "a number or <a id='frameWidth_page' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameWidth.value = \"page\"; update_controls(); } return false;'>page</a>; min " + min_frameWidth + "; when <a id='frameWidth_blank' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameWidth.value = \"\"; update_controls(); } return false;'>blank</a>, assigned to " + suggested_frameWidth + "; board width is " + boardWidth;
882  } else {
883    suggested_frameWidth = boardWidth;
884    suggested_frameHeight = estimated_boardHeight;
885    if (document.board.headerDisplay.value != 'hidden') {
886      suggested_frameHeight += Math.max(100, Math.round(0.2 * boardWidth));
887    }
888    if (document.board.movesDisplay.value != 'hidden') {
889      suggested_frameHeight += Math.max(300, Math.round(0.8 * boardWidth));
890    }
891    if ((document.board.headerDisplay.value != 'hidden') || (document.board.movesDisplay.value != 'hidden')) {
892      suggested_frameWidth = Math.max(400, Math.round(1.5 * boardWidth));
893    }
894    suggested_frameWidth += 2 * parseInt(document.board.framePadding.value, 10);
895    suggested_frameHeight += 2 * parseInt(document.board.framePadding.value, 10);
896    document.getElementById('frameHeight_helpText').innerHTML = "a number; min " + min_frameHeight + "; when <a id='frameHeight_blank' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameHeight.value = \"\"; update_controls(); } return false;'>blank</a>, assigned to " + suggested_frameHeight;
897    document.getElementById('frameWidth_helpText').innerHTML = "a number or <a id='frameWidth_board' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameWidth.value = \"board\"; update_controls(); } return false;'>board</a> or <a id='frameWidth_page' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameWidth.value = \"page\"; update_controls(); } return false;'>page</a>; min " + min_frameWidth + "; when <a id='frameWidth_blank' class='helplink' href='' onClick='if (!this.disabled) { document.board.frameWidth.value = \"\"; update_controls(); } return false;'>blank</a>, assigned to " + suggested_frameWidth + "; board width is " + boardWidth;
898  }
899
900  if (theObj = document.getElementById('frameWidth')) {
901    if (theObj.value !== "") {
902      if (!theObj.value.match('/^[^0-9]$/')) {
903        if (theObj.value < min_frameWidth) {
904          alert('error: iFrame width too small');
905          theObj.value = "";
906        }
907      } else { alert('error: invalid iFrame width value'); }
908    }
909  }
910
911  if (theObj = document.getElementById('frameHeight')) {
912    if (theObj.value !== "") {
913      if (!theObj.value.match('/^[^0-9]$/')) {
914        if (theObj.value < min_frameHeight) {
915          alert('error: iFrame height too small');
916          theObj.value = "";
917        }
918      } else { alert('error: invalid iFrame height value'); }
919    }
920  }
921
922}
923
924function update_pgnTextLength() {
925 document.getElementById('pgnTextLength').innerHTML = "&nbsp;&nbsp;&nbsp;" + document.getElementById('pgnText').value.replace(/\r\n/g,'\n').length + "p";
926}
927
928function calculate_html_code() {
929
930  // this must be the firts item
931  boardUrl_value = document.board.boardUrl.value;
932  iframeUrl = boardUrl_value + "?";
933
934  autoplayMode_value = document.board.autoplayMode.value;
935  delay_value = parseInt(document.board.delay.value, 10);
936  iframeUrl += "&am=" + autoplayMode_value.charAt(0) + "&d=" + delay_value;
937
938  initialGame_value = document.board.initialGame.value;
939  if (initialGame_value != "first") { iframeUrl += "&ig=" + initialGame_value.charAt(0); }
940
941  initialVariation_value = document.board.initialVariation.value;
942  if (!isNaN(parseInt(initialVariation_value, 10)) && parseInt(initialVariation_value, 10) > 0) { iframeUrl += "&iv=" + initialVariation_value; }
943
944  initialHalfmove_value = document.board.initialHalfmove.value;
945  if (initialHalfmove_value != "start") {
946    iframeUrl += "&ih=" + (isNaN(parseInt(initialHalfmove_value, 10)) ?
947                          initialHalfmove_value.charAt(0) :
948                          initialHalfmove_value);
949  }
950
951  pieceFont_value = document.board.pieceFont.value;
952  squareSize_value = parseInt(document.board.squareSize.value, 10);
953  if (document.board.pieceSize.value == "default") {
954    pieceSize_value = document.board.pieceSize.value;
955    iframeUrl += "&ss=" + squareSize_value + "&ps=" + pieceSize_value.charAt(0) + "&pf=" + pieceFont_value.charAt(0);
956  } else {
957    pieceSize_value = parseInt(document.board.pieceSize.value, 10);
958    if (pieceSize_value > squareSize_value) { alert("error: the piece size (" + pieceSize_value + ") can not be bigger than the square size (" + squareSize_value + ")"); }
959    iframeUrl += "&ss=" + squareSize_value + "&ps=" + pieceSize_value + "&pf=" + pieceFont_value.charAt(0);
960  }
961
962  lightColorHex_value = document.board.lightColorHex.value;
963  iframeUrl += "&lcs=" + hex2sex(lightColorHex_value);
964  darkColorHex_value = document.board.darkColorHex.value;
965  iframeUrl += "&dcs=" + hex2sex(darkColorHex_value);
966  boardBorderColorHex_value = document.board.boardBorderColorHex.value;
967  iframeUrl += "&bbcs=" + hex2sex(boardBorderColorHex_value);
968  boardShadowColorHex_value = document.board.boardShadowColorHex.value;
969  if (boardShadowColorHex_value != "transparent") {
970    if (boardShadowColorHex_value == "border") { iframeUrl += "&bscs=b"; }
971    else { iframeUrl += "&bscs=" + hex2sex(boardShadowColorHex_value); }
972  }
973
974  highlightMode_value = document.board.highlightMode.value;
975  iframeUrl += "&hm=" + highlightMode_value.charAt(0);
976  highlightColorHex_value = document.board.highlightColorHex.value;
977  iframeUrl += "&hcs=" + hex2sex(highlightColorHex_value);
978
979  buttonsDisplay_value = document.board.buttonsDisplay.value;
980  iframeUrl += "&bd=" + buttonsDisplay_value.charAt(0);
981
982  if ((document.board.buttonsDisplay.value != "hidden") && (document.board.controlBackgroundColorHex.value != "default")) {
983    controlBackgroundColorHex_value = document.board.controlBackgroundColorHex.value;
984    iframeUrl += "&cbcs=" + hex2sex(controlBackgroundColorHex_value);
985    controlTextColorHex_value = document.board.controlTextColorHex.value;
986    iframeUrl += "&ctcs=" + hex2sex(controlTextColorHex_value);
987  }
988
989  headerDisplay_value = document.board.headerDisplay.value;
990  iframeUrl += "&hd=" + headerDisplay_value.charAt(0);
991  movesDisplay_value = document.board.movesDisplay.value;
992  iframeUrl += "&md=" + movesDisplay_value.charAt(0);
993
994  if ((document.board.headerDisplay.value != "hidden") || (document.board.movesDisplay.value != "hidden")) {
995    textMargin_value = parseInt(document.board.textMargin.value, 10);
996    iframeUrl += "&tm=" + textMargin_value;
997  }
998
999  if (document.board.headerDisplay.value != "hidden") {
1000
1001    fontHeaderColorHex_value = document.board.fontHeaderColorHex.value;
1002    iframeUrl += "&fhcs=" + hex2sex(fontHeaderColorHex_value);
1003
1004    fontHeaderSize_value = document.board.fontHeaderSize.value;
1005    iframeUrl += "&fhs=" + percentFixForUrl( fontHeaderSize_value );
1006
1007  }
1008
1009  if ((document.board.movesDisplay.value != "hidden") || (document.board.headerDisplay.value == "live") || (document.board.headerDisplay.value == "variations")) {
1010
1011    fontMovesColorHex_value = document.board.fontMovesColorHex.value;
1012    iframeUrl += "&fmcs=" + hex2sex(fontMovesColorHex_value);
1013    fontCommentsColorHex_value = document.board.fontCommentsColorHex.value;
1014    iframeUrl += "&fccs=" + hex2sex(fontCommentsColorHex_value);
1015    fontVariationsColorHex_value = document.board.fontVariationsColorHex.value;
1016    if (fontVariationsColorHex_value != "comments") {
1017      iframeUrl += "&fvcs=" + hex2sex(fontVariationsColorHex_value);
1018    }
1019    highlightMoveColorHex_value = document.board.highlightMoveColorHex.value;
1020    if (highlightMoveColorHex_value == "background" ) { iframeUrl += "&hmcs=b"; }
1021    else { iframeUrl += "&hmcs=" + hex2sex(highlightMoveColorHex_value); }
1022
1023    fontMovesSize_value = document.board.fontMovesSize.value;
1024    iframeUrl += "&fms=" + percentFixForUrl( fontMovesSize_value );
1025    fontCommentsSize_value = document.board.fontCommentsSize.value;
1026    if (fontCommentsSize_value == "moves") { iframeUrl += "&fcs=m"; }
1027    else { iframeUrl += "&fcs=" + percentFixForUrl( fontCommentsSize_value ); }
1028    fontVariationsSize_value = document.board.fontVariationsSize.value;
1029    if (fontVariationsSize_value != "comments") {
1030      iframeUrl += "&fvs=" + percentFixForUrl( fontVariationsSize_value );
1031    }
1032
1033    commentsDisplay_value = document.board.commentsDisplay.value;
1034    iframeUrl += "&cd=" + commentsDisplay_value.charAt(0);
1035
1036  }
1037
1038  backgroundColorHex_value = document.board.backgroundColorHex.value;
1039  if (backgroundColorHex_value == "transparent") {
1040     iframeUrl += "&bcs=" + backgroundColorHex_value.charAt(0);
1041  } else {
1042     iframeUrl += "&bcs=" + hex2sex(backgroundColorHex_value);
1043  }
1044
1045  // this does not go in the iframe
1046  previewBackgroundColorHex_value = document.board.previewBackgroundColorHex.value;
1047
1048  framePadding_value = parseInt(document.board.framePadding.value, 10);
1049  iframeUrl += "&fp=" + framePadding_value;
1050
1051  horizontalLayout_value = document.board.horizontalLayout.value;
1052  iframeUrl += "&hl=" + horizontalLayout_value;
1053
1054  update_suggested_iframe_dimensions();
1055
1056  if ((frameHeight_value = document.board.frameHeight.value) === "") { frameHeight_value = suggested_frameHeight; }
1057  if ((frameWidth_value = document.board.frameWidth.value) === "") { frameWidth_value = suggested_frameWidth; }
1058
1059  if (frameHeight_value == "board") {
1060    iframeUrl += "&fh=" + frameHeight_value.charAt(0);
1061  } else {
1062    iframeUrl += "&fh=" + frameHeight_value;
1063  }
1064  if ((frameWidth_value == "page") || (frameWidth_value == "board")) {
1065    iframeUrl += "&fw=" + frameWidth_value.charAt(0);
1066  } else {
1067    iframeUrl += "&fw=" + frameWidth_value;
1068  }
1069
1070  pgnText_value = pgnTextFixFromInput(document.getElementById('pgnText').value);
1071  if (document.board.useTextarea.checked) {
1072    pgnId = "pgn4web_" + printHex(crc32(pgnText_value));
1073    iframeUrl += "&pi=" + pgnId;
1074  } else {
1075    if ((document.board.encodePgn.checked) && (pgnText_value != previousPgnTextToEncode)) {
1076      previousPgnTextToEncode = pgnText_value;
1077      pgnTextEncoded = EncodePGN(pgnText_value.replace(/\r\n/g,'\n'));
1078    }
1079    if (document.board.encodePgn.checked) { iframeUrl += "&pe=" + pgnTextEncoded; }
1080    else { iframeUrl += "&pt=" + pgnTextFixForUrl(pgnText_value.replace(/\r\n/g,'\n')); }
1081  }
1082
1083  // every parameter had an &xxx= format,now we need to remove the first &
1084  iframeUrl = iframeUrl.replace(/\?&/,"?");
1085}
1086
1087function pgnTextFixFromInput( text ) {
1088
1089  text = fixCommonPgnMistakes(text);
1090  if (document.board.useTextarea.checked) {
1091    text = simpleHtmlentities(text);
1092  } else {
1093    text = text.replace(/[\u0100-\uFFFF]/g,"*"); // replace all chars with code greather than 255 with *
1094  }
1095  return text;
1096}
1097
1098function pgnTextFixForUrl( text ) {
1099
1100  // escaped lines starting with % are removed till end of line
1101  text = text.replace(/^%.*$/mg,"");
1102  // we need everything on a single line, please note this breaks the ";" comment detection leading to threat everything after a ";" as comment
1103  text = text.replace(/\s/g," ");
1104
1105  // some chars dont work well in URLs
1106  text = text.replace(/%/g,"%25");
1107  text = text.replace(/#/g,"%23");
1108  text = text.replace(/&/g,"%26");
1109  text = text.replace(/\?/g,"%3F");
1110
1111  // the "'" char is used in the iframe statement
1112  text = text.replace(/'/g,"%27");
1113
1114  return text;
1115}
1116
1117function percentFixForUrl( text ) {
1118  text += ''; // makes sure text is a string
1119  return text.replace(/%$/,'p');
1120}
1121
1122function percentFixFromUrl( text ) {
1123  text += ''; // makes sure text is a string
1124  return text.replace(/pct$/,'%').replace(/p$/,'%'); // 100pct and 100p both mean 100%
1125}
1126
1127var html_code_string = "";
1128function generate_html_code() {
1129  var outerFrameWidth, outerFrameHeight;
1130
1131  // cleans the short url stuff
1132  shorturl_link_clean();
1133  shorturl_window_close();
1134  html_code_string = "";
1135
1136  calculate_html_code();
1137
1138  switch (frameWidth_value) {
1139    case "board":
1140      outerFrameWidth = min_frameWidth;
1141      break;
1142    case "page":
1143      outerFrameWidth = "100%";
1144      break;
1145    default:
1146      outerFrameWidth = frameWidth_value;
1147      break;
1148  }
1149
1150  switch (frameHeight_value) {
1151    case "board":
1152      outerFrameHeight = min_frameHeight;
1153      break;
1154    default:
1155      outerFrameHeight = frameHeight_value;
1156      break;
1157  }
1158
1159  if (document.getElementById('useTextarea').checked) {
1160    html_code_string += "<textarea id='" + pgnId + "' style='display: none;'>\n\n" + pgnText_value + "\n\n</textarea>\n\n";
1161  }
1162  html_code_string += "<iframe height='" + outerFrameHeight + "' width='" + outerFrameWidth + "' frameborder='0' scrolling='no' marginheight='0' marginwidth='0'";
1163  if (document.getElementById('backgroundColorHex').value == 'transparent') {
1164    html_code_string += " allowtransparency='true'";
1165  }
1166  html_code_string += " src='" + iframeUrl.replace(/&/g, '&amp;') + "'>your web browser and/or your host do not support iframes as required to display the chessboard</iframe>";
1167
1168  document.getElementById('html_code').value = html_code_string;
1169
1170  boardUrl_value = document.board.boardUrl.value;
1171  var thisBookmarkUrl = iframeUrl;
1172  thisBookmarkUrl = thisBookmarkUrl.replace(boardUrl_value, pgn4web_generator_url);
1173  thisBookmarkUrl = thisBookmarkUrl.replace(/&(pe|pt)=.*(&|$)/,"");
1174
1175  if (document.getElementById('encodePgn').checked) { encodePgn_value = "t"; }
1176  else { encodePgn_value = "f"; }
1177  if (encodePgn_value != encodePgn_default) { thisBookmarkUrl += "&ep=" + encodePgn_value; }
1178
1179  if (boardUrl_value != boardUrl_default) { thisBookmarkUrl += "&bu=" + boardUrl_value; }
1180
1181  if (document.getElementById('useTextarea').checked) { useTextarea_value = "t"; }
1182  else { useTextarea_value = "f"; }
1183  if (useTextarea_value != useTextarea_default) { thisBookmarkUrl += "&ut=" + useTextarea_value; }
1184
1185  previewBackgroundColorHex_value = document.board.previewBackgroundColorHex.value;
1186  if (previewBackgroundColorHex_value != previewBackgroundColorHex_default) {
1187    thisBookmarkUrl += "&pbcs=" + hex2sex(previewBackgroundColorHex_value);
1188  }
1189
1190  if ((gup("extendedOptions") == "true") || (gup("extendedOptions") == "t")) {
1191    thisBookmarkUrl += "&eo=t";
1192  }
1193
1194  document.getElementById('thisConfigBookmark').href = thisBookmarkUrl;
1195  var thisBookmarkCrc32 = printHex(crc32(thisBookmarkUrl));
1196  document.getElementById('thisConfigBookmark').title = "right-click, copy and save pgn4web board generator custom template link #" + thisBookmarkCrc32;
1197  document.getElementById('bookmarkCrc32').innerHTML = "#" + thisBookmarkCrc32;
1198
1199  document.getElementById('preview').innerHTML = "<table border='0' bgcolor='#" + previewBackgroundColorHex_value + "' width='100%' cellpadding='25'><tr><td align='center' valign='middle'> " + html_code_string + "</td></tr></table>";
1200
1201  var html_code_status_string = "<table width='100%' cellspacing='0' cellpadding='0'><tr><td align='left' valign='top'>";
1202  if (iframeUrl.length <= iframeUrl_max) {
1203    html_code_status_string += "<label class='helptext' for='html_code'>HTML code ready to cut and paste in your web page or blog</label>";
1204  } else {
1205    html_code_status_string += "<a class='helptext' style='color: red; font-weight: bold; text-decoration: none;' href='#pgn_form' onclick='if (confirm(\"board-generator error\\n\\nthe generated iFrame URL is \" + iframeUrl.length + \" chars long and exceeds the " + iframeUrl_max + " chars max URL length limit as enforced by some web browsers and by some web servers\\n\\neven if the chessboard looks properly in the preview window below, some users will not view the chessboard as intended\\n\\nthe URL length needs to be reduced within the allowed \" + iframeUrl_max + \" chars limit by shortening the input PGN data in the green textbox below and generating an updated iFrame URL\\n\\nclick OK to reach the green textbox with the PGN data to be shortened\")) { document.location.hash = \"#pgn_form\"; }; return false;' title='click here for more info'>error: " + iframeUrl.length + " chars URL exceeds " + iframeUrl_max + " chars limit, please shorten the PGN data; click here for more info</a>";
1206  }
1207  html_code_status_string += "</td><td align=right valign=top>";
1208  html_code_status_string += "<span class='helptext'>&nbsp;&nbsp;&nbsp;" + document.getElementById('pgnText').value.replace(/\r\n/g,'\n').length + "p";
1209  if (document.board.encodePgn.checked) { html_code_status_string += "&nbsp;" + pgnTextEncoded.length + "e"; }
1210  html_code_status_string += "&nbsp;" + iframeUrl.length + "u</span>";
1211
1212  html_code_status_string += "</td></tr></table>";
1213  document.getElementById('html_code_status').innerHTML = html_code_status_string;
1214
1215  if (firstLoad) { firstLoad = false; return; }
1216  if (iframeUrl.length <= iframeUrl_max) { location.href='#game_preview'; return; }
1217  location.href='#generate'; return;
1218}
1219
1220function validate_color(object, name, def) {
1221  if (object.value.match(/^[0-9A-Fa-f]{6}$/)) {
1222    return true;
1223  } else {
1224    alert('error: the ' + name + ' must be a six digits hexadecimal color code, like FF0000');
1225    object.color.fromString(def);
1226    return false;
1227  }
1228}
1229
1230function validate_highlightMoveColorHex() {
1231  object = document.getElementById('highlightMoveColorHex');
1232  if (object.value == 'background') { return true; }
1233  if (object.value.match(/^[0-9A-Fa-f]{6}$/)) {
1234    return true;
1235  } else {
1236    alert('error: the move highlight color must be \'background\' or a six digits hexadecimal color code, like FF0000');
1237    if (highlightMoveColorHex_default == 'background') { object.value = highlightMoveColorHex_default; }
1238    else { object.color.fromString(highlightMoveColorHex_default); }
1239    return false;
1240  }
1241}
1242
1243function validate_boardShadowColorHex() {
1244  object = document.getElementById('boardShadowColorHex');
1245  if (object.value == 'transparent') { return true; }
1246  if (object.value == 'border') { return true; }
1247  if (object.value.match(/^[0-9A-Fa-f]{6}$/)) {
1248    return true;
1249  } else {
1250    alert('error: the board shadow color must be \'transparent\' or \'border\' or a six digits hexadecimal color code, like FF0000');
1251    if ((boardShadowColorHex_default == 'transparent') || (boardShadowColorHex_default == 'border')) {
1252      object.value = boardShadowColorHex_default;
1253    } else { object.color.fromString(boardShadowColorHex_default); }
1254    return false;
1255  }
1256}
1257
1258function validate_fontVariationsColorHex() {
1259  object = document.getElementById('fontVariationsColorHex');
1260  if (object.value == 'comments') { return true; }
1261  if (object.value.match(/^[0-9A-Fa-f]{6}$/)) {
1262    return true;
1263  } else {
1264    alert('error: the font variations color must be \'comments\' or a six digits hexadecimal color code, like FF0000');
1265    if (fontVariationsColorHex_default == 'comments') {
1266      object.value = fontVariationsColorHex_default;
1267    } else { object.color.fromString(fontVariationsColorHex_default); }
1268    return false;
1269  }
1270}
1271
1272function validate_backgroundColorHex() {
1273  object = document.getElementById('backgroundColorHex');
1274  if (object.value == 'transparent') { return true; }
1275  if (object.value.match(/^[0-9A-Fa-f]{6}$/)) {
1276    return true;
1277  } else {
1278    alert('error: the move highlight color must be \'transparent\' or a six digits hexadecimal color code, like FF0000');
1279    if (backgroundColorHex_default == 'transparent') { object.value = backgroundColorHex_default; }
1280    else { object.color.fromString(backgroundColorHex_default); }
1281    return false;
1282  }
1283}
1284
1285function validate_number(object, name, def) {
1286  var vv = object.value.match(/^([0-9]+)(px$|$)/);
1287  if (vv) {
1288    object.value = vv[1];
1289    return true;
1290  } else {
1291    alert('error: the ' + name + ' must be a non negative integer');
1292    object.value = def;
1293    return false;
1294  }
1295}
1296
1297function validate_number_blank(object, name, def) {
1298  if (object.value === "") { return true; }
1299  var vv = object.value.match(/^([0-9]+)(px$|$)/);
1300  if (vv) {
1301    object.value = vv[1];
1302    return true;
1303  } else {
1304    alert('error: the ' + name + ' must be blank or a non negative integer');
1305    object.value = def;
1306    return false;
1307  }
1308}
1309
1310function validate_number_percentage(object, name, def) {
1311  var vv = object.value.match(/^([0-9]+)(%$|p$|pct$|px$|$)/);
1312  if (vv) {
1313    if (vv[2] == "px") { object.value = vv[1]; }
1314    return true;
1315  } else {
1316    alert('error: the ' + name + ' must be a non negative integer or percentage');
1317    object.value = def;
1318    return false;
1319  }
1320}
1321
1322function validate_number_percentage_blank(object, name, def) {
1323  if (object.value === "") { return true; }
1324  var vv = object.value.match(/^([0-9]+)(%$|p$|pct$|px$|$)/);
1325  if (vv) {
1326    if (vv[2] == "px") { object.value = vv[1]; }
1327    return true;
1328  } else {
1329    alert('error: the ' + name + ' must be blank or a non negative integer or percentage');
1330    object.value = def;
1331    return false;
1332  }
1333}
1334
1335function validate_fontCommentsSize() {
1336  var object = document.getElementById('fontCommentsSize');
1337  if (object.value == "moves") { return true; }
1338  var vv = object.value.match(/^([0-9]+)(%$|p$|pct$|px$|$)/);
1339  if (vv) {
1340    if (vv[2] == "px") { object.value = vv[1]; }
1341    return true;
1342  } else {
1343    alert('error: the comments font size must be \'moves\' or a non integer number or (deprecated) a percentage');
1344    object.value = fontCommentsSize_default;
1345    return false;
1346  }
1347}
1348
1349function validate_fontVariationsSize() {
1350  var object = document.getElementById('fontVariationsSize');
1351  if (object.value == "comments") { return true; }
1352  var vv = object.value.match(/^([0-9]+)(%$|p$|pct$|px$|$)/);
1353  if (vv) {
1354    if (vv[2] == "px") { object.value = vv[1]; }
1355    return true;
1356  } else {
1357    alert('error: the variations font size must be \'comments\' or a non integer number or (deprecated) a percentage');
1358    object.value = fontVariationsSize_default;
1359    return false;
1360  }
1361}
1362
1363function validate_frameWidth() {
1364  var object = document.getElementById('frameWidth');
1365  if (object.value === '') { return true; }
1366  if ((object.value == 'board') && (document.getElementById('horizontalLayout').value == "f")) { return true; }
1367  if (object.value == 'page') { return true; }
1368  var vv = object.value.match(/^([0-9]+)(px$|$)/);
1369  if (vv) {
1370    object.value = vv[1];
1371    return true;
1372  } else {
1373    if (document.getElementById('horizontalLayout').value == "t") {
1374      alert('error: in the horizontal layout the iFrame width must be a non negative integer or \'page\'');
1375    } else {
1376      alert('error: in the vertical layout the iFrame width must be a non negative integer, \'board\' or \'page\'');
1377    }
1378    object.value = "";
1379    return false;
1380  }
1381}
1382
1383function validate_frameHeight() {
1384  var object = document.getElementById('frameHeight');
1385  if (object.value === '') { return true; }
1386  if ((object.value == 'board') && (document.getElementById('horizontalLayout').value == "t")) { return true; }
1387  var vv = object.value.match(/^([0-9]+)(px$|$)/);
1388  if (vv) {
1389    object.value = vv[1];
1390    return true;
1391  } else {
1392    if (document.getElementById('horizontalLayout').value == "t") {
1393      alert('error: in the horizontal layout the iFrame height must be a non negative integer or \'board\'');
1394    } else {
1395      alert('error: in the vertical layout the iFrame height must be a non negative integer');
1396    }
1397    object.value = "";
1398    return false;
1399  }
1400}
1401
1402function validate_ss_ps_hm() {
1403  var retVal = true, maxPieceSize;
1404  var minSquareSize = (document.getElementById('highlightMode').value == 'border') ? 22 : 20;
1405  if (document.getElementById('squareSize').value < minSquareSize) {
1406    alert('error: square size must be at least ' + minSquareSize +
1407          ', resetting to ' + minSquareSize +
1408          '\n' + '(squareSize=' + document.getElementById('squareSize').value +
1409          ' pieceSize=' + document.getElementById('pieceSize').value +
1410          ' highlightMode=' + document.getElementById('highlightMode').value + ')');
1411    document.getElementById('squareSize').value = minSquareSize;
1412    retVal = false;
1413  }
1414  if (document.getElementById('pieceSize').value != "default") {
1415    if (document.getElementById('highlightMode').value == "border") {
1416      maxPieceSize = document.getElementById('squareSize').value -
1417        2 * Math.floor(0.05 * document.getElementById('squareSize').value);
1418    } else {
1419      maxPieceSize = document.getElementById('squareSize').value;
1420    }
1421    if (document.getElementById('pieceSize').value > maxPieceSize) {
1422      alert('error: piece size must be no bigger than ' + maxPieceSize +
1423            ', resetting to default' +
1424            '\n' + '(squareSize=' + document.getElementById('squareSize').value +
1425            ' pieceSize=' + document.getElementById('pieceSize').value +
1426            ' highlightMode=' + document.getElementById('highlightMode').value + ')');
1427      document.getElementById('pieceSize').value = "default";
1428      retVal = false;
1429    }
1430  }
1431  return retVal;
1432}
1433
1434function validate_useTextarea() {
1435  if ((!document.board.useTextarea.checked) && (document.board.fontVariationsSize.value != "comments")) {
1436    alert("warning: when use text area is disabled, font variations size defaults to 'comments'");
1437    document.board.fontVariationsSize.value = "comments";
1438  }
1439  if ((!document.board.useTextarea.checked) && (document.board.fontVariationsColorHex.value != "comments")) {
1440    alert("warning: when use text area is disabled, font variations color defaults to 'comments'");
1441    document.board.fontVariationsColorHex.color.fromString("FFFFFF");
1442    document.board.fontVariationsColorHex.value = "comments";
1443  }
1444}
1445
1446function checkInitialHalfmove() {
1447  var retVal = false;
1448  initialHalfmove_value = document.board.initialHalfmove.value;
1449  switch (initialHalfmove_value) {
1450    case "":
1451    case "start":
1452    case "end":
1453    case "random":
1454    case "comment":
1455    case "variation":
1456      document.board.initialHalfmoveSelect.value = document.board.initialHalfmove.value;
1457      document.board.initialHalfmoveNumber.value = initialHalfmoveNumber_default;
1458      retVal = true;
1459      break;
1460    default:
1461      if (initialHalfmove_value.match(/^[+-]?[0-9]+$/)) {
1462        document.board.initialHalfmoveSelect.value = "number";
1463        document.board.initialHalfmoveNumber.value = initialHalfmove_value;
1464        retVal = true;
1465      } else {
1466        alert("error: initial halfmove (as URL parameter) must be either a number or 'start', 'end', 'random', 'comment', 'variation' or their initials");
1467        document.board.initialHalfmove.value = initialHalfmove_value = initialHalfmove_default;
1468        document.board.initialHalfmoveSelect.value = initialHalfmoveSelect_default;
1469        document.board.initialHalfmoveNumber.value = initialHalfmoveNumber_default;
1470      }
1471      break;
1472  }
1473  document.board.initialHalfmoveNumber.disabled = (document.board.initialHalfmoveSelect.value != "number");
1474  return retVal;
1475}
1476
1477function setInitialHalfmove() {
1478  if (document.board.initialHalfmoveSelect.value == "number") {
1479    document.board.initialHalfmoveNumber.disabled = false;
1480    if (document.board.initialHalfmoveNumber.value === "") { document.board.initialHalfmoveNumber.value = 0; }
1481    if (document.board.initialHalfmoveNumber.value.match(/^[+-]?[0-9]+$/)) {
1482      document.board.initialHalfmove.value = initialHalfmove_value = document.board.initialHalfmoveNumber.value;
1483    } else {
1484      alert("error: initial halfmove number must be an integer");
1485      document.board.initialHalfmove.value = initialHalfmove_value = document.board.initialHalfmoveNumber.value = initialHalfmoveNumber_default;
1486    }
1487  } else {
1488    document.board.initialHalfmoveNumber.disabled = true;
1489    document.board.initialHalfmove.value = initialHalfmove_value = document.board.initialHalfmoveSelect.value;
1490  }
1491}
1492
1493function add_option(selectObject, newText, newValue) {
1494  var newOpt = document.createElement('option');
1495  newOpt.text = newText;
1496  newOpt.value = newValue;
1497  try { selectObject.add(newOpt, null); }
1498  catch(e) { selectObject.add(newOpt); } // bugfix: IE specific
1499}
1500
1501// template patterns
1502var common_template = "?am=l&d=3000&fh=&fw=";
1503
1504// color template array (description, general settings, highlight square color, highlight border color);
1505var color_template = new Array();
1506color_template[0] = new Array("blue ", "&lcs=VdyD&dcs=LHCg&bbcs=LHCg&bd=c&cbcs=PYGy&ctcs=l4It&fhcs=$$$$&fmcs=$$$$&fccs=v71$&hmcs=M___&bcs=VdyD", "&hcs=QtmS", "&hcs=s8pI");
1507color_template[1] = new Array("brown", "&lcs=XItn&dcs=NpQK&bbcs=NpQK&bd=c&cbcs=__iz&ctcs=NpQK&fhcs=k03b&fmcs=k03b&fccs=DRYC&hmcs=__X$&bcs=____", "&hcs=MWVi", "&hcs=__X$");
1508color_template[2] = new Array("gray ", "&lcs=YeiP&dcs=Qcij&bbcs=D91v&bscs=Lb2$&bd=s&cbcs=YeiP&ctcs=$$$$&fhcs=$$$$&fmcs=$$$$&fccs=v71$&hmcs=Qcij&bcs=____", "&hcs=Udiz", "&hcs=s6gP");
1509color_template[3] = new Array("green", "&lcs=W_iH&dcs=MHW2&bbcs=MHW2&bd=c&cbcs=UtKy&ctcs=x7x7&fhcs=g3g3&fmcs=7x7x&fccs=v71$&hmcs=RKim&bcs=W_iH", "&hcs=RKim", "&hcs=waRy");
1510color_template[4] = new Array("pink ", "&lcs=Wtyk&dcs=OXJO&bbcs=OXJO&bd=c&cbcs=UJ2e&ctcs=nkYj&fhcs=nkYi&fmcs=nkYi&fccs=DoRa&hmcs=ZbNv&bcs=Wtyk", "&hcs=UIFV", "&hcs=ZbNv");
1511color_template[5] = new Array("wood ", "&lcs=_XNo&dcs=O8AB&bbcs=O8AB&bscs=b&bd=s&cbcs=YeiP&ctcs=$$$$&fhcs=$$$$&fmcs=$$$$&fccs=v71$&hmcs=_XNo&bcs=____", "&hcs=r4fT", "&hcs=r4fT");
1512
1513// size template array
1514var size_template = new Array();
1515size_template[0] = new Array("small ", "&ss=26&ps=d&pf=d&hm=s&tm=13&fhs=14&fms=14&fcs=m&fp=13");
1516size_template[1] = new Array("medium", "&ss=36&ps=d&pf=d&hm=s&tm=18&fhs=16&fms=16&fcs=m&fp=18");
1517size_template[2] = new Array("large ", "&ss=50&ps=d&pf=d&hm=b&tm=25&fhs=19&fms=19&fcs=m&fp=25");
1518
1519// layout template array
1520var layout_template = new Array();
1521layout_template[0] = new Array("vertical  ", "&hl=f&hd=c&md=f&cd=i");
1522layout_template[1] = new Array("horizontal", "&hl=t&hd=j&md=f&cd=i");
1523
1524function load_templates() {
1525
1526  var theObj = document.getElementById('templatesList');
1527
1528  for (var cc=0; cc<color_template.length; cc++) {
1529    for (var ss=0; ss<size_template.length; ss++) {
1530      for (var ll=0; ll<layout_template.length; ll++) {
1531        var template_text = "";
1532        template_text += color_template[cc][0] + " ";
1533        template_text += size_template[ss][0] + " ";
1534        template_text += layout_template[ll][0] + " ";
1535        template_text += "template";
1536        // replace spaces with &nbsp; (ascii code 160)
1537        template_text = template_text.replace(/ /g,String.fromCharCode(160));
1538        var template_value = common_template;
1539        template_value += layout_template[ll][1];
1540        template_value += size_template[ss][1];
1541        template_value += color_template[cc][1];
1542        template_value += template_value.match("&hm=b") ? color_template[cc][3] : color_template[cc][2];
1543        if (color_template[cc][0].match("(gray|wood)")) {
1544          template_value = template_value.replace(/hm=(s|b)/,"hm=n");
1545        }
1546        add_option(theObj, template_text, template_value);
1547      }
1548    }
1549  }
1550}
1551
1552function template_selected() {
1553  if (document.getElementById('templatesList').value == "heading") { return; }
1554
1555  var selectedIndex = document.getElementById('templatesList').value == "random" ?
1556                  3 + Math.floor((document.getElementById('templatesList').length - 3) * Math.random()) :
1557                  document.getElementById('templatesList').selectedIndex;
1558
1559  if (confirm("do you really want to load the selected board generator template?" +
1560              "\n\n" + document.getElementById('templatesList').options[selectedIndex].text +
1561              "\n\nAll your settings besides the PGN text might be lost!")) {
1562
1563   var newLocationSearch = document.getElementById('templatesList').options[selectedIndex].value;
1564
1565    if (( document.getElementById('useTextarea').checked && (useTextarea_default != "t")) ||
1566        (!document.getElementById('useTextarea').checked && (useTextarea_default != "f")) ) {
1567      newLocationSearch += "&ut=" + (document.board.useTextarea.checked ? "t" : "f");
1568    }
1569
1570    if (( document.getElementById('encodePgn').checked && (encodePgn_default != "t")) ||
1571        (!document.getElementById('encodePgn').checked && (encodePgn_default != "f")) ) {
1572      newLocationSearch += "&ep=" + (document.board.encodePgn.checked ? "t" : "f");
1573    }
1574
1575    if (document.board.boardUrl.value != boardUrl_default) {
1576      newLocationSearch += "&bu=" + document.board.boardUrl.value;
1577    }
1578
1579    if ((gup("extendedOptions") == "true") || (gup("extendedOptions") == "t")) {
1580      newLocationSearch += "&eo=t";
1581    }
1582
1583    pgnText_value = document.getElementById('pgnText').value;
1584    if ((document.board.encodePgn.checked) && (pgnText_value != previousPgnTextToEncode)) {
1585       previousPgnTextToEncode = pgnText_value;
1586       pgnTextEncoded = EncodePGN(pgnText_value);
1587    }
1588    newLocationSearch += document.board.encodePgn.checked ?
1589                         "&pe=" + pgnTextEncoded :
1590                         "&pt=" + pgnTextFixForUrl(pgnText_value);
1591    newLocationSearch = newLocationSearch.replace(/^&/,"\?");
1592
1593    shorturl_window_close();
1594    if (newLocationSearch != location.search) {
1595      location.href = location.pathname + newLocationSearch + "#game_preview";
1596    } else {
1597      location.reload(true);
1598      location.hash = "#game_preview";
1599    }
1600  }
1601  document.getElementById('templatesList').value = "heading";
1602}
1603
1604function oneClickPuzzleSetup() {
1605  if (confirm("the one click optimized puzzle setup will set\n \nmoves display to 'puzzle'\nheader display to 'variations'\nbuttons display to 'none'\nautoplay mode to 'none'\n \nproceed?")) {
1606    document.board.movesDisplay.value = movesDisplay_value = "puzzle";
1607    document.board.headerDisplay.value = headerDisplay_value = "variations";
1608    document.board.buttonsDisplay.value = buttonsDisplay_value = "hidden";
1609    document.board.autoplayMode.value = autoplayMode_value = "none";
1610  }
1611}
1612
1613var sexEncodingCharSet = "$0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
1614
1615function sex2hex(sex, name) {
1616  if (sex === "") { return ""; }
1617  if (!sex.match(/^[0-9a-zA-z_\$]{4}$/)) {
1618    alert('error: the ' + name + ' must be a 4 digits color code in the proprietary format, like _L$$');
1619    return "";
1620  }
1621  sex += "";
1622  var dec = 0;
1623  var cnt;
1624  for (cnt=0; cnt<sex.length; cnt++) {
1625    dec <<= 6;
1626    dec += sexEncodingCharSet.indexOf(sex.charAt(cnt));
1627  }
1628  var hex = dec.toString(16).toUpperCase() + "";
1629  while (hex.length < 6) { hex = "0" + hex; }
1630  return hex;
1631}
1632
1633function hex2sex(hex) {
1634  var sex = "";
1635  var dec = parseInt(hex,16);
1636  while (dec>0) {
1637    sex = sexEncodingCharSet.charAt(dec % 64) + sex;
1638    dec >>= 6;
1639  }
1640  while (sex.length < 4) { sex = sexEncodingCharSet.charAt(0) + sex; }
1641  return sex;
1642}
1643
1644var bugWin=null;
1645function bug_report() {
1646  var email = pgn4web_project_email;
1647  var subject = "pgn4web board generator bug report";
1648  var bug_info = "pgn4web board generator bug report\n\n-------- automatically generated debug info: start --------\n\ndate: " + (new Date()).toUTCString() + "\n\nURL: " + window.location + "\n\nuser agent: " + window.navigator.userAgent+ "\n\npgn4web version: " + pgn4web_version + "\n\niFrame HTML code:\n\n" + html_code_string + "\n\nPGN input:\n\n" + document.getElementById('pgnText').value + "\n\n-------- automatically generated debug info: end   --------\n\nPlease add below a description of the bug and attach a screenshot if possible.\n\n\n";
1649  var mailto_link = 'mailto:' + email + '?subject=' + subject + '&body=' + escape(bug_info);
1650
1651  if (bugWin && !bugWin.closed) { bugWin.close(); }
1652  bugWin = window.open("", "pgn4web_bug_report", "resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no");
1653  if (bugWin !== null) {
1654    bugWin.document.open("text/html", "replace");
1655    bugWin.document.write("<html>");
1656    bugWin.document.write("<head><title>pgn4web board generator bug report</title><link rel='icon' sizes='16x16' href='pawn.ico' /><style type='text/css'> html, body { font-family: sans-serif;  color: black; background: white; padding: 10px; } a {text-decoration: none; color: black; } </style></head>");
1657    bugWin.document.write("<body style='text-align: justify;'>");
1658    bugWin.document.write("<h1 style='margin-top:0px; padding-top:0px; text-align:right;'><span style='float:left; color:black;'>pgn4web board generator bug report</span><span style='width:49px; height:29px; background:url(pawns.png) -47px -15px; vertical-align:baseline; display:inline-block;'></span></h1><div style='height:1em;'></div>Please make sure that:<ul type='square'><li>you are using the same web browser where you noticed the bug in the pgn4web board generator</li><li>you opened this bug report window from the pgn4web board generator page configured with all the parameter that result in the bug condition</li></ul>Then please email ALL the the debug information below and possibly a screenshot to <i><a href=mailto:" + pgn4web_project_email + ">" + pgn4web_project_email + "</a></i> (if your email client is properly configured, you can try to <i><a href='" + mailto_link + "'>click here and automatically compose the email in your default client</a></i>)<p></p><br/>");
1659    bugWin.document.write("<div style='background: #F4F4F4; scrollbar-base-color: #F4F4F4; padding: 20px; overflow: auto;'><pre><code>" + simpleHtmlentities(bug_info) + "</code></pre></div>");
1660    bugWin.document.write("</body>");
1661    bugWin.document.write("<html>");
1662    bugWin.document.close();
1663    if (window.focus) { bugWin.focus(); }
1664  }
1665}
1666
1667function print_menu( item, level, title ) {
1668  var menu = '<div style="height:1em;">';
1669  if (item) { menu += '<a name=' + item + '>&nbsp;</a>'; }
1670  menu += '</div>';
1671  menu += '<table width=100% cellspacing=0 cellpadding=0><tr><td td valign=middle align=left>';
1672  if (title) { menu += '<h' + level + '>' + title + '</h' + level + '>'; }
1673  menu += '</td><td valign=top align=right>';
1674  menu += '<div style="font-size: 70%;">';
1675  menu += '<a href=#top>instructions</a>';
1676  menu += '<br>';
1677  menu += '&nbsp; &nbsp;<span style="color:gray">actions:</span>';
1678  menu += '&nbsp; &nbsp;<a href=#generate>copy output</a>';
1679  menu += '&nbsp; &nbsp;<a href=#game_preview>preview</a>';
1680  menu += '&nbsp; &nbsp;<a href="javascript:generate_html_code()">generate</a>';
1681  menu += '<br>';
1682  menu += '&nbsp; &nbsp;<span style="color:gray">config:</span>';
1683  menu += '&nbsp; &nbsp;<a href=#pgn_form>PGN</a>';
1684  menu += '&nbsp; &nbsp;<a href=#templates>templates</a>';
1685  menu += '&nbsp; &nbsp;<a href=#replay_options>replay</a>';
1686  menu += '&nbsp; &nbsp;<a href=#board_options>board</a>';
1687  menu += '&nbsp; &nbsp;<a href=#header_moves_options>header and moves</a>';
1688  menu += '&nbsp; &nbsp;<a href=#page_options>page</a>';
1689  menu += '<span class="extendedOption">&nbsp; &nbsp;<a href=#url_options>URL</a></span>';
1690  menu += '</div>';
1691  menu += '</td></tr></table>';
1692  document.write(menu);
1693}
1694
1695var firstLoad = true;
1696window.onload = new_onLoad;
1697
1698</script>
1699
1700<h1 style="text-align:right;">
1701<span style="float:left; color:red;">
1702pgn4web board generator
1703</span>
1704<a href="." onfocus="this.blur();" style="width:49px; height:29px; background:url(pawns.png) -47px -15px; vertical-align:baseline; display:inline-block;"></a>
1705</h1>
1706
1707<div style="height: 1em"></div>
1708<script type="text/javascript">print_menu("instructions", 2, "instructions");</script>
1709
1710<ul type="square" style="text-align: justify; font-size: smaller;">
1711
1712<li>
1713<a href=#pgn_form><b>enter your PGN text</b> in the green textbox below</a>
1714  <ul type="square">
1715  <li id="help_pgn_short">keep PGN data short: due to a limitation of web browsers and web servers with the URL length, only short PGN texts are allowed, usually up to four games without comments; an error message shows when the max URL length limit is exceeded, in case try removing unnecessary header tags and comments/variations or try reducing the number of games per chessboard</li>
1716  <li id="help_pgn_compressed">the PGN data is compressed and encoded, with characters outside the 255 characters ascii set rejected and replaced with stars "*"; this might affect some non English text and names</li>
1717  <li>in case of errors in the supplied PGN data, a chessboard square starts flashing to signal the exception; detailed debug information is available clicking on the flashing chessboard square</li>
1718  </ul>
1719</li>
1720<div style="line-height: 0.5em;">&nbsp;</div>
1721
1722<li>
1723<b><a href=#templates>select a predefined settings template</a></b> and/or <b><a href=#replay_options>modify any of the configuration options</a></b>, layout, colors and fonts
1724</li>
1725<div style="line-height: 0.5em;">&nbsp;</div>
1726
1727<li>
1728<b><a href=#generate>generate the HTML code</a></b> and <b><a href=#game_preview>preview your chessboard</a></b>
1729</li>
1730<div style="line-height: 0.5em;">&nbsp;</div>
1731
1732<li>
1733<b><a href=#replay_options>fine tune configuration options</a></b> to your liking
1734  <ul type="square">
1735  <li><a href=#page_options>check carefully the frame height/width values</a>: different browsers might render some items slightly bigger or smaller, so <a href=#page_options>leave some empty space at the bottom of the frame by increasing the height</a></li>
1736  </ul>
1737</li>
1738<div style="line-height: 0.5em;">&nbsp;</div>
1739
1740<li>
1741once happy with <a href=#game_preview>the preview chessboard</a>, just <a href=#generate><b>cut and paste the HTML code</b> from the yellow box</a> into your web page or your blog; when entering the code in your website or blog, please make sure you are using the HTML editing option, otherwise an enhanced editor might alter the code you enter; you can also <a href=#generate><b>generate a short url</b></a> for sharing the board via email, instant messaging or social networking sites
1742</li>
1743<div style="line-height: 0.5em;">&nbsp;</div>
1744
1745<li>
1746if you plan to reuse similar settings for other chessboards, you can <b><a href=#templates>bookmark a custom template</a></b> into your web browser bookmarks
1747</li>
1748<div style="line-height: 0.5em;">&nbsp;</div>
1749
1750<li>
1751email to <i><script type="text/javascript">document.write('<a href=mailto:' + pgn4web_project_email + '>' + pgn4web_project_email + '</a>');</script></i> the address of your website or your blog
1752</li>
1753<div style="line-height: 0.5em;">&nbsp;</div>
1754
1755<li>
1756if something goes wrong, you might want to <i><a href="javascript:bug_report()">click here and file a bug report</a></i>
1757</li>
1758<div style="line-height: 0.5em;">&nbsp;</div>
1759
1760<li>
1761<b>service availability disclaimer</b>: the pgn4web board generator on this site is intended for chess enthusiasts to easily add chess games with a dynamic chessboard to their personal blogs and websites; this online service is provided on a best effort basis with no guarantee of future availability; if you publish chess games as part of a professional site and need continued server availability and high network performance, you are strongly recommended to evaluate the code from <script type="text/javascript">document.write('<a href=' + pgn4web_project_url + '>the pgn4web site</a>');</script> and install the tool on your own servers; for more details see the board widget generator pages of the pgn4web wiki at <script type="text/javascript">document.write('<a href=' + pgn4web_project_url + '>the pgn4web site</a>');</script>
1762</li>
1763</ul>
1764
1765<!-- hidden elements for the short url generation -->
1766
1767<form id="tinyurl_form_shorturl" action="http://tinyurl.com/create.php" method="post" target="pgn4web_shorturl_window" style="display:inline;">
1768<input id="tinyurl_form_shorturl_url" type="hidden" name="url">
1769<input id="tinyurl_form_shorturl_alias" type="hidden" name="alias">
1770</form>
1771
1772<!-- using bitly apis version 3, correct here if apis are changed -->
1773<form id="bitly_form_shorturl" action="http://api.bitly.com/v3/shorten" method="post" target="pgn4web_shorturl_window" style="display:inline;">
1774<input id="bitly_form_login" type="hidden" name="login">
1775<input id="bitly_form_apiKey" type="hidden" name="apiKey">
1776<input id="bitly_form_longUrl" type="hidden" name="longUrl">
1777<input id="bitly_form_format" type="hidden" name="format">
1778</form>
1779
1780<!-- end of hidden elements for the short url generation -->
1781
1782<form id="board" name="board" style="display:inline;" action="javascript:generate_html_code()">
1783
1784<div style="height: 3em">&nbsp;</div>
1785<script type="text/javascript">print_menu("generate", 2, "generate and copy iFrame and URL");</script>
1786
1787<div style="height: 1em">&nbsp;</div>
1788
1789<div style="font-weight: bold; margin-bottom:6px;">automatically generated HTML code for your web page or blog</div>
1790<textarea readonly id="html_code" name="html_code" rows=15 class="textbox" style="background-color: #FFFFCC; scrollbar-base-color: #FFFFCC;"></textarea>
1791<div id="html_code_status">&nbsp;</div>
1792<div style="margin-top:1em;"><a id="shorturl_link" title="generate a short url for sharing the chessboard via email, instant messaging or social networking sites" style="font-weight: bold;" href="javascript:shorten_pgn4web_url();">click here to create a short url for sharing the chessboard</a><span id="shorturl_link_separator"></span><a id="shorturl_link_pointer" class="shortUrl"></a></div>
1793<p></p>
1794<br>
1795
1796<table width=100% cellspacing=0 cellpadding=0><tr>
1797<td align=left valign=middle width="50%">
1798<input type="button" id="generate_html_code_button" name="generate_html_code_button" value="generate HTML code and update preview" onClick="generate_html_code()" style="width: 100%;"/>
1799</td><td width="25%">
1800</td><td align=right valign=middle width="25%">
1801<input type="button" id="reset_defaults_button" name="reset_defaults_button" value="reset form to default values" onClick="reset_form()" style="width: 100%;"/>
1802</td></tr></table>
1803<p></p>
1804<br>
1805
1806<div style="height: 2em">&nbsp;</div>
1807<script type="text/javascript">print_menu("game_preview", 2, "preview");</script>
1808<div style="height: 1em">&nbsp;</div>
1809
1810<center>
1811<div class="textbox" id=preview>&nbsp;</div>
1812</center>
1813
1814<div style="height: 4em">&nbsp;</div>
1815<h2>configuration options</h2>
1816
1817<script type="text/javascript">print_menu("pgn_form", 3, "chess games notation in PGN format");</script>
1818
1819<div style="height: 1em">&nbsp;</div>
1820
1821<textarea id="pgnText" class="textbox" style="background-color: #DDFFDD; scrollbar-base-color: #DDFFDD;" rows=15 onChange="update_pgnTextLength(); update_suggested_iframe_dimensions();"></textarea>
1822<table cellspacing="0" cellpadding="0" width="100%"><tr>
1823<td align="left"><label class="helptext" for="pgnText">enter PGN data, optionally <a class="helplink" href="" onClick="if (confirm('Strip PGN data?\n\nStripping PGN data will reduce the data size: the chessboard should still display correctly, however the resulting data will not be strictly compliant to the PGN standard.')) { stripPgnText(); } return false;">strip PGN data</a>, <a class="helplink" href="" onClick="if (pgnTextStripUndoValue) { if (confirm('Undo last PGN data strip?\n\nCurrent PGN data and any changes since the last strip will be lost.')) { pgnTextStripUndo(); } } else { alert('Undo data not available.'); } return false;">undo last strip</a></label></td>
1824<td align="right"><span class="helptext" id="pgnTextLength"></span></td>
1825</tr></table>
1826<p></p>
1827
1828<div style="height: 3em">&nbsp;</div>
1829<script type="text/javascript">print_menu("templates", 3, "templates");</script>
1830<div style="height: 1em">&nbsp;</div>
1831
1832<select class="largeDropdown" id="templatesList" name="largeDropdown" onChange="template_selected();" style="font-family: monospace; font-weight: bold; white-space: pre;">
1833<option value="heading" selected="selected">apply a built-in template...</option>
1834<option value="reapply">- reapply last loaded template</option>
1835<option value="random">- apply random template</option>
1836</select>
1837<label class="helptext" for="templatesList">select from preset board generator settings templates</label>
1838<p></p>
1839
1840<a class="configtext" id="thisConfigBookmark" title=""><b>pgn4web board generator custom template link<span id="bookmarkCrc32" style="display: none;"></span></b></a>
1841<span class="helptext">add link into the browser bookmarks, saving current board settings</span>
1842<p></p>
1843
1844<div style="height: 3em">&nbsp;</div>
1845<script type="text/javascript">print_menu("replay_options", 3, "game replay options");</script>
1846<div style="height: 1em">&nbsp;</div>
1847
1848<select class="dropdown" id="autoplayMode" name="dropdown">
1849<option value="game" selected="selected">game</option>
1850<option value="loop">loop</option>
1851<option value="none">none</option>
1852</select>
1853<label class="labeltext" for="autoplayMode">autoplay games</label>
1854<span class="helptext">autoplay first
1855<a id="autopplayMode_game" class="helplink" href="" onClick="if (!this.disabled) { document.board.autoplayMode.value = 'game'; } return false;">game</a>
1856once, or
1857<a id="autopplayMode_loop" class="helplink" href="" onClick="if (!this.disabled) { document.board.autoplayMode.value = 'loop'; } return false;">loop</a>
1858continiously, or autoplay
1859<a id="autopplayMode_none" class="helplink" href="" onClick="if (!this.disabled) { document.board.autoplayMode.value = 'none'; } return false;">none</a>
1860</span>
1861<p></p>
1862
1863<select class="dropdown" id="delay" name="dropdown">
1864<option value="1000"> 1 second</option>
1865<option value="2000"> 2 seconds</option>
1866<option value="3000" selected="selected"> 3 seconds</option>
1867<option value="5000"> 5 seconds</option>
1868<option value="10000">10 seconds</option>
1869<option value="30000">30 seconds</option>
1870</select>
1871<label class="labeltext" for="delay">autoplay delay</label>
1872<p></p>
1873<br>
1874
1875<select class="dropdown" id="initialGame" name="dropdown">
1876<option value="first" selected="selected">first</option>
1877<option value="last">last</option>
1878<option value="random">random</option>
1879</select>
1880<label class="labeltext" for="initialGame">initial game</label>
1881<p></p>
1882
1883<input class="input" type="text" id="initialVariation" name="input" value="" size="12" onChange="validate_number(this, 'initial variation', initialVariation_default);">
1884<label class="labeltext" for="initialVariation">initial variation</label>
1885<span class="helptext">a number; applies only at the first game load; when
1886<a id="initialVariation_blank" class="helplink" href="" onClick="if (!this.disabled) { document.board.initialVariation.value = ''; } return false;">blank</a>,
1887defaults to the main variation</span>
1888<p></p>
1889
1890<input type="hidden" id="initialHalfmove" value="">
1891
1892<select class="dropdown" id="initialHalfmoveSelect" name="dropdown" onChange="javascript:setInitialHalfmove();">
1893        <option value="start" selected="selected">start</option>
1894        <option value="end">end</option>
1895        <option value="random">random</option>
1896        <option value="comment">comment</option>
1897        <option value="variation">variation</option>
1898        <option value="number">custom number</option>
1899</select>
1900<label class="labeltext" for="initialHalfmoveSelect">initial halfmove</label>
1901<span class="helptext"><i>start, end, random and comment</i> settings apply at every game load, <i>custom number</i> only at the first load</span>
1902<p></p>
1903
1904<input class="input" type="text" id="initialHalfmoveNumber" name="input" value="" size="12" onChange="javascript:setInitialHalfmove();">
1905<label class="labeltext" for="initialHalfmoveNumber">initial halfmove number</label>
1906<span class="helptext">actual halfmove number when the setting above is
1907<a id="initialHalfmove_customNumber" class="helplink" href="" onClick="if (!this.disabled) { document.board.initialHalfmoveSelect.value = 'number'; setInitialHalfmove(); } return false;">custom number</a>
1908</span>
1909
1910<div style="height: 3em">&nbsp;</div>
1911<script type="text/javascript">print_menu("board_options", 3, "chessboard options");</script>
1912<div style="height: 1em">&nbsp;</div>
1913
1914<input class="input" type="text" id="squareSize" name="input" value="" size="12" onChange="validate_ss_ps_hm(); update_suggested_iframe_dimensions();">
1915<label class="labeltext" for="squareSize">square size</label>
1916<span class="helptext">a number; must be larger than the piece size plus the highlight border if any</span>
1917<p></p>
1918
1919<select class="dropdown" id="pieceSize" name="dropdown" onChange="validate_ss_ps_hm();">
1920<option value="default" selected="selected">default</option>
1921<option value="20">20</option>
1922<option value="21">21</option>
1923<option value="22">22</option>
1924<option value="23">23</option>
1925<option value="24">24</option>
1926<option value="25">25</option>
1927<option value="26">26</option>
1928<option value="27">27</option>
1929<option value="28">28</option>
1930<option value="29">29</option>
1931<option value="30">30</option>
1932<option value="31">31</option>
1933<option value="32">32</option>
1934<option value="33">33</option>
1935<option value="34">34</option>
1936<option value="35">35</option>
1937<option value="36">36</option>
1938<option value="37">37</option>
1939<option value="38">38</option>
1940<option value="39">39</option>
1941<option value="40">40</option>
1942<option value="41">41</option>
1943<option value="42">42</option>
1944<option value="43">43</option>
1945<option value="44">44</option>
1946<option value="45">45</option>
1947<option value="46">46</option>
1948<option value="47">47</option>
1949<option value="48">48</option>
1950<option value="52">52</option>
1951<option value="56">56</option>
1952<option value="60">60</option>
1953<option value="64">64</option>
1954<option value="72">72</option>
1955<option value="80">80</option>
1956<option value="88">88</option>
1957<option value="96">96</option>
1958<option value="112">112</option>
1959<option value="128">128</option>
1960<option value="144">144</option>
1961<option value="300">300</option>
1962</select>
1963<label class="labeltext" for="pieceSize">piece size</label>
1964<span class="helptext">
1965<a id="pieceSize_default" class="helplink" href="" onClick="if (!this.disabled) { document.board.pieceSize.value = 'default'; } return false;">default</a>
1966selects piece size based on square size</span>
1967<p></p>
1968
1969<select class="dropdown" id="pieceFont" name="dropdown">
1970<option value="default" selected="selected">default</option>
1971<option value="alpha">alpha</option>
1972<option value="merida">merida</option>
1973<option value="uscf">uscf</option>
1974<option value="random">random</option>
1975</select>
1976<label class="labeltext" for="pieceFont">piece font</label>
1977<span class="helptext">
1978<a id="pieceFont_default" class="helplink" href="" onClick="if (!this.disabled) { document.board.pieceFont.value = 'default'; } return false;">default</a>
1979selects piece font based on piece size</span>
1980<p></p>
1981<br>
1982
1983<input class="color {adjust:false} input" type="text" id="lightColorHex" name="input" value="" size="12" onChange="validate_color(this, 'light squares color', lightColorHex_default)">
1984<label class="labeltext" for="lightColorHex">light squares color</label>
1985<p></p>
1986
1987<input class="color {adjust:false} input" type="text" id="darkColorHex" name="input" value="" size="12" onChange="validate_color(this, 'dark squares color', darkColorHex_default)">
1988<label class="labeltext" for="darkColorHex">dark squares color</label>
1989<p></p>
1990
1991<input class="color {adjust:false} input" type="text" id="boardBorderColorHex" name="input" value="" size="12" onChange="validate_color(this, 'board border color', boardBorderColorHex_default)">
1992<label class="labeltext" for="boardBorderColorHex">board border color</label>
1993<p></p>
1994
1995<input class="color {adjust:false} input" type="text" id="boardShadowColorHex" name="input" value="" size="12" onChange="validate_boardShadowColorHex()">
1996<label class="labeltext" for="boardShadowColorHex">board shadow color</label>
1997<span class="helptext">a color;
1998<a id="boardShadowColor_transparent" class="helplink" href="" onClick="if (!this.disabled) { document.board.boardShadowColorHex.color.fromString('FFFFFF'); document.board.boardShadowColorHex.value = 'transparent'; } return false;">transparent</a>
1999disables the shadow,
2000<a id="boardShadowColor_border" class="helplink" href="" onClick="if (!this.disabled) { document.board.boardShadowColorHex.color.fromString('FFFFFF'); document.board.boardShadowColorHex.value = 'border'; } return false;">border</a>
2001copies the board border color
2002</span>
2003<p></p>
2004
2005<select class="dropdown" id="highlightMode" name="dropdown" onChange="validate_ss_ps_hm(); update_controls();">
2006<option value="border">border</option>
2007<option value="square" selected="selected">square</option>
2008<option value="none">none</option>
2009</select>
2010<label class="labeltext" for="highlightMode">square highlight mode</label>
2011<p></p>
2012
2013<input class="color {adjust:false} input" type="text" id="highlightColorHex" name="input" value="" size="12" onChange="validate_color(this, 'highlight squares color', highlightColorHex_default)">
2014<label class="labeltext" for="highlightColorHex">highlight squares color</label>
2015<p></p>
2016<br>
2017
2018<select class="dropdown" id="buttonsDisplay" name="dropdown" onChange="update_controls()">
2019<option value="hidden" selected="selected">hidden</option>
2020<option value="standard">standard</option>
2021<option value="custom">custom</option>
2022</select>
2023<label class="labeltext" for="buttonsDisplay">how to show control buttons</label>
2024<span class="helptext">browser's
2025<a id="buttonsDisplay_standard" class="helplink" href="" onClick="if (!this.disabled) { document.board.buttonsDisplay.value = 'standard'; update_controls(); } return false;">standard</a>
2026buttons, or
2027<a id="buttonsDisplay_custom" class="helplink" href="" onClick="if (!this.disabled) { document.board.buttonsDisplay.value = 'custom'; update_controls(); } return false;">custom</a>
2028colors below, or
2029<a id="buttonsDisplay_hidden" class="helplink" href="" onClick="if (!this.disabled) { document.board.buttonsDisplay.value = 'hidden'; update_controls(); } return false;">hidden</a>
2030buttons</span>
2031<p></p>
2032
2033<input class="color {adjust:false} input" type="text" id="controlBackgroundColorHex" name="input" value="" size="12" onChange="validate_color(this, 'control buttons background color', controlBackgroundColorHex_default); update_controls()">
2034<label class="labeltext" for="controlBackgroundColorHex">custom control buttons background color</label>
2035<p></p>
2036
2037<input class="color {adjust:false} input" type="text" id="controlTextColorHex" name="input" value="" size="12" onChange="validate_color(this, 'control buttons text color', controlTextColorHex_default)">
2038<label class="labeltext" for="controlTextColorHex">custom control buttons text color</label>
2039
2040<div style="height: 3em">&nbsp;</div>
2041<script type="text/javascript">print_menu("header_moves_options", 3, "header and moves options");</script>
2042<div style="height: 1em">&nbsp;</div>
2043
2044<input class="input" type="text" id="textMargin" name="input" value="" size="12" onChange="validate_number(this, 'text margin', textMargin_default);">
2045<label class="labeltext" for="textMargin">text margin</label>
2046<span class="helptext">a number; header/moves margin, nice to have when text overflows with scrollbars</span>
2047<p></p>
2048<br>
2049
2050<select class="dropdown" id="headerDisplay" name="dropdown" onChange="update_controls()">
2051<option value="centered">centered</option>
2052<option value="justified" selected="selected">justified</option>
2053<option value="hidden">hidden</option>
2054<option value="live">live</option>
2055<option value="variations">variations</option>
2056</select>
2057<label class="labeltext" for="headerDisplay"><b>how to show game header</b></label>
2058<p></p>
2059
2060<input class="input" type="text" id="fontHeaderSize" name="input" value="" size="12" onChange="validate_number_percentage(this, 'header font size', fontHeaderSize_default);">
2061<label class="labeltext" for="fontHeaderSize">header font size</label>
2062<span class="helptext">a number</span>
2063<p></p>
2064
2065<input class="color {adjust:false} input" type="text" id="fontHeaderColorHex" name="input" value="" size="12" onChange="validate_color(this, 'header font color', fontHeaderColorHex_default)">
2066<label class="labeltext" for="fontHeaderColorHex">header font color</label>
2067<p></p>
2068<br>
2069
2070<select class="dropdown" id="movesDisplay" name="dropdown" onChange="update_controls()">
2071<option value="figurine" selected="selected">figurine</option>
2072<option value="text">text</option>
2073<option value="puzzle">puzzle</option>
2074<option value="hidden">hidden</option>
2075</select>
2076<label class="labeltext" for="movesDisplay"><b>how to show game moves</b></label>
2077<span class="helptext">select a game moves display option or use <a id="movesDisplay_oneClickOptimizedPuzzleSetup" class="helplink" href="" onClick="if (!this.disabled) { oneClickPuzzleSetup(); update_controls(); } return false;">the one click optimized puzzle setup</a></span>
2078<p></p>
2079
2080<input class="input" type="text" id="fontMovesSize" name="input" value="" size="12" onChange="validate_number_percentage(this, 'moves font size', fontMovesSize_default);">
2081<label class="labeltext" for="fontMovesSize">moves font size</label>
2082<span class="helptext">a number</span>
2083<p></p>
2084
2085<input class="color {adjust:false} input" type="text" id="fontMovesColorHex" name="input" value="" size="12" onChange="validate_color(this, 'moves font color', fontMovesColorHex_default)">
2086<label class="labeltext" for="fontMovesColorHex">moves font color</label>
2087<p></p>
2088
2089<input class="color {adjust:false} input" type="text" id="highlightMoveColorHex" name="input" value="" size="12" onChange="validate_highlightMoveColorHex()">
2090<label class="labeltext" for="highlightMoveColorHex">highlight move color</label>
2091<span class="helptext">a color;
2092<a id="highlightMoveColor_background" class="helplink" href="" onClick="if (!this.disabled) { document.board.highlightMoveColorHex.color.fromString('FFFFFF'); document.board.highlightMoveColorHex.value = 'background'; } return false;">background</a>
2093copies the background color</span>
2094<p></p>
2095<br>
2096
2097<select class="dropdown" id="commentsDisplay" name="dropdown" onChange="update_controls()">
2098<option value="inline" selected="selected">inline</option>
2099<option value="newline">newline</option>
2100<option value="hidden">hidden</option>
2101</select>
2102<label class="labeltext" for="commentsDisplay">how to show move comments and variations</label>
2103<span class="helptext">
2104<a id="commentsDisplay_inline" class="helplink" href="" onClick="if (!this.disabled) { document.board.commentsDisplay.value = 'inline'; update_controls(); } return false;">inline</a>
2105inbetween game moves, or on a
2106<a id="commentsDisplay_newline" class="helplink" href="" onClick="if (!this.disabled) { document.board.commentsDisplay.value = 'newline'; update_controls(); } return false;">newline</a>
2107, or
2108<a id="commentsDisplay_hidden" class="helplink" href="" onClick="if (!this.disabled) { document.board.commentsDisplay.value = 'hidden'; update_controls(); } return false;">hidden</a>
2109</span>
2110<p></p>
2111
2112<input class="input" type="text" id="fontCommentsSize" name="input" value="" size="12" onChange="validate_fontCommentsSize();">
2113<label class="labeltext" for="fontCommentsSize">comments <span class="noExtendedOption">and variations </span>font size</label>
2114<span class="helptext">a number;
2115<a id="fontCommentsSize_moves" class="helplink" href="" onClick="if (!this.disabled) { document.board.fontCommentsSize.value = 'moves'; } return false;">moves</a>
2116copies the moves font size</span>
2117<p></p>
2118
2119<input class="color {adjust:false} input" type="text" id="fontCommentsColorHex" name="input" value="" size="12" onChange="validate_color(this, 'comments font color', fontCommentsColorHex_default)">
2120<label class="labeltext" for="fontCommentsColorHex">comments <span class="noExtendedOption">and variations </span>font color</label>
2121
2122<!-- hiding variations font size and color -->
2123<span class="extendedOption">
2124
2125<p></p>
2126<input class="input" type="text" id="fontVariationsSize" name="input" value="" size="12" onChange="validate_fontVariationsSize();">
2127<label class="labeltext" for="fontVariationsSize">variations font size</label>
2128<span class="helptext">a number;
2129<a id="fontVariationsSize_comments" class="helplink" href="" onClick="if (!this.disabled) { document.board.fontVariationsSize.value = 'comments'; } return false;">comments</a>
2130copies the comments font size</span>
2131
2132<p></p>
2133<input class="color {adjust:false} input" type="text" id="fontVariationsColorHex" name="input" value="" size="12" onChange="validate_color(this, 'variations font color', fontVariationsColorHex_default)">
2134<label class="labeltext" for="fontVariationsColorHex">variations font color</label>
2135<span class="helptext">a number;
2136<a id="fontVariationsColor_comments" class="helplink" href="" onClick="if (!this.disabled) { document.board.fontVariationsColorHex.color.fromString('FFFFFF'); document.board.fontVariationsColorHex.value = 'comments'; } return false;">comments</a>
2137copies the comments font color</span>
2138
2139</span>
2140
2141<div style="height: 3em">&nbsp;</div>
2142<script type="text/javascript">print_menu("page_options", 3, "web page options");</script>
2143<div style="height: 1em">&nbsp;</div>
2144
2145<select class="dropdown" id="horizontalLayout" name="dropdown" onChange="validate_frameHeight(); validate_frameWidth(); update_suggested_iframe_dimensions();">
2146<option value="t">horizontal</option>
2147<option value="f" selected="selected">vertical</option>
2148</select>
2149<label class="labeltext" for="horizontalLayout">chessboard and header/moves layout</label>
2150<p></p>
2151<br>
2152
2153<input class="input" type="text" id="frameHeight" name="input" value="" size="12" onChange="validate_frameHeight(); update_suggested_iframe_dimensions();">
2154<label class="labeltext" for="frameHeight">iFrame height</label>
2155<span id="frameHeight_helpText" class="helptext"></span>
2156<p></p>
2157
2158<input class="input" type="text" id="frameWidth" name="input" value="" size="12" onChange="validate_frameWidth(); update_suggested_iframe_dimensions();">
2159<label class="labeltext" for="frameWidth">iFrame width</label>
2160<span id="frameWidth_helpText" class="helptext"></span>
2161<p></p>
2162
2163<input class="input" type="text" id="framePadding" name="input" value="" size="12" onChange="validate_number(this, 'frame padding', framePadding_default); update_suggested_iframe_dimensions();">
2164<label class="labeltext" for="framePadding">iFrame padding</label>
2165<span class="helptext">a number; border padding around the iframe, included within the iFrame width value</span>
2166<p></p>
2167<br>
2168
2169<input class="color {adjust:false} input" type="text" id="backgroundColorHex" name="input" value="" size="12" onChange="validate_backgroundColorHex()">
2170<label class="labeltext" for="backgroundColorHex">background color</label>
2171<span class="helptext">a color;
2172<a id="backgroundColor_transparent" class="helplink" href="" onClick="if (!this.disabled) { document.board.backgroundColorHex.color.fromString('FFFFFF'); document.board.backgroundColorHex.value = 'transparent'; } return false;">transparent</a>
2173uses the parent's background color</span>
2174<p></p>
2175
2176<!-- hiding preview background color -->
2177<span class="extendedOption">
2178
2179<input class="color {adjust:false} input" type="text" id="previewBackgroundColorHex" name="input" value="" size="12" onChange="validate_color(this, 'preview background color', previewBackgroundColorHex_default)">
2180<label class="labeltext" for="previewBackgroundColorHex">preview background color</label>
2181<span class="helptext">not actually used in the HTML code, just for the preview</span>
2182<p></p>
2183
2184</span>
2185<!-- end hiding preview background color -->
2186
2187<!-- hiding URL options -->
2188<span class="extendedOption">
2189
2190<div style="height: 2em">&nbsp;</div>
2191<script type="text/javascript">print_menu("url_options", 3, "URL options");</script>
2192<div style="height: 1em">&nbsp;</div>
2193
2194<input class="checkbox" type="checkbox" id="useTextarea" name="checkbox" onChange="validate_useTextarea(); update_controls(); update_help();">
2195<label class="labeltext" for="useTextarea">use HTML textarea</label>
2196<span class="helptext">normally
2197<a id="useTextarea_disabled" class="helplink" href="" onClick="if (!this.disabled) { document.board.useTextarea.checked = false; update_controls(); } return false;">disabled</a>;
2198use only for deployment on a page from the same domain as the <i>board URL</i></span>
2199<p></p>
2200
2201<input class="checkbox" type="checkbox" id="encodePgn" name="checkbox" onChange="update_help();">
2202<label class="labeltext" for="encodePgn">encode PGN text</label>
2203<span class="helptext">normally
2204<a id="encodePgn_enabled" class="helplink" href="" onClick="if (!this.disabled) { document.board.encodePgn.checked = true; } return false;">enabled</a>
2205</span>
2206<p></p>
2207
2208<input class="input" type="text" id="boardUrl" name="boardUrl" value="" size="12">
2209<label class="labeltext" for="boardUrl">board URL</label>
2210<span class="helptext">normally as
2211<a id="boardUrl_default" class="helplink" href="" onClick="if (!this.disabled) { document.board.boardUrl.value = boardUrl_default; } return false;">default</a>
2212unless <i>use HTML textarea</i> is enabled or for deployment on a page from a different domain</span>
2213<p></p>
2214
2215</span>
2216<!-- end hiding URL options -->
2217
2218<!-- hidden checkbox for calculating width -->
2219<input class="checkbox" type="checkbox" id="hiddenCheckbox" name="checkbox" style="height: 1px; visibility: hidden;" />
2220
2221<div style="height: 1em">&nbsp;</div>
2222<script type="text/javascript">print_menu("", 2, "");</script>
2223
2224<script type="text/javascript">
2225
2226inputWidth = document.getElementById('squareSize').offsetWidth;
2227theObj = document.getElementsByName('dropdown');
2228for (ii = 0; ii < theObj.length; ii++) {
2229  theObj[ii].style.width = inputWidth + 'px';
2230}
2231
2232checkboxWidth = document.getElementById('hiddenCheckbox').offsetWidth;
2233// the last number added to marginLeft should be equal to the value of the .checkbox style at the top
2234theObj = document.getElementsByName('checkbox');
2235for (ii = 0; ii < theObj.length; ii++) {
2236  theObj[ii].style.marginLeft += (inputWidth - checkboxWidth + 22) + 'px';
2237}
2238
2239
2240var pgnTextStripUndoValue;
2241
2242function stripPgnText() {
2243  var theObj = document.getElementById("pgnText");
2244  if (theObj) {
2245    pgnHeader = new Array();
2246    pgnGame = new Array();
2247    numberOfGames = -1;
2248    pgnGameFromPgnText(theObj.value);
2249    if (pgnGame.length === 0) {
2250      pgnHeader[0] = "";
2251      pgnGame[0] = theObj.value;
2252      numberOfGames = 1;
2253    }
2254    var strippedPgnText = "", strippedHeader, strippedGame, theTokens, theMatch, theRegex, ii, jj;
2255
2256    for (ii = 0; ii < pgnGame.length; ii++) {
2257      strippedHeader = "";
2258      if (theTokens = pgnHeader[ii].match(/\[\s*(Event|Site|Date|Round|White|Black|Result|FEN|Variant)\s*"[^"]+"\s*\]/g)) { // rebuild header leaving only header tags used by board.html
2259        for (jj = 0; jj < theTokens.length; jj++) {
2260          theMatch = theTokens[jj].match(/\[\s*(\w+)\s*"([^"]*)"\s*\]/);
2261          if ((theMatch[1] != "Variant") || (!theMatch[2].match(/^\s*(|chess|normal|standard)\s*$/))) {
2262            if (theMatch[2] = theMatch[2].replace(/[?.]+/g, "").replace(/^\s+|\s+$/g, "")) { // remove ? from header tags
2263              strippedHeader += '[' + theMatch[1] + ' "' + theMatch[2] + '"]\n';
2264            }
2265          }
2266        }
2267      }
2268      if (strippedHeader === "") { strippedHeader = '[X""]\n'; }
2269
2270      strippedGame = pgnGame[ii];
2271      strippedGame = strippedGame.replace(/(^|\n)%[^\n]*(\n|$)/, "$1$2"); // remove lines starting %
2272      strippedGame = strippedGame.replace(/\b\d+\s*\.+\s*(?=[a-hKQRBNO])/g, " "); // remove move numbers
2273      strippedGame = strippedGame.replace(/(\w)[+#](\W)/g, "$1$2"); // remove check and mate signs
2274      strippedGame = strippedGame.replace(/(\w)(x|:)([a-h][1-8])\b/g, "$1$3"); // remove capture signs
2275      strippedGame = strippedGame.replace(/([a-h][18])=([A-Z])/g, "$1$2"); // remove promotion sign
2276      strippedGame = strippedGame.replace(/([36])ep\b/g, "$1"); // remove en passant text
2277      if (theTokens = strippedGame.split("\n")) { // compact lines unless a ; char is present
2278        strippedGame = "";
2279        for (jj = 0; jj < theTokens.length; jj++) {
2280          if ((jj === 0) || (theTokens[jj - 1].indexOf(";") < 0)) {
2281            strippedGame += " " + theTokens[jj].replace(/(^\s+|\s+$)/g, "");
2282          } else {
2283            strippedGame += "\n" + theTokens[jj].replace(/(^\s+|\s+$)/g, "");
2284          }
2285        }
2286      }
2287      strippedGame = strippedGame.replace(/\s*\{(\s*(\$\d+|[?!#])+)\s*\}/, "$1"); // remove comment brackets around NAGs and ?!#
2288      strippedGame = strippedGame.replace(/\[%[^\]]*\]/g, " "); // remove comments tags
2289      strippedGame = strippedGame.replace(/{\s*White Time:\s*\S+\s+Black Time:\s*\S+\s*}/g, " "); // remove custom time info
2290      strippedGame = strippedGame.replace(/{\s*D\s*}|(\bDiagram\s+)?\[#\]/ig, " "); // remove diagram markers
2291      strippedGame = strippedGame.replace(/ +([})\]])/g, "$1").replace(/([{(\[]) +/g, "$1"); // remove space before/after round/curly/square brackets
2292      strippedGame = strippedGame.replace(/\[\s*\]/g, " ").replace(/{\s*}/g, " ").replace(/\(\s*\)/g, " "); // remove empty comments and variations
2293      if (theMatch = strippedHeader.match(/\[\s*Result\s+"([^"]+)"\s*\]/)) { // remove result at the end of game if matching the Result header tag
2294        theRegex = new RegExp(theMatch[1].replace(/([\^$.|?*+(){[])/g, "\\$1") + "\\s*$", "");
2295        strippedGame = strippedGame.replace(theRegex, "");
2296      }
2297      strippedGame = strippedGame.replace(/(^\s+|\s+$)/g, ""); // remove leading/closing spaces
2298      if (strippedGame === "") { strippedGame = ";"; }
2299
2300      strippedPgnText += strippedHeader + strippedGame + "\n\n";
2301    }
2302    if (numberOfGames == 1) {
2303      strippedPgnText = strippedPgnText.replace(/\[X""\]\s*/g, "");
2304    }
2305    strippedPgnText = strippedPgnText.replace(/;\s*$/, "");
2306    strippedPgnText = strippedPgnText.replace(/ {2,}/g, " "); // reduce sequential spaces
2307    strippedPgnText = strippedPgnText.replace(/(\n{2})\n+/g, "$1"); // reduce sequential empty lines
2308    strippedPgnText = strippedPgnText.replace(/(\n) +/g, "$1");
2309    strippedPgnText = strippedPgnText.replace(/(^\s+|\s+$)/g, ""); // remove leading/closing spaces
2310    if (strippedPgnText != theObj.value) {
2311      pgnTextStripUndoValue = theObj.value;
2312      theObj.value = strippedPgnText;
2313      update_pgnTextLength();
2314    }
2315    return true;
2316  }
2317  return false;
2318}
2319
2320function pgnTextStripUndo() {
2321  var theObj = document.getElementById("pgnText");
2322  if (theObj && pgnTextStripUndoValue) {
2323    theObj.value = pgnTextStripUndoValue;
2324    update_pgnTextLength();
2325    pgnTextStripUndoValue = "";
2326    return true;
2327  }
2328  return false;
2329}
2330
2331</script>
2332
2333</form>
2334
2335</body>
2336
2337</html>
2338
2339