diff --git a/app/views/lobby/jsI18n.scala.html b/app/views/lobby/jsI18n.scala.html index 3ae26f2332..cb5806efcb 100644 --- a/app/views/lobby/jsI18n.scala.html +++ b/app/views/lobby/jsI18n.scala.html @@ -1,5 +1,12 @@ @()(implicit ctx: Context) @Html(J.stringify(i18nJsObject( trans.realTime, -trans.correspondence +trans.correspondence, +trans.nbGamesInPlay, +trans.player, +trans.time, +trans.joinTheGame, +trans.cancel, +trans.casual, +trans.rated ))) diff --git a/modules/lobby/src/main/Hook.scala b/modules/lobby/src/main/Hook.scala index a47e8232d7..d01cb2ac78 100644 --- a/modules/lobby/src/main/Hook.scala +++ b/modules/lobby/src/main/Hook.scala @@ -58,7 +58,7 @@ case class Hook( "username" -> username, "rating" -> rating, "variant" -> realVariant.shortName, - "mode" -> realMode.toString, + "mode" -> realMode.id, "clock" -> clock.show, "time" -> clock.estimateTotalTime, "speed" -> speed.id, diff --git a/public/javascripts/big.js b/public/javascripts/big.js index e2f9335681..fe27fcc875 100644 --- a/public/javascripts/big.js +++ b/public/javascripts/big.js @@ -287,6 +287,12 @@ var storage = { }); } + if (lichess.round) startRound(document.getElementById('lichess'), lichess.round); + else if (lichess.prelude) startPrelude(document.querySelector('.lichess_game'), lichess.prelude); + else if (lichess.analyse) startAnalyse(document.getElementById('lichess'), lichess.analyse); + else if (lichess.user_analysis) startUserAnalysis(document.getElementById('lichess'), lichess.user_analysis); + else if (lichess.lobby) startLobby(document.getElementById('hooks_wrap'), lichess.lobby); + $('#lichess').on('click', '.socket-link:not(.disabled)', function() { lichess.socket.send($(this).data('msg'), $(this).data('data')); }); @@ -387,11 +393,6 @@ var storage = { $('body').on('lichess.content_loaded', setBlindMode); } - if (lichess.round) startRound(document.getElementById('lichess'), lichess.round); - else if (lichess.prelude) startPrelude(document.querySelector('.lichess_game'), lichess.prelude); - else if (lichess.analyse) startAnalyse(document.getElementById('lichess'), lichess.analyse); - else if (lichess.user_analysis) startUserAnalysis(document.getElementById('lichess'), lichess.user_analysis); - setTimeout(function() { if (lichess.socket === null) { lichess.socket = new lichess.StrongSocket("/socket", 0); @@ -1243,6 +1244,468 @@ var storage = { }, 100); }); + function startLobby(element, cfg) { + var $timeline = $("#timeline"); + var $newposts = $("div.new_posts"); + var nbPlayersElement = document.getElementById('site_baseline span'); + var lobby; + // var $canvas = $wrap.find('.canvas'); + // var $hooksList = $wrap.find('#hooks_list'); + // var $tableWrap = $hooksList.find('div.table_wrap'); + // var $table = $tableWrap.find('table').sortable(); + // var $tbody = $table.find('tbody'); + // var animation = 500; + // var hookPool = []; + // var nextHooks = []; + + // var flushHooksTimeout; + // var flushHooksSchedule = function() { + // flushHooksTimeout = setTimeout(flushHooks, 8000); + // }; + // var flushHooks = function() { + // clearTimeout(flushHooksTimeout); + // $tbody.fadeIn(500); + // $tableWrap.clone().attr('id', 'tableclone').appendTo($hooksList).fadeOut(500, function() { + // $(this).remove(); + // }); + // $tbody.find('tr.disabled').remove(); + // $tbody.append(nextHooks); + // nextHooks = []; + // $table.trigger('sortable.sort'); + // flushHooksSchedule(); + // }; + // flushHooksSchedule(); + // $('body').on('lichess.hook-flush', flushHooks); + + // $wrap.on('click', '>div.tabs>a', function() { + // var tab = $(this).data('tab'); + // $(this).siblings().removeClass('active').end().addClass('active'); + // $wrap.find('>.tab').hide().filter('.' + tab).show(); + // storage.set('lobbytab', tab); + // reloadSeeksIfVisible(); + // }); + // var active = storage.get('lobbytab'); + // if (['real_time', 'seeks', 'now_playing'].indexOf(active) === -1) active = 'real_time'; + // if (!$wrap.find('>div.tabs>.' + active).length) active = 'real_time'; + // $wrap.find('>div.tabs>.' + active).addClass('active'); + // $wrap.find('>.' + active).show(); + + // $realTime.on('click', '.toggle', function() { + // var mode = $(this).data('mode'); + // $realTime.children().hide().filter('#hooks_' + mode).show(); + // storage.set('lobbymode', mode); + // }); + // var mode = storage.get('lobbymode') || 'list'; + // $('#hooks_' + mode).show(); + + // $wrap.find('a.filter').click(function() { + // var $a = $(this); + // var $div = $wrap.find('#hook_filter'); + // setTimeout(function() { + // $div.click(function(e) { + // e.stopPropagation(); + // }); + // $('html').one('click', function(e) { + // $div.off('click').removeClass('active'); + // $a.removeClass('active'); + // }); + // }, 10); + // if ($(this).toggleClass('active').hasClass('active')) { + // $div.addClass('active'); + // if ($div.is(':empty')) { + // $.ajax({ + // url: $(this).attr('href'), + // success: function(html) { + // var save = $.fp.debounce(function() { + // var $form = $div.find('form'); + // $.ajax({ + // url: $form.attr('action'), + // data: $form.serialize(), + // type: 'post', + // success: function(filter) { + // lichess_preload.filter = filter; + // drawHooks(); + // $('body').trigger('lichess.hook-flush'); + // } + // }); + // }, 500); + // $div.html(html).find('input').change(save); + // $div.find('button.reset').click(function() { + // $div.find('label input').prop('checked', true).trigger('change'); + // $div.find('.rating_range').each(function() { + // var s = $(this); + // s.slider('values', [s.slider('option', 'min'), s.slider('option', 'max')]).trigger('change'); + // }); + // }); + // $div.find('button').click(function() { + // $wrap.find('a.filter').click(); + // return false; + // }); + // $div.find('.rating_range').each(function() { + // var $this = $(this); + // var $input = $this.find("input"); + // var $span = $this.siblings(".range"); + // var min = $input.data("min"); + // var max = $input.data("max"); + // var values = $input.val() ? $input.val().split("-") : [min, max]; + // $span.text(values.join(' - ')); + + // function change() { + // setTimeout(function() { + // var values = $this.slider('values'); + // $input.val(values[0] + "-" + values[1]); + // $span.text(values[0] + " - " + values[1]); + // save(); + // }, 50); + // } + // $this.slider({ + // range: true, + // min: min, + // max: max, + // values: values, + // step: 50, + // slide: change + // }).change(change); + // }); + // } + // }); + // } + // } else { + // $div.removeClass('active'); + // } + // return false; + // }); + + function resizeTimeline() { + if ($timeline.length) { + var pos = $timeline.offset().top, + max = $('#lichess').offset().top + 536; + while (pos + $timeline.outerHeight() > max) { + $timeline.find('div.entry:last').remove(); + } + } + } + resizeTimeline(); + + // lichess_preload.hookPool.forEach(addHook); + // drawHooks(true); + // $table.find('th:eq(2)').click().end(); + + lichess.socket = new lichess.StrongSocket( + '/lobby/socket/v1', + cfg.data.version, { + receive: function(t, d) { + if (lobby) lobby.socketReceive(t, d); + else console.log('missed', t, d); + }, + events: { + reload_timeline: function() { + $.ajax({ + url: $timeline.data('href'), + success: function(html) { + $timeline.html(html); + resizeTimeline(); + $('body').trigger('lichess.content_loaded'); + } + }); + }, + streams: function(html) { + $('#streams_on_air').html(html); + }, + // hook_add: function(hook) { + // addHook(hook); + // drawHooks(); + // if (hook.action == 'cancel') $('body').trigger('lichess.hook-flush'); + // }, + // hook_remove: removeHook, + // hook_list: syncHookIds, + featured: changeFeatured, + redirect: function(e) { + $.lichessOpeningPreventClicks(); + $.redirect(e); + }, + tournaments: function(data) { + $("#enterable_tournaments").html(data); + $('body').trigger('lichess.content_loaded'); + }, + reload_forum: function() { + setTimeout(function() { + $.ajax($newposts.data('url'), { + success: function(data) { + $newposts.find('ol').html(data).end().scrollTop(0); + $('body').trigger('lichess.content_loaded'); + } + }); + }, Math.round(Math.random() * 5000)); + }, + // reload_seeks: reloadSeeksIfVisible, + nbr: function(e) { + if (nbPlayersElement && e) { + var prev = parseInt(nbPlayersElement.textContent, 10); + var k = 5; + var interv = 2000 / k; + $.fp.range(k).forEach(function(it) { + setTimeout(function() { + var val = Math.round(((prev * (k - 1 - it)) + (e * (it + 1))) / k); + if (val != prev) { + nbPlayersElement.textContent = val; + prev = val; + } + }, Math.round(it * interv)); + }); + } + }, + // override fen event to reload playing games list + // fen: function(e) { + // lichess.StrongSocket.defaults.events.fen(e); + // if ($nowPlaying.find('.mini_board_' + e.id).length) $.ajax({ + // url: $nowPlaying.data('href'), + // success: function(html) { + // $nowPlaying.html(html); + // $('body').trigger('lichess.content_loaded'); + // var nb = $nowPlaying.find('.my_turn').length; + // $wrap.find('.tabs .now_playing').toggleClass('hilight', nb).find('.unread').text(nb); + // } + // }); + // } + }, + options: { + name: 'lobby' + } + }); + + cfg.socketSend = lichess.socket.send.bind(lichess.socket); + lobby = LichessLobby(document.getElementById('hooks_wrap'), cfg); + + // var variantConfirms = { + // '960': "This is a Chess960 game!\n\nThe starting position of the pieces on the players' home ranks is randomized.\nRead more: http://wikipedia.org/wiki/Chess960\n\nDo you want to play Chess960?", + // 'KotH': "This is a King of the Hill game!\n\nThe game can be won by bringing the king to the center.\nRead more: http://lichess.org/king-of-the-hill", + // '3+': "This is a Three-check game!\n\nThe game can be won by checking the opponent 3 times.\nRead more: http://en.wikipedia.org/wiki/Three-check_chess", + // "Anti": "This is an antichess chess game!\n\n If you can take a piece, you must. The game can be won by losing all your pieces." + // }; + + // function confirmVariant(variant) { + // return Object.keys(variantConfirms).every(function(key) { + // var v = variantConfirms[key] + // if (variant == key && !storage.get(key)) { + // var c = confirm(v); + // if (c) storage.set(key, 1); + // return c; + // } else return true; + // }) + // } + + // $seeks.on('click', 'tr', function() { + // if ($(this).hasClass('must_login')) { + // if (confirm($.trans('You need an account to do that'))) { + // location.href = '/signup'; + // } + // return false; + // } + // if ($(this).data('action') != 'joinSeek' || confirmVariant($(this).data('variant'))) { + // lichess.socket.send($(this).data('action'), $(this).data('id')); + // } + // }); + + // function reloadSeeksIfVisible() { + // if ($seeks.is(':visible')) { + // $.ajax($seeks.data('reload-url'), { + // success: function(html) { + // $seeks.html(html); + // } + // }); + // } + // } + + function changeFeatured(o) { + $('#featured_game').html(o.html); + $('body').trigger('lichess.content_loaded'); + } + + // function removeHook(id) { + // hookPool = hookPool.filter(function(h) { + // return h.id != id; + // }); + // drawHooks(); + // } + + // function syncHookIds(ids) { + // hookPool = hookPool.filter(function(h) { + // return $.fp.contains(ids, h.id); + // }); + // drawHooks(); + // } + + // function addHook(hook) { + // hook.action = hook.uid == lichess.StrongSocket.sri ? "cancel" : "join"; + // hookPool.push(hook); + // } + + // function disableHook(id) { + // $tbody.children('.' + id).addClass('disabled').attr('title', ''); + // destroyChartHook(id); + // } + + // function destroyHook(id) { + // $tbody.children('.' + id).remove(); + // destroyChartHook(id); + // } + + // function destroyChartHook(id) { + // $('#' + id).not('.hiding').addClass('hiding').fadeOut(animation, function() { + // $.powerTip.destroy($(this)); + // $(this).remove(); + // }); + // } + + // function drawHooks(initial) { + // var filter = lichess_preload.filter; + // var seen = []; + // var hidden = 0; + // var visible = 0; + // hookPool.forEach(function(hook) { + // var hide = !$.fp.contains(filter.variant, hook.variant) || !$.fp.contains(filter.mode, hook.mode) || !$.fp.contains(filter.speed, hook.speed) || + // (filter.rating && (!hook.rating || (hook.rating < filter.rating[0] || hook.rating > filter.rating[1]))); + // var hash = hook.mode + hook.variant + hook.time + hook.rating; + // if (hide && hook.action != 'cancel') { + // destroyHook(hook.id); + // hidden++; + // } else if ($.fp.contains(seen, hash) && hook.action != 'cancel') { + // $('#' + hook.id).filter(':visible').hide(); + // $tbody.children('.' + hook.id).hide(); + // } else { + // visible++; + // if (!$('#' + hook.id).length) { + // $canvas.append($(renderPlot(hook)).fadeIn(animation)); + // if (initial) $tbody.append(renderTr(hook)); + // else nextHooks.push(renderTr(hook)); + // } else { + // $('#' + hook.id).not(':visible').fadeIn(animation); + // $tbody.children('.' + hook.id).show(); + // } + // } + // if (hook.action != 'cancel') seen.push(hash); + // }); + // $.makeArray($canvas.find('>span.plot')).map(function(o) { + // return o.getAttribute('data-id'); + // }).concat( + // $.makeArray($tbody.children()).map(function(o) { + // return o.getAttribute('data-id'); + // })).forEach(function(id) { + // if (!$.fp.find(hookPool, function(x) { + // return x.id == id; + // })) disableHook(id); + // }); + + // $wrap + // .find('a.filter') + // .toggleClass('on', hidden > 0) + // .find('span.number').text('(' + hidden + ')'); + + // $('body').trigger('lichess.content_loaded'); + // } + + // function renderPlot(hook) { + // var bottom = Math.max(0, ratingY(hook.rating) - 7); + // var left = Math.max(0, clockX(hook.time) - 4); + // var klass = [ + // 'plot', + // hook.mode == "Rated" ? 'rated' : 'casual', + // hook.action == 'cancel' ? 'cancel' : '', + // hook.variant != 'STD' ? 'variant' : '' + // ].join(' '); + // var $plot = $(''); + // return $plot.data('hook', hook).powerTip({ + // fadeInTime: 0, + // fadeOutTime: 0, + // placement: hook.rating > 2200 ? 'se' : 'ne', + // mouseOnToPopup: true, + // closeDelay: 200, + // intentPollInterval: 50, + // popupId: 'hook' + // }).data('powertipjq', $(renderHook(hook))); + // } + + // function ratingY(e) { + // function ratingLog(a) { + // return Math.log(a / 150 + 1); + // } + // var rating = Math.max(800, Math.min(2800, e || 1500)); + // var ratio; + // if (rating == 1500) { + // ratio = 0.25; + // } else if (rating > 1500) { + // ratio = 0.25 + (ratingLog(rating - 1500) / ratingLog(1300)) * 3 / 4; + // } else { + // ratio = 0.25 - (ratingLog(1500 - rating) / ratingLog(500)) / 4; + // } + // return Math.round(ratio * 489); + // } + + // function clockX(dur) { + // function durLog(a) { + // return Math.log((a - 30) / 200 + 1); + // } + // var max = 2000; + // return Math.round(durLog(Math.min(max, dur || max)) / durLog(max) * 489); + // } + + // function renderHook(hook) { + // var html = ''; + // if (hook.rating) { + // html += '' + hook.username.substr(0, 14) + ''; + // html += '' + hook.rating + ''; + // } else { + // html += 'Anonymous'; + // } + // html += '' + hook.clock + ''; + // html += '' + + // '' + $.trans(hook.mode) + ''; + // html += ''; + // return html; + // } + + // function renderTr(hook) { + // var title = (hook.action == "join") ? $.trans('Join the game') + ' - ' + hook.perf.name : $.trans('cancel'); + // return '' + [ + // ['', ''], + // [hook.username, (hook.rating ? '' + hook.username + '' : 'Anonymous')], + // [hook.rating || 0, hook.rating ? hook.rating : ''], + // [hook.time, hook.clock], + // [hook.mode, + // '' + + // $.trans(hook.mode) + // ] + // ].map(function(x) { + // return '' + x[1] + ''; + // }).join('') + ''; + // } + + // $('#hooks_chart').append( + // [1000, 1200, 1400, 1500, 1600, 1800, 2000, 2200, 2400].map(function(v) { + // var b = ratingY(v); + // return '' + v + '' + + // '
'; + // }).join('') + [1, 2, 3, 5, 7, 10, 15, 20, 30].map(function(v) { + // var l = clockX(v * 60); + // return '' + v + '' + + // '
'; + // }).join('')); + + // $tbody.on('click', 'a.ulink', function(e) { + // e.stopPropagation(); + // }); + // $tbody.on('click', 'td:not(.disabled)', function() { + // $('#' + $(this).parent().data('id')).click(); + // }); + // $canvas.on('click', '>span.plot:not(.hiding)', function() { + // var data = $(this).data('hook'); + // if (data.action != 'join' || confirmVariant(data.variant)) { + // lichess.socket.send(data.action, data.id); + // } + // }); + } + //////////////// // lobby.js // //////////////// @@ -1533,469 +1996,6 @@ var storage = { $('#hooks_list, #hooks_chart').hide(); }; - // hooks - $(function() { - - var $wrap = $('#hooks_wrap'); - if (!$wrap.length) return; - if (!lichess.StrongSocket.available) return; - - var $nowPlaying = $('#now_playing'); - var $seeks = $('#seeks'); - var $timeline = $("#timeline"); - var $newposts = $("div.new_posts"); - var $realTime = $('#real_time'); - var nbPlayersElement = document.getElementById('site_baseline span'); - // var $canvas = $wrap.find('.canvas'); - // var $hooksList = $wrap.find('#hooks_list'); - // var $tableWrap = $hooksList.find('div.table_wrap'); - // var $table = $tableWrap.find('table').sortable(); - // var $tbody = $table.find('tbody'); - // var animation = 500; - // var hookPool = []; - // var nextHooks = []; - - // var flushHooksTimeout; - // var flushHooksSchedule = function() { - // flushHooksTimeout = setTimeout(flushHooks, 8000); - // }; - // var flushHooks = function() { - // clearTimeout(flushHooksTimeout); - // $tbody.fadeIn(500); - // $tableWrap.clone().attr('id', 'tableclone').appendTo($hooksList).fadeOut(500, function() { - // $(this).remove(); - // }); - // $tbody.find('tr.disabled').remove(); - // $tbody.append(nextHooks); - // nextHooks = []; - // $table.trigger('sortable.sort'); - // flushHooksSchedule(); - // }; - // flushHooksSchedule(); - // $('body').on('lichess.hook-flush', flushHooks); - - // $wrap.on('click', '>div.tabs>a', function() { - // var tab = $(this).data('tab'); - // $(this).siblings().removeClass('active').end().addClass('active'); - // $wrap.find('>.tab').hide().filter('.' + tab).show(); - // storage.set('lobbytab', tab); - // reloadSeeksIfVisible(); - // }); - // var active = storage.get('lobbytab'); - // if (['real_time', 'seeks', 'now_playing'].indexOf(active) === -1) active = 'real_time'; - // if (!$wrap.find('>div.tabs>.' + active).length) active = 'real_time'; - // $wrap.find('>div.tabs>.' + active).addClass('active'); - // $wrap.find('>.' + active).show(); - - // $realTime.on('click', '.toggle', function() { - // var mode = $(this).data('mode'); - // $realTime.children().hide().filter('#hooks_' + mode).show(); - // storage.set('lobbymode', mode); - // }); - // var mode = storage.get('lobbymode') || 'list'; - // $('#hooks_' + mode).show(); - - // $wrap.find('a.filter').click(function() { - // var $a = $(this); - // var $div = $wrap.find('#hook_filter'); - // setTimeout(function() { - // $div.click(function(e) { - // e.stopPropagation(); - // }); - // $('html').one('click', function(e) { - // $div.off('click').removeClass('active'); - // $a.removeClass('active'); - // }); - // }, 10); - // if ($(this).toggleClass('active').hasClass('active')) { - // $div.addClass('active'); - // if ($div.is(':empty')) { - // $.ajax({ - // url: $(this).attr('href'), - // success: function(html) { - // var save = $.fp.debounce(function() { - // var $form = $div.find('form'); - // $.ajax({ - // url: $form.attr('action'), - // data: $form.serialize(), - // type: 'post', - // success: function(filter) { - // lichess_preload.filter = filter; - // drawHooks(); - // $('body').trigger('lichess.hook-flush'); - // } - // }); - // }, 500); - // $div.html(html).find('input').change(save); - // $div.find('button.reset').click(function() { - // $div.find('label input').prop('checked', true).trigger('change'); - // $div.find('.rating_range').each(function() { - // var s = $(this); - // s.slider('values', [s.slider('option', 'min'), s.slider('option', 'max')]).trigger('change'); - // }); - // }); - // $div.find('button').click(function() { - // $wrap.find('a.filter').click(); - // return false; - // }); - // $div.find('.rating_range').each(function() { - // var $this = $(this); - // var $input = $this.find("input"); - // var $span = $this.siblings(".range"); - // var min = $input.data("min"); - // var max = $input.data("max"); - // var values = $input.val() ? $input.val().split("-") : [min, max]; - // $span.text(values.join(' - ')); - - // function change() { - // setTimeout(function() { - // var values = $this.slider('values'); - // $input.val(values[0] + "-" + values[1]); - // $span.text(values[0] + " - " + values[1]); - // save(); - // }, 50); - // } - // $this.slider({ - // range: true, - // min: min, - // max: max, - // values: values, - // step: 50, - // slide: change - // }).change(change); - // }); - // } - // }); - // } - // } else { - // $div.removeClass('active'); - // } - // return false; - // }); - - function resizeTimeline() { - if ($timeline.length) { - var pos = $timeline.offset().top, - max = $('#lichess').offset().top + 536; - while (pos + $timeline.outerHeight() > max) { - $timeline.find('div.entry:last').remove(); - } - } - } - resizeTimeline(); - - // lichess_preload.hookPool.forEach(addHook); - // drawHooks(true); - // $table.find('th:eq(2)').click().end(); - - lichess.socket = new lichess.StrongSocket( - '/lobby/socket/v1', - lichess.lobby.data.version, { - events: { - reload_timeline: function() { - $.ajax({ - url: $timeline.data('href'), - success: function(html) { - $timeline.html(html); - resizeTimeline(); - $('body').trigger('lichess.content_loaded'); - } - }); - }, - streams: function(html) { - $('#streams_on_air').html(html); - }, - // hook_add: function(hook) { - // addHook(hook); - // drawHooks(); - // if (hook.action == 'cancel') $('body').trigger('lichess.hook-flush'); - // }, - // hook_remove: removeHook, - // hook_list: syncHookIds, - featured: changeFeatured, - redirect: function(e) { - $.lichessOpeningPreventClicks(); - $.redirect(e); - }, - tournaments: function(data) { - $("#enterable_tournaments").html(data); - $('body').trigger('lichess.content_loaded'); - }, - reload_forum: function() { - setTimeout(function() { - $.ajax($newposts.data('url'), { - success: function(data) { - $newposts.find('ol').html(data).end().scrollTop(0); - $('body').trigger('lichess.content_loaded'); - } - }); - }, Math.round(Math.random() * 5000)); - }, - // reload_seeks: reloadSeeksIfVisible, - nbr: function(e) { - if (nbPlayersElement && e) { - var prev = parseInt(nbPlayersElement.textContent, 10); - var k = 5; - var interv = 2000 / k; - $.fp.range(k).forEach(function(it) { - setTimeout(function() { - var val = Math.round(((prev * (k - 1 - it)) + (e * (it + 1))) / k); - if (val != prev) { - nbPlayersElement.textContent = val; - prev = val; - } - }, Math.round(it * interv)); - }); - } - }, - // override fen event to reload playing games list - // fen: function(e) { - // lichess.StrongSocket.defaults.events.fen(e); - // if ($nowPlaying.find('.mini_board_' + e.id).length) $.ajax({ - // url: $nowPlaying.data('href'), - // success: function(html) { - // $nowPlaying.html(html); - // $('body').trigger('lichess.content_loaded'); - // var nb = $nowPlaying.find('.my_turn').length; - // $wrap.find('.tabs .now_playing').toggleClass('hilight', nb).find('.unread').text(nb); - // } - // }); - // } - }, - options: { - name: "lobby" - } - }); - - // var variantConfirms = { - // '960': "This is a Chess960 game!\n\nThe starting position of the pieces on the players' home ranks is randomized.\nRead more: http://wikipedia.org/wiki/Chess960\n\nDo you want to play Chess960?", - // 'KotH': "This is a King of the Hill game!\n\nThe game can be won by bringing the king to the center.\nRead more: http://lichess.org/king-of-the-hill", - // '3+': "This is a Three-check game!\n\nThe game can be won by checking the opponent 3 times.\nRead more: http://en.wikipedia.org/wiki/Three-check_chess", - // "Anti": "This is an antichess chess game!\n\n If you can take a piece, you must. The game can be won by losing all your pieces." - // }; - - // function confirmVariant(variant) { - // return Object.keys(variantConfirms).every(function(key) { - // var v = variantConfirms[key] - // if (variant == key && !storage.get(key)) { - // var c = confirm(v); - // if (c) storage.set(key, 1); - // return c; - // } else return true; - // }) - // } - - // $seeks.on('click', 'tr', function() { - // if ($(this).hasClass('must_login')) { - // if (confirm($.trans('You need an account to do that'))) { - // location.href = '/signup'; - // } - // return false; - // } - // if ($(this).data('action') != 'joinSeek' || confirmVariant($(this).data('variant'))) { - // lichess.socket.send($(this).data('action'), $(this).data('id')); - // } - // }); - - // function reloadSeeksIfVisible() { - // if ($seeks.is(':visible')) { - // $.ajax($seeks.data('reload-url'), { - // success: function(html) { - // $seeks.html(html); - // } - // }); - // } - // } - - function changeFeatured(o) { - $('#featured_game').html(o.html); - $('body').trigger('lichess.content_loaded'); - } - - // function removeHook(id) { - // hookPool = hookPool.filter(function(h) { - // return h.id != id; - // }); - // drawHooks(); - // } - - // function syncHookIds(ids) { - // hookPool = hookPool.filter(function(h) { - // return $.fp.contains(ids, h.id); - // }); - // drawHooks(); - // } - - // function addHook(hook) { - // hook.action = hook.uid == lichess.StrongSocket.sri ? "cancel" : "join"; - // hookPool.push(hook); - // } - - // function disableHook(id) { - // $tbody.children('.' + id).addClass('disabled').attr('title', ''); - // destroyChartHook(id); - // } - - // function destroyHook(id) { - // $tbody.children('.' + id).remove(); - // destroyChartHook(id); - // } - - // function destroyChartHook(id) { - // $('#' + id).not('.hiding').addClass('hiding').fadeOut(animation, function() { - // $.powerTip.destroy($(this)); - // $(this).remove(); - // }); - // } - - // function drawHooks(initial) { - // var filter = lichess_preload.filter; - // var seen = []; - // var hidden = 0; - // var visible = 0; - // hookPool.forEach(function(hook) { - // var hide = !$.fp.contains(filter.variant, hook.variant) || !$.fp.contains(filter.mode, hook.mode) || !$.fp.contains(filter.speed, hook.speed) || - // (filter.rating && (!hook.rating || (hook.rating < filter.rating[0] || hook.rating > filter.rating[1]))); - // var hash = hook.mode + hook.variant + hook.time + hook.rating; - // if (hide && hook.action != 'cancel') { - // destroyHook(hook.id); - // hidden++; - // } else if ($.fp.contains(seen, hash) && hook.action != 'cancel') { - // $('#' + hook.id).filter(':visible').hide(); - // $tbody.children('.' + hook.id).hide(); - // } else { - // visible++; - // if (!$('#' + hook.id).length) { - // $canvas.append($(renderPlot(hook)).fadeIn(animation)); - // if (initial) $tbody.append(renderTr(hook)); - // else nextHooks.push(renderTr(hook)); - // } else { - // $('#' + hook.id).not(':visible').fadeIn(animation); - // $tbody.children('.' + hook.id).show(); - // } - // } - // if (hook.action != 'cancel') seen.push(hash); - // }); - // $.makeArray($canvas.find('>span.plot')).map(function(o) { - // return o.getAttribute('data-id'); - // }).concat( - // $.makeArray($tbody.children()).map(function(o) { - // return o.getAttribute('data-id'); - // })).forEach(function(id) { - // if (!$.fp.find(hookPool, function(x) { - // return x.id == id; - // })) disableHook(id); - // }); - - // $wrap - // .find('a.filter') - // .toggleClass('on', hidden > 0) - // .find('span.number').text('(' + hidden + ')'); - - // $('body').trigger('lichess.content_loaded'); - // } - - // function renderPlot(hook) { - // var bottom = Math.max(0, ratingY(hook.rating) - 7); - // var left = Math.max(0, clockX(hook.time) - 4); - // var klass = [ - // 'plot', - // hook.mode == "Rated" ? 'rated' : 'casual', - // hook.action == 'cancel' ? 'cancel' : '', - // hook.variant != 'STD' ? 'variant' : '' - // ].join(' '); - // var $plot = $(''); - // return $plot.data('hook', hook).powerTip({ - // fadeInTime: 0, - // fadeOutTime: 0, - // placement: hook.rating > 2200 ? 'se' : 'ne', - // mouseOnToPopup: true, - // closeDelay: 200, - // intentPollInterval: 50, - // popupId: 'hook' - // }).data('powertipjq', $(renderHook(hook))); - // } - - // function ratingY(e) { - // function ratingLog(a) { - // return Math.log(a / 150 + 1); - // } - // var rating = Math.max(800, Math.min(2800, e || 1500)); - // var ratio; - // if (rating == 1500) { - // ratio = 0.25; - // } else if (rating > 1500) { - // ratio = 0.25 + (ratingLog(rating - 1500) / ratingLog(1300)) * 3 / 4; - // } else { - // ratio = 0.25 - (ratingLog(1500 - rating) / ratingLog(500)) / 4; - // } - // return Math.round(ratio * 489); - // } - - // function clockX(dur) { - // function durLog(a) { - // return Math.log((a - 30) / 200 + 1); - // } - // var max = 2000; - // return Math.round(durLog(Math.min(max, dur || max)) / durLog(max) * 489); - // } - - // function renderHook(hook) { - // var html = ''; - // if (hook.rating) { - // html += '' + hook.username.substr(0, 14) + ''; - // html += '' + hook.rating + ''; - // } else { - // html += 'Anonymous'; - // } - // html += '' + hook.clock + ''; - // html += '' + - // '' + $.trans(hook.mode) + ''; - // html += ''; - // return html; - // } - - // function renderTr(hook) { - // var title = (hook.action == "join") ? $.trans('Join the game') + ' - ' + hook.perf.name : $.trans('cancel'); - // return '' + [ - // ['', ''], - // [hook.username, (hook.rating ? '' + hook.username + '' : 'Anonymous')], - // [hook.rating || 0, hook.rating ? hook.rating : ''], - // [hook.time, hook.clock], - // [hook.mode, - // '' + - // $.trans(hook.mode) - // ] - // ].map(function(x) { - // return '' + x[1] + ''; - // }).join('') + ''; - // } - - // $('#hooks_chart').append( - // [1000, 1200, 1400, 1500, 1600, 1800, 2000, 2200, 2400].map(function(v) { - // var b = ratingY(v); - // return '' + v + '' + - // '
'; - // }).join('') + [1, 2, 3, 5, 7, 10, 15, 20, 30].map(function(v) { - // var l = clockX(v * 60); - // return '' + v + '' + - // '
'; - // }).join('')); - - // $tbody.on('click', 'a.ulink', function(e) { - // e.stopPropagation(); - // }); - // $tbody.on('click', 'td:not(.disabled)', function() { - // $('#' + $(this).parent().data('id')).click(); - // }); - // $canvas.on('click', '>span.plot:not(.hiding)', function() { - // var data = $(this).data('hook'); - // if (data.action != 'join' || confirmVariant(data.variant)) { - // lichess.socket.send(data.action, data.id); - // } - // }); - }); - /////////////////// // tournament.js // /////////////////// diff --git a/public/stylesheets/home.css b/public/stylesheets/home.css index ed1bed09c0..3d68a2bebd 100644 --- a/public/stylesheets/home.css +++ b/public/stylesheets/home.css @@ -42,6 +42,7 @@ div.lobby_and_ground { display: inline-block; text-decoration: none; padding: 0px 8px; + margin-right: 3px; border: 1px solid #ccc; background: #dadada; transition: 0.13s; @@ -59,10 +60,7 @@ div.lobby_and_ground { border-top: 2px solid #d85000; } #hooks_wrap > div.tabs .unread { - display: none; -} -#hooks_wrap > div.tabs a.hilight .unread { - display: inline; + margin-left: 3px; } #real_time .toggle { cursor: pointer; @@ -149,15 +147,12 @@ div.lobby_and_ground { margin-left: 3px; } #hooks_wrap .table_wrap { + text-shadow: 0px 1px 0px #FFF; width: 512px; max-height: 512px; - min-height: 200px; + min-height: 78px; overflow: hidden; } -#hooks_wrap .table_wrap table { - width: 512px; - text-shadow: 0px 1px 0px #FFF; -} #hooks_wrap .table_wrap thead th { padding: 14px 12px; font-weight: lighter; @@ -166,16 +161,6 @@ div.lobby_and_ground { #hooks_list thead th { cursor: pointer; } -#hooks_wrap .table_wrap th.reload span { - display: block; - cursor: pointer; - margin-left: 2px; - opacity: 0.5; - transition: 0.13s; -} -#hooks_wrap .table_wrap th.reload:hover span { - opacity: 0.8; -} #hooks_wrap .table_wrap th.sorting-asc, #hooks_wrap .table_wrap th.sorting-desc { font-weight: normal; diff --git a/ui/analyse/src/ctrl.js b/ui/analyse/src/ctrl.js index 55a4d589aa..376094620d 100644 --- a/ui/analyse/src/ctrl.js +++ b/ui/analyse/src/ctrl.js @@ -143,8 +143,8 @@ module.exports = function(cfg, router, i18n, onChange) { this.router = router; - this.trans = function() { - var str = i18n[arguments[0]] + this.trans = function(key) { + var str = i18n[key] || key; Array.prototype.slice.call(arguments, 1).forEach(function(arg) { str = str.replace('%s', arg); }); diff --git a/ui/lobby/src/ctrl.js b/ui/lobby/src/ctrl.js index 5ca72a8b38..817d6bd50d 100644 --- a/ui/lobby/src/ctrl.js +++ b/ui/lobby/src/ctrl.js @@ -1,24 +1,40 @@ var m = require('mithril'); -var partial = chessground.util.partial; +var socket = require('./socket'); +var variant = require('./variant'); +var lobby = require('./lobby'); -module.exports = function(opts) { +module.exports = function(env) { - this.data = data({}, opts.data); + this.data = env.data; + lobby.sortHooks(this.data.hooks); + + this.socket = new socket(env.socketSend, this); + + var fixTab = function(tab) { + if (['real_time', 'seeks', 'now_playing'].indexOf(tab) === -1) tab = 'real_time'; + if (tab === 'now_playing' && this.data.nowPlaying.length === 0) tab = 'real_time'; + return tab; + }.bind(this); + + this.setTab = function(tab) { + this.vm.tab = fixTab(tab); + storage.set('lobbytab', this.vm.tab); + }.bind(this); this.vm = { + tab: fixTab(storage.get('lobbytab')) }; - this.socket = new socket(opts.socketSend, this); + this.clickHook = function(hook) { + if (hook.action === 'cancel' || variant.confirm(data.variant)) socket.send(hook.action, hook.id); + }.bind(this); - this.router = opts.routes; - - this.trans = function() { - var str = opts.i18n[arguments[0]] + this.router = env.routes; + this.trans = function(key) { + var str = env.i18n[key] || key; Array.prototype.slice.call(arguments, 1).forEach(function(arg) { str = str.replace('%s', arg); }); return str; }; - - init(this); }; diff --git a/ui/lobby/src/i18n.js b/ui/lobby/src/i18n.js index 1791892eab..8bba5c6d84 100644 --- a/ui/lobby/src/i18n.js +++ b/ui/lobby/src/i18n.js @@ -1,6 +1,6 @@ module.exports = function(messages) { return function(key) { - var str = messages[key] || untranslated[key] || key; + var str = messages[key] || key; Array.prototype.slice.call(arguments, 1).forEach(function(arg) { str = str.replace('%s', arg); }); diff --git a/ui/lobby/src/lobby.js b/ui/lobby/src/lobby.js new file mode 100644 index 0000000000..57e3ac69bf --- /dev/null +++ b/ui/lobby/src/lobby.js @@ -0,0 +1,9 @@ +function hookOrder(a, b) { + return a.rating > b.rating ? -1 : 1; +}; + +module.exports = { + sortHooks: function(hooks) { + hooks.sort(hookOrder); + } +}; diff --git a/ui/lobby/src/main.js b/ui/lobby/src/main.js index c416c3f8f2..5288766cac 100644 --- a/ui/lobby/src/main.js +++ b/ui/lobby/src/main.js @@ -1,16 +1,20 @@ var m = require('mithril'); -var realTime = require('./module/realTime'); +var ctrl = require('./ctrl'); +var view = require('./view/main'); -module.exports = function(element, env) { +module.exports = function(element, opts) { - //setup routes to start w/ the `#` symbol - m.route.mode = 'hash'; + var controller = new ctrl(opts); - //define a route - m.route(element, '/', { - '/': realTime(env) + m.module(element, { + controller: function () { return controller; }, + view: view }); + + return { + socketReceive: controller.socket.receive + }; }; // lol, that's for the rest of lichess to access mithril diff --git a/ui/lobby/src/module/realTime.js b/ui/lobby/src/module/realTime.js deleted file mode 100644 index ad48b4308e..0000000000 --- a/ui/lobby/src/module/realTime.js +++ /dev/null @@ -1,28 +0,0 @@ -var m = require('mithril'); - -var i18n = require('../i18n'); - -module.exports = function(env) { - return { - controller: function() { - this.data = env.data; - this.trans = i18n(env.i18n); - this.router = env.routes; - }, - view: function(ctrl) { - var myTurnPovsNb = ctrl.data.nowPlaying.povs.count(function(p) { - return p.isMyTurn; - }); - return [ - m('div.tabs', [ - m('a', ctrl.trans('realTime')), - m('a', ctrl.trans('correspondence')), - m('a', [ - ctrl.trans('nbGamesInPlay', ctrl.data.nowPlaying.povs.length), - myTurnPovsNb.length > 0 ? m('span.unread', myTurnPovsNb.length) : null - ]) - ]) - ]; - } - }; -}; diff --git a/ui/lobby/src/variant.js b/ui/lobby/src/variant.js new file mode 100644 index 0000000000..03816f206b --- /dev/null +++ b/ui/lobby/src/variant.js @@ -0,0 +1,23 @@ +var variantConfirms = { + '960': "This is a Chess960 game!\n\nThe starting position of the pieces on the players' home ranks is randomized.\nRead more: http://wikipedia.org/wiki/Chess960\n\nDo you want to play Chess960?", + 'KotH': "This is a King of the Hill game!\n\nThe game can be won by bringing the king to the center.\nRead more: http://lichess.org/king-of-the-hill", + '3+': "This is a Three-check game!\n\nThe game can be won by checking the opponent 3 times.\nRead more: http://en.wikipedia.org/wiki/Three-check_chess", + "Anti": "This is an antichess chess game!\n\n If you can take a piece, you must. The game can be won by losing all your pieces." +}; + +function storageKey(key) { + return 'lichess.variant.' + key; +} + +module.exports = { + confirm: function(variant) { + return Object.keys(variantConfirms).every(function(key) { + var v = variantConfirms[key] + if (variant === key && !storage.get(storageKey(key))) { + var c = confirm(v); + if (c) storage.set(storageKey(key), 1); + return c; + } else return true; + }) + } +}; diff --git a/ui/lobby/src/view.js b/ui/lobby/src/view.js deleted file mode 100644 index 549ff5e2b6..0000000000 --- a/ui/lobby/src/view.js +++ /dev/null @@ -1,8 +0,0 @@ -var m = require('mithril'); - -module.exports = function(ctrl) { - return [ - m('div#hooks_wrap'), - m('div#start_buttons') - ]; -}; diff --git a/ui/lobby/src/view/main.js b/ui/lobby/src/view/main.js new file mode 100644 index 0000000000..725859888c --- /dev/null +++ b/ui/lobby/src/view/main.js @@ -0,0 +1,17 @@ +var m = require('mithril'); + +var renderTabs = require('./tabs'); +var renderRealTime = require('./realTime'); + +module.exports = function(ctrl) { + var body; + switch (ctrl.vm.tab) { + case 'real_time': + body = renderRealTime(ctrl); + break; + } + return [ + m('div.tabs', renderTabs(ctrl)), + body + ]; +}; diff --git a/ui/lobby/src/view/realTime.js b/ui/lobby/src/view/realTime.js new file mode 100644 index 0000000000..ea7e4eda58 --- /dev/null +++ b/ui/lobby/src/view/realTime.js @@ -0,0 +1,50 @@ +var m = require('mithril'); +var util = require('chessground').util; + +function tds(bits) { + return bits.map(function(bit) { + return { + tag: 'td', + children: [bit] + }; + }); +} + +function renderHook(ctrl, hook) { + var title = (hook.action === 'join') ? ctrl.trans('joinTheGame') + ' - ' + hook.perf.name : ctrl.trans('cancel'); + return m('tr', { + title: (hook.action === 'join') ? ctrl.trans('joinTheGame') + ' - ' + hook.perf.name : ctrl.trans('cancel'), + 'data-id': hook.id, + class: hook.action, + onclick: util.partial(ctrl.clickHook, hook) + }, tds([ + m('span', { + class: 'is is2 color-icon ' + (hook.color || 'random') + }), (hook.rating ? m('a', { + href: '/@/' + hook.username + }, hook.username) : 'Anonymous'), + hook.rating ? hook.rating : '', + hook.clock, [m('span', { + class: 'varicon', + 'data-icon': hook.perf.icon + }), ctrl.trans(hook.mode === 1 ? 'rated' : 'casual')] + ])); +}; + +module.exports = function(ctrl) { + return m('table.table_wrap', [ + m('thead', + m('tr', [ + m('th', m('span', { + 'data-hint': ctrl.trans('graph'), + class: 'toggle hint--bottom' + }, m('span.chart[data-icon=9]'))), + m('th', ctrl.trans('player')), + m('th', 'Rating'), + m('th', ctrl.trans('time')), + m('th', ctrl.trans('mode')) + ]) + ), + m('tbody', ctrl.data.hooks.map(util.partial(renderHook, ctrl))) + ]); +}; diff --git a/ui/lobby/src/view/tabs.js b/ui/lobby/src/view/tabs.js new file mode 100644 index 0000000000..f59a21a0f5 --- /dev/null +++ b/ui/lobby/src/view/tabs.js @@ -0,0 +1,26 @@ +var m = require('mithril'); +var util = require('chessground').util; + +function tab(ctrl, key, active, content) { + var attrs = { + onclick: util.partial(ctrl.setTab, key) + } + if (key === active) attrs.class = 'active'; + return m('a', attrs, content); +} + +module.exports = function(ctrl) { + var nowPlayingNb = ctrl.data.nowPlaying.length; + var myTurnPovsNb = ctrl.data.nowPlaying.filter(function(p) { + return p.isMyTurn; + }).length; + var active = ctrl.vm.tab; + return [ + tab(ctrl, 'real_time', active, ctrl.trans('realTime')), + tab(ctrl, 'seeks', active, ctrl.trans('correspondence')), + nowPlayingNb > 0 ? tab(ctrl, 'now_playing', active, [ + ctrl.trans('nbGamesInPlay', nowPlayingNb), + myTurnPovsNb > 0 ? m('span.unread', myTurnPovsNb) : null + ]) : null + ]; +}; diff --git a/ui/puzzle/src/ctrl.js b/ui/puzzle/src/ctrl.js index 8da302890f..7d692d4e5b 100644 --- a/ui/puzzle/src/ctrl.js +++ b/ui/puzzle/src/ctrl.js @@ -153,8 +153,8 @@ module.exports = function(cfg, router, i18n) { this.router = router; - this.trans = function() { - var str = i18n[arguments[0]] + this.trans = function(key) { + var str = i18n[key] || key; Array.prototype.slice.call(arguments, 1).forEach(function(arg) { str = str.replace('%s', arg); }); diff --git a/ui/round/src/ctrl.js b/ui/round/src/ctrl.js index 0470e9bf8c..5a3ef4bf72 100644 --- a/ui/round/src/ctrl.js +++ b/ui/round/src/ctrl.js @@ -118,8 +118,8 @@ module.exports = function(opts) { this.router = opts.routes; - this.trans = function() { - var str = opts.i18n[arguments[0]] + this.trans = function(key) { + var str = opts.i18n[key] || key; Array.prototype.slice.call(arguments, 1).forEach(function(arg) { str = str.replace('%s', arg); });