X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=www%2Fjs%2Fremoteglot.js;h=0f56b5b206dbc4b7d69d549f8a0f44827d978f90;hb=f3d67feddf00f544e224f3f0a361b914578cdc63;hp=a37fede21d8d44cd7a821e0946d681662f090eac;hpb=7bea925ab1f4de8036939bb6a5a8016492fba872;p=remoteglot
diff --git a/www/js/remoteglot.js b/www/js/remoteglot.js
index a37fede..0f56b5b 100644
--- a/www/js/remoteglot.js
+++ b/www/js/remoteglot.js
@@ -68,6 +68,18 @@ var unique = null;
/** @type {boolean} @private */
var enable_sound = false;
+/**
+ * Our best estimate of how many milliseconds we need to add to
+ * new Date() to get the true UTC time. Calibrated against the
+ * server clock.
+ *
+ * @type {?number}
+ * @private
+ */
+var client_clock_offset_ms = null;
+
+var clock_timer = null;
+
/** The current position on the board, represented as a FEN string.
* @type {?string}
* @private
@@ -122,10 +134,15 @@ var request_update = function() {
$.ajax({
url: "/analysis.pl?ims=" + ims + "&unique=" + unique
}).done(function(data, textstatus, xhr) {
- ims = xhr.getResponseHeader('X-Remoteglot-Last-Modified');
- var num_viewers = xhr.getResponseHeader('X-Remoteglot-Num-Viewers');
+ sync_server_clock(xhr.getResponseHeader('Date'));
+ ims = xhr.getResponseHeader('X-RGLM');
+ var num_viewers = xhr.getResponseHeader('X-RGNV');
possibly_play_sound(current_analysis_data, data);
- current_analysis_data = data;
+ if (Array.isArray(data)) {
+ current_analysis_data = JSON_delta.patch(current_analysis_data, data);
+ } else {
+ current_analysis_data = data;
+ }
update_board(current_analysis_data, displayed_analysis_data);
update_num_viewers(num_viewers);
@@ -145,7 +162,7 @@ var possibly_play_sound = function(old_data, new_data) {
return;
}
var ding = document.getElementById('ding');
- if (ding && ding.play !== undefined) {
+ if (ding && ding.play) {
if (old_data['position'] && old_data['position']['fen'] &&
new_data['position'] && new_data['position']['fen'] &&
(old_data['position']['fen'] !== new_data['position']['fen'] ||
@@ -155,6 +172,23 @@ var possibly_play_sound = function(old_data, new_data) {
}
}
+/**
+ * @type {!string} server_date_string
+ */
+var sync_server_clock = function(server_date_string) {
+ var server_time_ms = new Date(server_date_string).getTime();
+ var client_time_ms = new Date().getTime();
+ var estimated_offset_ms = server_time_ms - client_time_ms;
+
+ // In order not to let the noise move us too much back and forth
+ // (the server only has one-second resolution anyway), we only
+ // change an existing skew if we are at least five seconds off.
+ if (client_clock_offset_ms === null ||
+ Math.abs(estimated_offset_ms - client_clock_offset_ms) > 5000) {
+ client_clock_offset_ms = estimated_offset_ms;
+ }
+}
+
var clear_arrows = function() {
for (var i = 0; i < arrows.length; ++i) {
if (arrows[i].svg) {
@@ -690,6 +724,8 @@ var update_board = function(current_data, display_data) {
$("#pv").empty();
$("#searchstats").html(" ");
$("#refutationlines").empty();
+ $("#whiteclock").empty();
+ $("#blackclock").empty();
refutation_lines = [];
update_refutation_lines();
clear_arrows();
@@ -697,6 +733,8 @@ var update_board = function(current_data, display_data) {
return;
}
+ update_clock();
+
// The engine id.
if (data['id'] && data['id']['name'] !== null) {
$("#engineid").text(data['id']['name']);
@@ -808,6 +846,106 @@ var update_num_viewers = function(num_viewers) {
}
}
+var update_clock = function() {
+ clearTimeout(clock_timer);
+
+ var data = displayed_analysis_data || current_analysis_data;
+ if (data['position']) {
+ var result = data['position']['result'];
+ if (result === '1-0') {
+ $("#whiteclock").text("1");
+ $("#blackclock").text("0");
+ $("#whiteclock").removeClass("running-clock");
+ $("#blackclock").removeClass("running-clock");
+ return;
+ }
+ if (result === '1/2-1/2') {
+ $("#whiteclock").text("1/2");
+ $("#blackclock").text("1/2");
+ $("#whiteclock").removeClass("running-clock");
+ $("#blackclock").removeClass("running-clock");
+ return;
+ }
+ if (result === '0-1') {
+ $("#whiteclock").text("0");
+ $("#blackclock").text("1");
+ $("#whiteclock").removeClass("running-clock");
+ $("#blackclock").removeClass("running-clock");
+ return;
+ }
+ }
+
+ var white_clock = "";
+ var black_clock = "";
+
+ // Static clocks.
+ if (data['position'] &&
+ data['position']['white_clock'] &&
+ data['position']['black_clock']) {
+ white_clock = data['position']['white_clock'].replace(/:[0-5][0-9]$/, "");
+ black_clock = data['position']['black_clock'].replace(/:[0-5][0-9]$/, "");
+ }
+
+ // Dynamic clock (only one, obviously).
+ var color;
+ if (data['position']['white_clock_target']) {
+ color = "white";
+ $("#whiteclock").addClass("running-clock");
+ $("#blackclock").removeClass("running-clock");
+ } else if (data['position']['black_clock_target']) {
+ color = "black";
+ $("#whiteclock").removeClass("running-clock");
+ $("#blackclock").addClass("running-clock");
+ } else {
+ $("#whiteclock").removeClass("running-clock");
+ $("#blackclock").removeClass("running-clock");
+ }
+ if (color) {
+ var now = new Date().getTime() + client_clock_offset_ms;
+ var remaining_ms = data['position'][color + '_clock_target'] * 1000 - now;
+ if (color === "white") {
+ white_clock = format_clock(remaining_ms);
+ } else {
+ black_clock = format_clock(remaining_ms);
+ }
+
+ // See when the clock will change next, and update right after that.
+ var next_update_ms = remaining_ms % 60000 + 100;
+ clock_timer = setTimeout(update_clock, next_update_ms);
+ }
+
+ $("#whiteclock").text(white_clock);
+ $("#blackclock").text(black_clock);
+}
+
+/**
+ * @param {Number} remaining_ms
+ */
+var format_clock = function(remaining_ms) {
+ if (remaining_ms <= 0) {
+ return "00:00";
+ }
+
+ var remaining = Math.floor(remaining_ms / 1000);
+ var seconds = remaining % 60;
+ remaining = (remaining - seconds) / 60;
+ var minutes = remaining % 60;
+ remaining = (remaining - minutes) / 60;
+ var hours = remaining;
+ return format_2d(hours) + ":" + format_2d(minutes);
+}
+
+/**
+ * @param {Number} x
+ */
+var format_2d = function(x) {
+ if (x >= 10) {
+ return x;
+ } else {
+ return "0" + x;
+ }
+}
+
/**
* @param {string} move
* @param {Number} move_num
@@ -963,6 +1101,14 @@ var set_sound = function(param_enable_sound) {
if (enable_sound) {
$("#soundon").html("On");
$("#soundoff").html("Off");
+
+ // Seemingly at least Firefox prefers MP3 over Opus; tell it otherwise,
+ // and also preload the file since the user has selected audio.
+ var ding = document.getElementById('ding');
+ if (ding && ding.canPlayType && ding.canPlayType('audio/ogg; codecs="opus"') === 'probably') {
+ ding.src = 'ding.opus';
+ ding.load();
+ }
} else {
$("#soundon").html("On");
$("#soundoff").html("Off");