From ecfaca7f9b76d000c076a34053d0d1b813a34450 Mon Sep 17 00:00:00 2001 From: Stefan Breunig Date: Sun, 3 Feb 2013 19:44:35 +0100 Subject: [PATCH] more chat related stuff. public user chat and message posting is still missing though --- code/chat.js | 287 +++++++++++++++++++++++++---- code/map_data.js | 4 +- code/portal_detail_display.js | 17 +- code/request_handling.js | 5 + code/utils_misc.js | 6 + json_examples/chat_public.js | 111 +++++++++++ main.js | 4 +- style.css | 13 +- total-conversion-build.user.js | 325 ++++++++++++++++++++++++++++----- 9 files changed, 681 insertions(+), 91 deletions(-) diff --git a/code/chat.js b/code/chat.js index 4c804da1..10ea586a 100644 --- a/code/chat.js +++ b/code/chat.js @@ -1,29 +1,19 @@ window.chat = function() {}; +window.chat._oldFactionTimestamp = -1; +window.chat._newFactionTimestamp = -1; +window.chat._oldPublicTimestamp = -1; +window.chat._newPublicTimestamp = -1; + window.chat.getOldestTimestamp = function(public) { - if(chat._needsClearing) return -1; - if(public) { - var a = $('#chatpublic time:first').data('timestamp'); - var b = $('#chatbot time:first').data('timestamp'); - if(a && b) return Math.min(a, b); - return a || b || -1; - } else { - return $('#chatfaction time').first().data('timestamp') || -1; - } + return chat['_old'+(public ? 'Public' : 'Faction')+'Timestamp']; } window.chat.getNewestTimestamp = function(public) { - if(chat._needsClearing) return -1; - if(public) { - var a = $('#chatpublic time:last').data('timestamp'); - var b = $('#chatbot time:last').data('timestamp'); - if(a && b) return Math.max(a, b); - return a || b || -1; - } else { - return $('#chatfaction time').last().data('timestamp') || -1; - } + return chat['_new'+(public ? 'Public' : 'Faction')+'Timestamp']; } + window.chat._needsClearing = false; window.chat._oldBBox = null; window.chat.genPostData = function(public, getOlderMsgs) { @@ -40,7 +30,7 @@ window.chat.genPostData = function(public, getOlderMsgs) { var ne = b.getNorthEast(); var sw = b.getSouthWest(); var data = { - desiredNumItems: 10, + desiredNumItems: public ? 100 : 50, // public contains so much crap minLatE6: Math.round(sw.lat*1E6), minLngE6: Math.round(sw.lng*1E6), maxLatE6: Math.round(ne.lat*1E6), @@ -136,14 +126,17 @@ window.chat._displayedFactionGuids = []; window.chat.handleFaction = function(data, textStatus, jqXHR, isOldMsgs) { if(!data || !data.result) { window.failedRequestCount++; - return console.warn('Couldn’t get chat data. Waiting for next auto-refresh.'); + return console.warn('faction chat error. Waiting for next auto-refresh.'); } + chat._newFactionTimestamp = data.result[0][1]; + chat._oldFactionTimestamp = data.result[data.result.length-1][1]; + chat.clearIfRequired(); var msgs = ''; var prevTime = null; - $.each(data.result.reverse(), function(ind, json) { + $.each(data.result.reverse(), function(ind, json) { // oldest first! // avoid duplicates if(window.chat._displayedFactionGuids.indexOf(json[0]) !== -1) return; window.chat._displayedFactionGuids.push(json[0]); @@ -167,8 +160,9 @@ window.chat.handleFaction = function(data, textStatus, jqXHR, isOldMsgs) { // if there is a change of day between two requests, handle the // divider insertion here. if(isOldMsgs) { - var nextTime = new Date($('#chatfaction time:last').data('timestamp')).toLocaleDateString(); - if(prevTime && prevTime !== nextTime) + var ts = $('#chatfaction time:first').data('timestamp'); + var nextTime = new Date(ts).toLocaleDateString(); + if(prevTime && prevTime !== nextTime && ts) msgs += chat.renderDivider(nextTime); } @@ -179,24 +173,185 @@ window.chat.handleFaction = function(data, textStatus, jqXHR, isOldMsgs) { else c.append(msgs); - // If scrolled down completely, keep it that way so new messages can - // be seen easily. If scrolled up, only need to fix scroll position - // when old messages are added. New messages added at the bottom don’t - // change the view and enabling this would make the chat scroll down - // for every added message, even if the user wants to read old stuff. - if(scrollBefore === 0 || isOldMsgs) { - c.data('ignoreNextScroll', true); - c.scrollTop(c.scrollTop() + (scrollBottom(c)-scrollBefore)); - } - + chat.keepScrollPosition(c, scrollBefore, isOldMsgs); chat.needMoreMessages(); } + +// +// requesting public +// + +window.chat._requestOldPublicRunning = false; +window.chat.requestOldPublic = function(isRetry) { + if(chat._requestOldPublicRunning) return; + if(isIdle()) return renderUpdateStatus(); + chat._requestOldPublicRunning = true; + + var d = chat.genPostData(true, true); + var r = window.postAjax( + 'getPaginatedPlextsV2', + d, + chat.handleOldPublic, + isRetry + ? function() { window.chat._requestOldPublicRunning = false; } + : function() { window.chat.requestOldPublic(true) } + ); + + requests.add(r); +} + +window.chat._requestNewPublicRunning = false; +window.chat.requestNewPublic = function(isRetry) { + if(chat._requestNewPublicRunning) return; + if(window.isIdle()) return renderUpdateStatus(); + chat._requestNewPublicRunning = true; + + var d = chat.genPostData(true, false); + var r = window.postAjax( + 'getPaginatedPlextsV2', + d, + chat.handleNewPublic, + isRetry + ? function() { window.chat._requestNewPublicRunning = false; } + : function() { window.chat.requestNewPublic(true) } + ); + + requests.add(r); +} + + +// +// handle public +// + + +window.chat.handleOldPublic = function(data, textStatus, jqXHR) { + chat._requestOldPublicRunning = false; + chat.handlePublic(data, textStatus, jqXHR, true); +} + +window.chat.handleNewPublic = function(data, textStatus, jqXHR) { + chat._requestNewPublicRunning = false; + chat.handlePublic(data, textStatus, jqXHR, false); +} + +window.chat._displayedPublicGuids = []; +window.chat._displayedPlayerActionTime = {}; +window.chat.handlePublic = function(data, textStatus, jqXHR, isOldMsgs) { + if(!data || !data.result) { + window.failedRequestCount++; + return console.warn('public chat error. Waiting for next auto-refresh.'); + } + + chat._newPublicTimestamp = data.result[0][1]; + chat._oldPublicTimestamp = data.result[data.result.length-1][1]; + + chat.clearIfRequired(); + + var c = $('#chat > div:visible'); + var scrollBefore = scrollBottom(c); + + chat.handlePublicAutomated(data); + //chat.handlePublicPlayer(data, isOldMsgs); + + chat.keepScrollPosition(c, scrollBefore, isOldMsgs); + chat.needMoreMessages(); +} + + + + + +window.chat.handlePublicAutomated = function(data) { + $.each(data.result, function(ind, json) { // newest first! + var time = json[1]; + + // ignore player messages + var t = json[2].plext.plextType; + if(t !== 'SYSTEM_BROADCAST' && t !== 'SYSTEM_NARROWCAST') return true; + + var tmpmsg = '', nick = null, pguid, team; + + // each automated message is composed of many text chunks. loop + // over them to gather all necessary data. + $.each(json[2].plext.markup, function(ind, part) { + switch(part[0]) { + case 'PLAYER': + pguid = part[1].guid; + var lastAction = window.chat._displayedPlayerActionTime[pguid]; + // ignore older messages about player + if(lastAction && lastAction[0] > time) return false; + + nick = part[1].plain; + team = part[1].team === 'ALIENS' ? TEAM_ENL : TEAM_RES; + window.setPlayerName(pguid, nick); // free nick name resolves + if(ind > 0) tmpmsg += nick; // don’t repeat nick directly + break; + + case 'TEXT': + tmpmsg += part[1].plain; + break; + + case 'PORTAL': + var latlng = [part[1].latE6/1E6, part[1].lngE6/1E6]; + var js = 'window.zoomToAndShowPortal(\''+part[1].guid+'\', ['+latlng[0]+', '+latlng[1]+'])'; + tmpmsg += ''+part[1].name+''; + break; + } + }); + + // nick will only be set if we don’t have any info about that + // player yet. + if(nick) { + tmpmsg = chat.renderMsg(tmpmsg, nick, time, team); + window.chat._displayedPlayerActionTime[pguid] = [time, tmpmsg]; + }; + }); + + if(chat.getActive() === 'automated') + window.chat.renderAutomatedMsgsToBox(); +} + +window.chat.getActive = function() { + return $('#chatcontrols .active').text(); +} + +window.chat.renderAutomatedMsgsToBox = function() { + var x = window.chat._displayedPlayerActionTime; + // we don’t care about the GUIDs anymore + var vals = $.map(x, function(v, k) { return [v]; }); + // sort them old to new + vals = vals.sort(function(a, b) { return a[0]-b[0]; }); + + var prevTime = null; + var msgs = $.map(vals, function(v) { + var nowTime = new Date(v[0]).toLocaleDateString(); + if(prevTime && prevTime !== nowTime) + var val = chat.renderDivider(nowTime) + v[1]; + else + var val = v[1]; + + prevTime = nowTime; + return val; + }).join('\n'); + + $('#chatautomated').html(msgs); +} + + + + window.chat.clear = function() { console.log('clearing now'); window.chat._displayedFactionGuids = []; window.chat._displayedPublicGuids = []; - $('#chatfaction, #chatpublic, #chatbot').data('ignoreNextScroll', true).html(''); + window.chat._displayedPlayerActionTime = {}; + window.chat._oldFactionTimestamp = -1; + window.chat._newFactionTimestamp = -1; + window.chat._oldPublicTimestamp = -1; + window.chat._newPublicTimestamp = -1; + $('#chatfaction, #chatpublic, #chatautomated').data('ignoreNextScroll', true).html(''); } window.chat.clearIfRequired = function() { @@ -210,6 +365,9 @@ window.chat.toggle = function() { if(c.hasClass('expand')) { $('#chatcontrols a:first').text('expand'); c.removeClass('expand'); + var div = $('#chat > div:visible'); + div.data('ignoreNextScroll', true); + div.scrollTop(9999999999999); // scroll to bottom } else { $('#chatcontrols a:first').text('shrink'); c.addClass('expand'); @@ -220,7 +378,7 @@ window.chat.toggle = function() { window.chat.request = function() { console.log('refreshing chat'); chat.requestNewFaction(); - //~ chat.requestNewPublic(); + chat.requestNewPublic(); } // checks if there are enough messages in the selected chat tab and @@ -229,7 +387,7 @@ window.chat.needMoreMessages = function() { var activeChat = $('#chat > :visible'); if(scrollBottom(activeChat) !== 0 || activeChat.scrollTop() !== 0) return; console.log('no scrollbar in active chat, requesting more msgs'); - if($('#chatcontrols a:last.active')) + if($('#chatcontrols a:last.active').length) chat.requestOldFaction(); else chat.requestOldPublic(); @@ -254,6 +412,9 @@ window.chat.setup = function() { $('#chatcontrols, #chat, #chatinput').show(); $('#chatcontrols a:first').click(window.chat.toggle); + $('#chatcontrols a:not(:first)').click(window.chat.chooser); + + $('#chatinput').click(function() { $('#chatinput input').focus(); }); @@ -267,16 +428,19 @@ window.chat.setup = function() { if(scrollBottom(t) === 0) chat.requestNewFaction(); }); - $('#chatpublic, #chatbot').scroll(function() { + $('#chatpublic, #chatautomated').scroll(function() { var t = $(this); if(t.data('ignoreNextScroll')) return t.data('ignoreNextScroll', false); if(t.scrollTop() < 200) chat.requestOldPublic(); if(scrollBottom(t) === 0) chat.requestNewPublic(); }); - chat.requestNewFaction(); + chat.request(); window.addResumeFunction(chat.request); window.requests.addRefreshFunction(chat.request); + + var cls = PLAYER.team === 'ALIENS' ? 'enl' : 'res'; + $('#chatinput span').addClass(cls) } @@ -285,9 +449,56 @@ window.chat.renderMsg = function(msg, nick, time, team) { var tb = unixTimeToString(time, true); var t = ''; var s = 'style="color:'+COLORS[team]+'"'; + var title = nick.length >= 8 ? 'title="'+nick+'"' : ''; return '

'+t+''+nick+''+msg+'

'; } window.chat.renderDivider = function(text) { return '─ '+text+' ────────────────────────────────────────────────────────────────────────────'; } + +window.chat.chooser = function(event) { + var t = $(event.target); + var tt = t.text(); + var span = $('#chatinput span'); + + $('#chatcontrols .active').removeClass('active'); + t.addClass('active'); + + $('#chat > div').hide(); + + switch(tt) { + case 'faction': + span.css('color', ''); + span.text('tell faction:'); + $('#chatfaction').show(); + break; + + case 'public': + span.css('cssText', 'color: red !important'); + span.text('spam public:'); + $('#chatpublic').show(); + break; + + case 'automated': + span.css('cssText', 'color: #bbb !important'); + span.text('tell Jarvis:'); + chat.renderAutomatedMsgsToBox(); + $('#chatautomated').show(); + break; + } +} + + +// contains the logic to keep the correct scroll position. +window.chat.keepScrollPosition = function(box, scrollBefore, isOldMsgs) { + // If scrolled down completely, keep it that way so new messages can + // be seen easily. If scrolled up, only need to fix scroll position + // when old messages are added. New messages added at the bottom don’t + // change the view and enabling this would make the chat scroll down + // for every added message, even if the user wants to read old stuff. + if(scrollBefore === 0 || isOldMsgs) { + box.data('ignoreNextScroll', true); + box.scrollTop(box.scrollTop() + (scrollBottom(box)-scrollBefore)); + } +} diff --git a/code/map_data.js b/code/map_data.js index bfcd3a8a..3d97639e 100644 --- a/code/map_data.js +++ b/code/map_data.js @@ -81,7 +81,9 @@ window.handleDataResponse = function(data, textStatus, jqXHR) { if(selectedPortal == ent[0]) portalUpdateAvailable = true; portalsDetail[ent[0]] = ent[2]; - // immediately render portal details if selected by URL + // immediately render portal details if selected by URL. + // is also used internally to select a portal that may not have + // been loaded yet. See utils_misc#zoomToAndShowPortal. if(urlPortal && ent[0] == urlPortal && !selectedPortal) { urlPortal = null; // only pre-select it once window.renderPortalDetails(ent[0]); diff --git a/code/portal_detail_display.js b/code/portal_detail_display.js index 4a8699e6..09d9fbfe 100644 --- a/code/portal_detail_display.js +++ b/code/portal_detail_display.js @@ -4,8 +4,14 @@ // methods that highlight the portal in the map view. window.renderPortalDetails = function(guid) { - var update = selectPortal(guid); var d = portalsDetail[guid]; + if(!d) { + unselectOldPortal(); + urlPortal = guid; + return; + } + + var update = selectPortal(guid); // collect some random data that’s not worth to put in an own method var links = {incoming: 0, outgoing: 0}; @@ -106,3 +112,12 @@ window.selectPortal = function(guid) { return update; } + + +window.unselectOldPortal = function() { + var oldPortal = portals[selectedPortal]; + if(oldPortal) + oldPortal.setStyle({color: oldPortal.options.fillColor}); + selectedPortal = null; + $('#portaldetails').html(''); +} diff --git a/code/request_handling.js b/code/request_handling.js index 10209f49..bef601c1 100644 --- a/code/request_handling.js +++ b/code/request_handling.js @@ -22,8 +22,13 @@ window.requests.abort = function() { $.each(window.activeRequests, function(ind, actReq) { if(actReq) actReq.abort(); }); + window.activeRequests = []; window.failedRequestCount = 0; + window.chat._requestOldPublicRunning = false; + window.chat._requestNewPublicRunning = false; + window.chat._requestOldFactionRunning = false; + window.chat._requestNewFactionRunning = false; renderUpdateStatus(); } diff --git a/code/utils_misc.js b/code/utils_misc.js index 01acfbfb..8d6c7d71 100644 --- a/code/utils_misc.js +++ b/code/utils_misc.js @@ -119,3 +119,9 @@ window.scrollBottom = function(elm) { if(typeof elm === 'string') elm = $(elm); return elm.get(0).scrollHeight - elm.innerHeight() - elm.scrollTop(); } + + +window.zoomToAndShowPortal = function(guid, latlng) { + renderPortalDetails(guid); + map.setView(latlng, 17); +} diff --git a/json_examples/chat_public.js b/json_examples/chat_public.js index aa3e9bb5..5f48dcaa 100644 --- a/json_examples/chat_public.js +++ b/json_examples/chat_public.js @@ -2665,3 +2665,114 @@ ] ] } + + + + + + + + + + + + +{ + "gameBasket": { + "deletedEntityGuids": [ + + ], + "gameEntities": [ + + ], + "inventory": [ + + ] + }, + "result": [ + [ + "ca3de97465fb43f2b45ec34ca9cea2de.d", + 1359702662465, + { + "plext": { + "text": "Your L6 Resonator on Universit\u00e4tazeichen Heidelberg (Im Neuenheimer Feld 330, Campus Im Neunheimer Feld, 69120 Heidelberg, Germany) was destroyed by MohSai1r", + "markup": [ + [ + "TEXT", + { + "plain": "Your " + } + ], + [ + "TEXT", + { + "plain": "L6" + } + ], + [ + "TEXT", + { + "plain": " Resonator on " + } + ], + [ + "PORTAL", + { + "name": "Universit\u00e4tazeichen Heidelberg", + "plain": "Universit\u00e4tazeichen Heidelberg (Im Neuenheimer Feld 330, Campus Im Neunheimer Feld, 69120 Heidelberg, Germany)", + "team": "ALIENS", + "latE6": 49418303, + "address": "Im Neuenheimer Feld 330, Campus Im Neunheimer Feld, 69120 Heidelberg, Germany", + "lngE6": 8669490, + "guid": "b6cab1983f5d4795816e0d3ad3af3459.11" + } + ], + [ + "TEXT", + { + "plain": " was destroyed by " + } + ], + [ + "PLAYER", + { + "plain": "MohSai1r", + "guid": "a0c2e839783f4e889ca570e2cd5c7819.c", + "team": "RESISTANCE" + } + ] + ], + "plextType": "SYSTEM_NARROWCAST", + "team": "RESISTANCE" + } + } + ], + [ + "0b511244557349e6ad98a6d9b1332a3d.d", + 1359915357570, + { + "plext": { + "text": "xn37: x", + "markup": [ + [ + "SENDER", + { + "plain": "xn37: ", + "guid": "e015c2eecf2c424e82f375774c9e5446.c", + "team": "ALIENS" + } + ], + [ + "TEXT", + { + "plain": "x" + } + ] + ], + "plextType": "PLAYER_GENERATED", + "team": "ALIENS" + } + } + ] + ] +} diff --git a/main.js b/main.js index 55517f16..ada99d7e 100644 --- a/main.js +++ b/main.js @@ -52,7 +52,7 @@ document.getElementsByTagName('body')[0].innerHTML = '' + '' + '' + '