]> git.sesse.net Git - remoteglot/blobdiff - www/js/remoteglot.js
Do not rely on innerHTML for print_pv().
[remoteglot] / www / js / remoteglot.js
index c3de366309a6c6cd60289b551e4576515e531a7d..5c769f4c05b50a94bd4f214513fdd08fe2b6d104 100644 (file)
@@ -380,9 +380,7 @@ let sync_server_clock = function(server_date_string) {
 let clear_arrows = function() {
        for (let i = 0; i < arrows.length; ++i) {
                if (arrows[i].svg) {
-                       if (arrows[i].svg.parentElement) {
-                               arrows[i].svg.parentElement.removeChild(arrows[i].svg);
-                       }
+                       arrows[i].svg.remove();
                        delete arrows[i].svg;
                }
        }
@@ -506,11 +504,12 @@ let position_arrow = function(arrow) {
                return;
        }
 
-       let zoom_factor = document.getElementById("board").getBoundingClientRect().width / 400.0;
+       let board_width = parseInt(document.querySelector(".board-b72b1").style.width, 10);
+       let zoom_factor = board_width / 400.0;
        let line_width = arrow.line_width * zoom_factor;
        let arrow_size = arrow.arrow_size * zoom_factor;
 
-       let square_width = document.querySelector(".square-a8").getBoundingClientRect().width;
+       let square_width = board_width / 8;
        let from_y, to_y, from_x, to_x;
        if (board.orientation() === 'black') {
                from_y = (arrow.from_row + 0.5)*square_width;
@@ -527,8 +526,8 @@ let position_arrow = function(arrow) {
        let SVG_NS = "http://www.w3.org/2000/svg";
        let XHTML_NS = "http://www.w3.org/1999/xhtml";
        let svg = document.createElementNS(SVG_NS, "svg");
-       svg.setAttribute("width", /** @type{number} */ (document.getElementById("board").getBoundingClientRect().width));
-       svg.setAttribute("height", /** @type{number} */ (document.getElementById("board").getBoundingClientRect().height));
+       svg.setAttribute("width", board_width);
+       svg.setAttribute("height", board_width);
        svg.setAttribute("style", "position: absolute");
        svg.setAttribute("position", "absolute");
        svg.setAttribute("version", "1.1");
@@ -631,7 +630,7 @@ let find_nonstupid_moves = function(data, margin, invert) {
        let pv_score = undefined;
        for (let move in data['refutation_lines']) {
                let line = data['refutation_lines'][move];
-               let score = compute_score_sort_key(line['score'], line['depth'], invert, false);
+               let score = compute_score_sort_key(line['score'], line['depth'], invert);
                if (move == data['pv'][0]) {
                        pv_score = score;
                }
@@ -733,59 +732,74 @@ let print_pv = function(line_num, splicepos, opt_limit, opt_showlast) {
                }
        }
 
-       let ret = '';
+       let ret = document.createDocumentFragment();
        let i = 0;
        let in_tb = false;
+       let link = document.createElement('a');
+       link.className = 'move';
        if (opt_limit && opt_showlast && pv.length > opt_limit) {
                // Truncate the PV at the beginning (instead of at the end).
                // We assume here that toplay is 'W'. We also assume that if
                // opt_showlast is set, then it is the history, and thus,
                // the UI should be to expand the history.
-               ret = '(<a class="move" href="javascript:collapse_history(false)">…</a>) ';
+               ret.appendChild(document.createTextNode('('));
+               link.href = 'javascript:collapse_history(false)';
+               link.textContent = '…';
+               ret.appendChild(link);
+               ret.appendChild(document.createTextNode(') '));
                i = pv.length - opt_limit;
                if (i % 2 == 1) {
                        ++i;
                }
                move_num += i / 2;
        } else if (toplay == 'B' && pv.length > 0) {
+               ret.appendChild(document.createTextNode(move_num + '. … '));
                let move = "";
                if (splicepos === 0) {
-                       move += "(TB: ";
+                       ret.appendChild(document.createTextNode('(TB: '));
                        in_tb = true;
                }
-               move += "<a class=\"move\" id=\"automove" + line_num + "-0\" href=\"javascript:show_line(" + line_num + ", " + 0 + ");\">" + pv[0] + "</a>";
-               ret = move_num + '. … ' + move;
+               link.setAttribute('id', 'automove' + line_num + '-0');
+               link.href = 'javascript:show_line(' + line_num + ', ' + 0 + ');';
+               link.textContent = pv[0];
+               ret.appendChild(link);
                toplay = 'W';
                ++i;
                ++move_num;
        }
        for ( ; i < pv.length; ++i) {
-               let move = "<a class=\"move\" id=\"automove" + line_num + "-" + i + "\" href=\"javascript:show_line(" + line_num + ", " + i + ");\">" + pv[i] + "</a>";
+               link = document.createElement('a');
+               link.className = 'move';
+               link.setAttribute('id', 'automove' + line_num + '-' + i);
+               link.textContent = pv[i];
+               link.href = 'javascript:show_line(' + line_num + ', ' + i + ');';
                if (splicepos === i) {
-                       ret += " (TB: ";
+                       ret.appendChild(document.createTextNode('(TB: '));
                        in_tb = true;
                }
 
                if (toplay == 'W') {
                        if (i > opt_limit && !opt_showlast) {
                                if (in_tb) {
-                                       ret += ")";
+                                       ret.appendChild(document.createTextNode(')'));
                                }
-                               return ret + ' (…)';
+                               ret.appendChild(document.createTextNode(' (…)'));
+                               return ret;
                        }
                        if (ret != '') {
-                               ret += ' ';
+                               ret.appendChild(document.createTextNode(' '));
                        }
-                       ret += move_num + '. ' + move;
+                       ret.appendChild(document.createTextNode(move_num + '. '));
                        ++move_num;
                        toplay = 'B';
                } else {
-                       ret += ' ' + move;
+                       ret.appendChild(document.createTextNode(' '));
                        toplay = 'W';
                }
+               ret.appendChild(link);
        }
        if (in_tb) {
-               ret += ")";
+               ret.appendChild(document.createTextNode(')'));
        }
        return ret;
 }
@@ -803,14 +817,20 @@ let update_board_highlight = function() {
 }
 
 let update_history = function() {
+       let history = document.getElementById('history');
        if (display_lines[0] === null || display_lines[0].pv.length == 0) {
-               document.getElementById("history").innerHTML = "No history";
+               history.textContent = 'No history';
        } else if (truncate_display_history) {
-               document.getElementById("history").innerHTML = print_pv(0, null, 8, true);
+               history.replaceChildren(print_pv(0, null, 8, true));
        } else {
-               document.getElementById("history").innerHTML =
-                       '(<a class="move" href="javascript:collapse_history(true)">collapse</a>) ' +
-                       print_pv(0, null);
+               history.textContent = '(';
+               let link = document.createElement('a');
+               link.className = 'move';
+               link.href = 'javascript:collapse_history(true)';
+               link.textContent = 'collapse';
+               history.appendChild(link);
+               history.appendChild(document.createTextNode(') '));
+               history.append(print_pv(0, null));
        }
 }
 
@@ -877,10 +897,13 @@ let update_refutation_lines = function() {
 
                if (line['pv'].length == 0) {
                        // Not found, so just make a one-move PV.
-                       let move = "<a class=\"move\" href=\"javascript:show_line(" + display_lines.length + ", " + 0 + ");\">" + line['move'] + "</a>";
-                       move_td.innerHTML = move;
-                       let score_td = document.createElement("td");
+                       let link = document.createElement('a');
+                       link.className = 'move';
+                       link.href = 'javascript:show_line(' + display_lines.length + ', ' + 0 + ')';
+                       link.textContent = line['move'];
+                       move_td.replaceChildren(link);
 
+                       let score_td = document.createElement("td");
                        score_td.classList.add("score");
                        score_td.textContent = "—";
                        tr.appendChild(score_td);
@@ -893,7 +916,7 @@ let update_refutation_lines = function() {
                        let pv_td = document.createElement("td");
                        tr.appendChild(pv_td);
                        pv_td.classList.add("pv");
-                       pv_td.innerHTML = add_pv(base_fen, base_line.concat([ line['move'] ]), move_num, toplay, scores, start_display_move_num);
+                       pv_td.append(add_pv(base_fen, base_line.concat([ line['move'] ]), move_num, toplay, scores, start_display_move_num));
 
                        tbl.append(tr);
                        continue;
@@ -922,7 +945,7 @@ let update_refutation_lines = function() {
                let pv_td = document.createElement("td");
                tr.appendChild(pv_td);
                pv_td.classList.add("pv");
-               pv_td.innerHTML = add_pv(base_fen, base_line.concat(line['pv']), move_num, toplay, scores, start_display_move_num, 10);
+               pv_td.append(add_pv(base_fen, base_line.concat(line['pv']), move_num, toplay, scores, start_display_move_num, 10));
 
                tbl.append(tr);
        }
@@ -1216,7 +1239,7 @@ let update_board = function() {
                document.getElementById("score").textContent = "No analysis for this move";
                document.getElementById("pvtitle").textContent = "PV:";
                document.getElementById("pv").replaceChildren();
-               document.getElementById("searchstats").innerHTML = "&nbsp;";
+               document.getElementById("searchstats").textContent = "&nbsp;";
                document.getElementById("refutationlines").replaceChildren();
                document.getElementById("whiteclock").replaceChildren();
                document.getElementById("blackclock").replaceChildren();
@@ -1255,7 +1278,7 @@ let update_board = function() {
 
        // The search stats.
        if (data['searchstats']) {
-               document.getElementById("searchstats").innerHTML = data['searchstats'];
+               document.getElementById("searchstats").textContent = data['searchstats'];
        } else if (data['tablebase'] == 1) {
                document.getElementById("searchstats").textContent = "Tablebase result";
        } else if (data['nodes'] && data['nps'] && data['depth']) {
@@ -1284,7 +1307,7 @@ let update_board = function() {
        document.getElementById("pvtitle").textContent = "PV:";
 
        let scores = [{ first_move: -1, score: data['score'] }];
-       document.getElementById("pv").innerHTML = add_pv(data['position']['fen'], data['pv'], data['position']['move_num'], data['position']['toplay'], scores, 0);
+       document.getElementById("pv").replaceChildren(add_pv(data['position']['fen'], data['pv'], data['position']['move_num'], data['position']['toplay'], scores, 0));
 
        // Update the PV arrow.
        clear_arrows();
@@ -1828,23 +1851,19 @@ let update_historic_analysis = function() {
  * @param {string} fen
  */
 let update_imbalance = function(fen) {
-       let hiddenboard = new Chess(fen);
        let imbalance = {'k': 0, 'q': 0, 'r': 0, 'b': 0, 'n': 0, 'p': 0};
-       for (let row = 0; row < 8; ++row) {
-               for (let col = 0; col < 8; ++col) {
-                       let col_text = String.fromCharCode('a1'.charCodeAt(0) + col);
-                       let row_text = String.fromCharCode('a1'.charCodeAt(1) + row);
-                       let square = col_text + row_text;
-                       let contents = hiddenboard.get(square);
-                       if (contents !== null) {
-                               if (contents.color === 'w') {
-                                       ++imbalance[contents.type];
-                               } else {
-                                       --imbalance[contents.type];
-                               }
-                       }
+       for (const c of fen) {
+               if (c === ' ') {
+                       // End of board
+                       break;
+               }
+               if (c != c.toUpperCase()) {
+                       --imbalance[c];
+               } else if (c != c.toLowerCase()) {
+                       ++imbalance[c.toLowerCase()];
                }
        }
+
        let white_imbalance = document.getElementById('whiteimbalance');
        let black_imbalance = document.getElementById('blackimbalance');
        white_imbalance.textContent = '';
@@ -1894,7 +1913,7 @@ let update_move_highlight = function() {
                        document.getElementById("pvtitle").textContent = "Exploring:";
                        current_display_line.start_display_move_num = 0;
                        display_lines.push(current_display_line);
-                       document.getElementById("pv").innerHTML = print_pv(display_lines.length - 1, null);  // FIXME
+                       document.getElementById("pv").append(print_pv(display_lines.length - 1, null));  // FIXME
                        display_line_num = display_lines.length - 1;
 
                        // Clear out the PV, so it's not selected by anything later.
@@ -1954,12 +1973,12 @@ let update_displayed_line = function() {
        document.getElementById("linemsg").style.display = 'none';
 
        if (current_display_move <= 0) {
-               document.getElementById("prevmove").innerHTML = "Previous";
+               document.getElementById("prevmove").textContent = "Previous";
        } else {
                document.getElementById("prevmove").innerHTML = "<a href=\"javascript:prev_move();\">Previous</a></span>";
        }
        if (current_display_move == current_display_line.pv.length - 1) {
-               document.getElementById("nextmove").innerHTML = "Next";
+               document.getElementById("nextmove").textContent = "Next";
        } else {
                document.getElementById("nextmove").innerHTML = "<a href=\"javascript:next_move();\">Next</a></span>";
        }
@@ -2242,6 +2261,9 @@ let onSnapEnd = function(source, target) {
 
        // Shouldn't really be here if we have hash probes, but there's really
        // nothing we can do.
+       // FIXME: Just make a new line, probably (even if we don't have hash moves).
+       // As it is, we can actually drag (but not click) such a move in the UI,
+       // but it has no effect on what we're probing.
 }
 // End of dragging-related code.
 
@@ -2348,10 +2370,9 @@ let compute_plot_score = function(score) {
  * @param score The score digest tuple.
  * @param {?number} depth Depth the move has been computed to, or null.
  * @param {boolean} invert Whether black is to play.
- * @param {boolean=} depth_secondary_key
  * @return {number}
  */
-let compute_score_sort_key = function(score, depth, invert, depth_secondary_key) {
+let compute_score_sort_key = function(score, depth, invert) {
        let s;
        if (!score) {
                return -10000000;
@@ -2375,11 +2396,7 @@ let compute_score_sort_key = function(score, depth, invert, depth_secondary_key)
        }
        if (s) {
                if (invert) s = -s;
-               if (depth_secondary_key) {
-                       return s * 200 + (depth || 0);
-               } else {
-                       return s;
-               }
+               return s;
        } else {
                return null;
        }