rework chat handling completely
The old system was getting too complicated to add new features to. The new one should be easier to understand and will be explained below. This patch should fix #140 and fix #16. There are several places where new data requests may come from: - chat.needMoreMessages checks if we are scrolled too far up or there is no scrollbar. It then requests new messages. - scrolling up - switching the chat tab via chat.chooser - auto refresh - once on boot The latter two always request both types of chat. Faction and public are handled the same way. Public is later split into categories. I will explain the faction chat here because it’s easier. It starts in chat.requestFaction. This will initialize the query to the server for data. The exact query is determined by chat. genPostData. There can only be one faction chat request at a time. Clearing on map move is handled automatically in code/requests.js. Let’s assume the data query is successful. It is now passed to chat.handleFaction which runs some basic checks before the data is processed and stored in chat._factionData. This is done by chat. writeDataToHash. The hash keys are the message GUIDs to avoid duplicates. The hash values are an array of timestamp, processed message and other meta data. There is only one way to render faction chat, so data is directly handed to chat.renderFaction which immediately hands it to chat .renderData. renderData discards the GUIDs and sorts the values by their timestamp. It then iterates over the data to insert date break lines and finally renders the data in the DOM. It also does some magic to keep the correct scrolling position. Chat data will be cleared on map move or zoom. However, the display is not refreshed, so the old, invalid chat data is still displayed. Only once the data query is finished the data is rendered. The upside is that small map operations within your local area appear to never lose their chat data. Downside is that there’s invalid chat for some time when changing cities.
This commit is contained in:
parent
4c07fb12ae
commit
360f6f8336
458
code/chat.js
458
code/chat.js
@ -1,22 +1,14 @@
|
|||||||
window.chat = function() {};
|
window.chat = function() {};
|
||||||
|
|
||||||
window.chat._lastNicksForAutocomplete = [[], []];
|
|
||||||
window.chat.addNickForAutocomplete = function(nick, isFaction) {
|
|
||||||
var r = chat._lastNicksForAutocomplete[isFaction ? 0 : 1];
|
|
||||||
if(r.indexOf(nick) !== -1) return;
|
|
||||||
r.push(nick);
|
|
||||||
if(r.length >= 15)
|
|
||||||
r.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
window.chat.handleTabCompletion = function() {
|
window.chat.handleTabCompletion = function() {
|
||||||
var el = $('#chatinput input');
|
var el = $('#chatinput input');
|
||||||
var curPos = el.get(0).selectionStart;
|
var curPos = el.get(0).selectionStart;
|
||||||
var text = el.val();
|
var text = el.val();
|
||||||
var word = text.slice(0, curPos).replace(/.*\b([a-z0-9-_])/, '$1').toLowerCase();
|
var word = text.slice(0, curPos).replace(/.*\b([a-z0-9-_])/, '$1').toLowerCase();
|
||||||
|
|
||||||
var list = window.chat._lastNicksForAutocomplete;
|
var list = $('#chat > div:visible mark');
|
||||||
list = list[1].concat(list[0]);
|
list = list.map(function(ind, mark) { return $(mark).text(); } );
|
||||||
|
list = uniqueArray(list);
|
||||||
|
|
||||||
var nick = null;
|
var nick = null;
|
||||||
for(var i = 0; i < list.length; i++) {
|
for(var i = 0; i < list.length; i++) {
|
||||||
@ -43,27 +35,24 @@ window.chat.handleTabCompletion = function() {
|
|||||||
// timestamp and clear management
|
// timestamp and clear management
|
||||||
//
|
//
|
||||||
|
|
||||||
window.chat._oldFactionTimestamp = -1;
|
window.chat.getTimestamps = function(isFaction) {
|
||||||
window.chat._newFactionTimestamp = -1;
|
var storage = isFaction ? chat._factionData : chat._publicData;
|
||||||
window.chat._oldPublicTimestamp = -1;
|
return $.map(storage, function(v, k) { return [v[0]]; });
|
||||||
window.chat._newPublicTimestamp = -1;
|
|
||||||
|
|
||||||
window.chat.getOldestTimestamp = function(public) {
|
|
||||||
return chat['_old'+(public ? 'Public' : 'Faction')+'Timestamp'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.chat.getNewestTimestamp = function(public) {
|
window.chat.getOldestTimestamp = function(isFaction) {
|
||||||
return chat['_new'+(public ? 'Public' : 'Faction')+'Timestamp'];
|
var t = Math.min.apply(null, chat.getTimestamps(isFaction));
|
||||||
|
return t === Infinity ? -1 : t;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.chat.clearIfRequired = function(elm) {
|
window.chat.getNewestTimestamp = function(isFaction) {
|
||||||
if(!elm.data('needsClearing')) return;
|
var t = Math.max.apply(null, chat.getTimestamps(isFaction));
|
||||||
elm.data('ignoreNextScroll', true).data('needsClearing', false).html('');
|
return t === -1*Infinity ? -1 : t;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.chat._oldBBox = null;
|
window.chat._oldBBox = null;
|
||||||
window.chat.genPostData = function(public, getOlderMsgs) {
|
window.chat.genPostData = function(isFaction, getOlderMsgs) {
|
||||||
if(typeof public !== 'boolean') throw('Need to know if public or faction chat.');
|
if(typeof isFaction !== 'boolean') throw('Need to know if public or faction chat.');
|
||||||
|
|
||||||
chat._localRangeCircle.setLatLng(map.getCenter());
|
chat._localRangeCircle.setLatLng(map.getCenter());
|
||||||
var b = map.getBounds().extend(chat._localRangeCircle.getBounds());
|
var b = map.getBounds().extend(chat._localRangeCircle.getBounds());
|
||||||
@ -78,35 +67,30 @@ window.chat.genPostData = function(public, getOlderMsgs) {
|
|||||||
// need to reset these flags now because clearing will only occur
|
// need to reset these flags now because clearing will only occur
|
||||||
// after the request is finished – i.e. there would be one almost
|
// after the request is finished – i.e. there would be one almost
|
||||||
// useless request.
|
// useless request.
|
||||||
chat._displayedFactionGuids = [];
|
chat._factionData = {};
|
||||||
chat._displayedPublicGuids = [];
|
chat._publicData = {};
|
||||||
chat._displayedPlayerActionTime = {};
|
|
||||||
chat._oldFactionTimestamp = -1;
|
|
||||||
chat._newFactionTimestamp = -1;
|
|
||||||
chat._oldPublicTimestamp = -1;
|
|
||||||
chat._newPublicTimestamp = -1;
|
|
||||||
}
|
}
|
||||||
chat._oldBBox = bbs;
|
chat._oldBBox = bbs;
|
||||||
|
|
||||||
var ne = b.getNorthEast();
|
var ne = b.getNorthEast();
|
||||||
var sw = b.getSouthWest();
|
var sw = b.getSouthWest();
|
||||||
var data = {
|
var data = {
|
||||||
desiredNumItems: public ? CHAT_PUBLIC_ITEMS : CHAT_FACTION_ITEMS,
|
desiredNumItems: isFaction ? CHAT_FACTION_ITEMS : CHAT_PUBLIC_ITEMS ,
|
||||||
minLatE6: Math.round(sw.lat*1E6),
|
minLatE6: Math.round(sw.lat*1E6),
|
||||||
minLngE6: Math.round(sw.lng*1E6),
|
minLngE6: Math.round(sw.lng*1E6),
|
||||||
maxLatE6: Math.round(ne.lat*1E6),
|
maxLatE6: Math.round(ne.lat*1E6),
|
||||||
maxLngE6: Math.round(ne.lng*1E6),
|
maxLngE6: Math.round(ne.lng*1E6),
|
||||||
minTimestampMs: -1,
|
minTimestampMs: -1,
|
||||||
maxTimestampMs: -1,
|
maxTimestampMs: -1,
|
||||||
factionOnly: !public
|
factionOnly: isFaction
|
||||||
}
|
}
|
||||||
|
|
||||||
if(getOlderMsgs) {
|
if(getOlderMsgs) {
|
||||||
// ask for older chat when scrolling up
|
// ask for older chat when scrolling up
|
||||||
data = $.extend(data, {maxTimestampMs: chat.getOldestTimestamp(public)});
|
data = $.extend(data, {maxTimestampMs: chat.getOldestTimestamp(isFaction)});
|
||||||
} else {
|
} else {
|
||||||
// ask for newer chat
|
// ask for newer chat
|
||||||
var min = chat.getNewestTimestamp(public);
|
var min = chat.getNewestTimestamp(isFaction);
|
||||||
// the inital request will have both timestamp values set to -1,
|
// the inital request will have both timestamp values set to -1,
|
||||||
// thus we receive the newest desiredNumItems. After that, we will
|
// thus we receive the newest desiredNumItems. After that, we will
|
||||||
// only receive messages with a timestamp greater or equal to min
|
// only receive messages with a timestamp greater or equal to min
|
||||||
@ -130,322 +114,217 @@ window.chat.genPostData = function(public, getOlderMsgs) {
|
|||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// requesting faction
|
// faction
|
||||||
//
|
//
|
||||||
|
|
||||||
window.chat._requestOldFactionRunning = false;
|
window.chat._requestFactionRunning = false;
|
||||||
window.chat.requestOldFaction = function(isRetry) {
|
window.chat.requestFaction = function(getOlderMsgs, isRetry) {
|
||||||
if(chat._requestOldFactionRunning) return;
|
if(chat._requestFactionRunning && !isRetry) return;
|
||||||
if(isIdle()) return renderUpdateStatus();
|
if(isIdle()) return renderUpdateStatus();
|
||||||
chat._requestOldFactionRunning = true;
|
chat._requestFactionRunning = true;
|
||||||
|
|
||||||
var d = chat.genPostData(false, true);
|
var d = chat.genPostData(true, getOlderMsgs);
|
||||||
var r = window.postAjax(
|
var r = window.postAjax(
|
||||||
'getPaginatedPlextsV2',
|
'getPaginatedPlextsV2',
|
||||||
d,
|
d,
|
||||||
chat.handleOldFaction,
|
chat.handleFaction,
|
||||||
isRetry
|
isRetry
|
||||||
? function() { window.chat._requestOldFactionRunning = false; }
|
? function() { window.chat._requestFactionRunning = false; }
|
||||||
: function() { window.chat.requestOldFaction(true) }
|
: function() { window.chat.requestFaction(getOlderMsgs, true) }
|
||||||
);
|
|
||||||
|
|
||||||
requests.add(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.chat._requestNewFactionRunning = false;
|
|
||||||
window.chat.requestNewFaction = function(isRetry) {
|
|
||||||
if(chat._requestNewFactionRunning) return;
|
|
||||||
if(window.isIdle()) return renderUpdateStatus();
|
|
||||||
chat._requestNewFactionRunning = true;
|
|
||||||
|
|
||||||
var d = chat.genPostData(false, false);
|
|
||||||
var r = window.postAjax(
|
|
||||||
'getPaginatedPlextsV2',
|
|
||||||
d,
|
|
||||||
chat.handleNewFaction,
|
|
||||||
isRetry
|
|
||||||
? function() { window.chat._requestNewFactionRunning = false; }
|
|
||||||
: function() { window.chat.requestNewFaction(true) }
|
|
||||||
);
|
);
|
||||||
|
|
||||||
requests.add(r);
|
requests.add(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
window.chat._factionData = {};
|
||||||
// handle faction
|
window.chat.handleFaction = function(data, textStatus, jqXHR) {
|
||||||
//
|
chat._requestFactionRunning = false;
|
||||||
|
|
||||||
window.chat.handleOldFaction = function(data, textStatus, jqXHR) {
|
|
||||||
chat._requestOldFactionRunning = false;
|
|
||||||
chat.handleFaction(data, textStatus, jqXHR, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.chat.handleNewFaction = function(data, textStatus, jqXHR) {
|
|
||||||
chat._requestNewFactionRunning = false;
|
|
||||||
chat.handleFaction(data, textStatus, jqXHR, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
window.chat._displayedFactionGuids = [];
|
|
||||||
window.chat.handleFaction = function(data, textStatus, jqXHR, isOldMsgs) {
|
|
||||||
if(!data || !data.result) {
|
if(!data || !data.result) {
|
||||||
window.failedRequestCount++;
|
window.failedRequestCount++;
|
||||||
return console.warn('faction chat error. Waiting for next auto-refresh.');
|
return console.warn('faction chat error. Waiting for next auto-refresh.');
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = $('#chatfaction');
|
|
||||||
chat.clearIfRequired(c);
|
|
||||||
|
|
||||||
if(data.result.length === 0) return;
|
if(data.result.length === 0) return;
|
||||||
|
|
||||||
chat._newFactionTimestamp = data.result[0][1];
|
var old = chat.getOldestTimestamp(true);
|
||||||
chat._oldFactionTimestamp = data.result[data.result.length-1][1];
|
chat.writeDataToHash(data, chat._factionData, false);
|
||||||
|
var oldMsgsWereAdded = old !== chat.getOldestTimestamp(true);
|
||||||
|
|
||||||
var scrollBefore = scrollBottom(c);
|
window.chat.renderFaction(oldMsgsWereAdded);
|
||||||
chat.renderPlayerMsgsTo(true, data, isOldMsgs, chat._displayedFactionGuids);
|
|
||||||
chat.keepScrollPosition(c, scrollBefore, isOldMsgs);
|
|
||||||
|
|
||||||
if(data.result.length >= CHAT_FACTION_ITEMS) chat.needMoreMessages();
|
if(data.result.length >= CHAT_FACTION_ITEMS) chat.needMoreMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.chat.renderFaction = function(oldMsgsWereAdded) {
|
||||||
|
chat.renderData(chat._factionData, 'chatfaction', oldMsgsWereAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// requesting public
|
// public
|
||||||
//
|
//
|
||||||
|
|
||||||
window.chat._requestOldPublicRunning = false;
|
window.chat._requestPublicRunning = false;
|
||||||
window.chat.requestOldPublic = function(isRetry) {
|
window.chat.requestPublic = function(getOlderMsgs, isRetry) {
|
||||||
if(chat._requestOldPublicRunning) return;
|
if(chat._requestPublicRunning && !isRetry) return;
|
||||||
if(isIdle()) return renderUpdateStatus();
|
if(isIdle()) return renderUpdateStatus();
|
||||||
chat._requestOldPublicRunning = true;
|
chat._requestPublicRunning = true;
|
||||||
|
|
||||||
var d = chat.genPostData(true, true);
|
var d = chat.genPostData(false, getOlderMsgs);
|
||||||
var r = window.postAjax(
|
var r = window.postAjax(
|
||||||
'getPaginatedPlextsV2',
|
'getPaginatedPlextsV2',
|
||||||
d,
|
d,
|
||||||
chat.handleOldPublic,
|
chat.handlePublic,
|
||||||
isRetry
|
isRetry
|
||||||
? function() { window.chat._requestOldPublicRunning = false; }
|
? function() { window.chat._requestPublicRunning = false; }
|
||||||
: function() { window.chat.requestOldPublic(true) }
|
: function() { window.chat.requestPublic(getOlderMsgs, true) }
|
||||||
);
|
);
|
||||||
|
|
||||||
requests.add(r);
|
requests.add(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.chat._requestNewPublicRunning = false;
|
window.chat._publicData = {};
|
||||||
window.chat.requestNewPublic = function(isRetry) {
|
window.chat.handlePublic = function(data, textStatus, jqXHR) {
|
||||||
if(chat._requestNewPublicRunning) return;
|
chat._requestPublicRunning = false;
|
||||||
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) {
|
if(!data || !data.result) {
|
||||||
window.failedRequestCount++;
|
window.failedRequestCount++;
|
||||||
return console.warn('public chat error. Waiting for next auto-refresh.');
|
return console.warn('public chat error. Waiting for next auto-refresh.');
|
||||||
}
|
}
|
||||||
|
|
||||||
var ca = $('#chatautomated');
|
|
||||||
var cp = $('#chatpublic');
|
|
||||||
chat.clearIfRequired(ca);
|
|
||||||
chat.clearIfRequired(cp);
|
|
||||||
|
|
||||||
if(data.result.length === 0) return;
|
if(data.result.length === 0) return;
|
||||||
|
|
||||||
chat._newPublicTimestamp = data.result[0][1];
|
var old = chat.getOldestTimestamp(true);
|
||||||
chat._oldPublicTimestamp = data.result[data.result.length-1][1];
|
chat.writeDataToHash(data, chat._publicData, true);
|
||||||
|
var oldMsgsWereAdded = old !== chat.getOldestTimestamp(true);
|
||||||
|
|
||||||
|
switch(chat.getActive()) {
|
||||||
var scrollBefore = scrollBottom(ca);
|
case 'public': window.chat.renderPublic(oldMsgsWereAdded); break;
|
||||||
chat.handlePublicAutomated(data);
|
case 'compact': window.chat.renderCompact(oldMsgsWereAdded); break;
|
||||||
chat.keepScrollPosition(ca, scrollBefore, isOldMsgs);
|
case 'full': window.chat.renderFull(oldMsgsWereAdded); break;
|
||||||
|
}
|
||||||
|
|
||||||
var scrollBefore = scrollBottom(cp);
|
|
||||||
chat.renderPlayerMsgsTo(false, data, isOldMsgs, chat._displayedPublicGuids);
|
|
||||||
chat.keepScrollPosition(cp, scrollBefore, isOldMsgs);
|
|
||||||
|
|
||||||
if(data.result.length >= CHAT_PUBLIC_ITEMS) chat.needMoreMessages();
|
if(data.result.length >= CHAT_PUBLIC_ITEMS) chat.needMoreMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.chat.renderPublic = function(oldMsgsWereAdded) {
|
||||||
window.chat.handlePublicAutomated = function(data) {
|
// only keep player data
|
||||||
$.each(data.result, function(ind, json) { // newest first!
|
var data = $.map(chat._publicData, function(entry) {
|
||||||
var time = json[1];
|
if(!entry[1]) return [entry];
|
||||||
|
|
||||||
// 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 += '<a onclick="'+js+'" title="'+part[1].address+'" class="help">'+part[1].name+'</a>';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
chat.renderData(data, 'chatpublic', oldMsgsWereAdded);
|
||||||
// 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.renderAutomatedMsgsTo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.chat.renderAutomatedMsgsTo = function() {
|
window.chat.renderCompact = function(oldMsgsWereAdded) {
|
||||||
var x = window.chat._displayedPlayerActionTime;
|
var data = {};
|
||||||
// we don’t care about the GUIDs anymore
|
$.each(chat._publicData, function(guid, entry) {
|
||||||
var vals = $.map(x, function(v, k) { return [v]; });
|
// skip player msgs
|
||||||
// sort them old to new
|
if(!entry[1]) return true;
|
||||||
vals = vals.sort(function(a, b) { return a[0]-b[0]; });
|
var pguid = entry[3];
|
||||||
|
// ignore if player has newer data
|
||||||
var prevTime = null;
|
if(data[pguid] && data[pguid][0] > entry[0]) return true;
|
||||||
var msgs = $.map(vals, function(v) {
|
data[pguid] = entry;
|
||||||
var nowTime = new Date(v[0]).toLocaleDateString();
|
});
|
||||||
if(prevTime && prevTime !== nowTime)
|
// data keys are now player guids instead of message guids. However,
|
||||||
var val = chat.renderDivider(nowTime) + v[1];
|
// it is all the same to renderData.
|
||||||
else
|
chat.renderData(data, 'chatcompact', oldMsgsWereAdded);
|
||||||
var val = v[1];
|
|
||||||
|
|
||||||
prevTime = nowTime;
|
|
||||||
return val;
|
|
||||||
}).join('\n');
|
|
||||||
|
|
||||||
$('#chatautomated').html(msgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.chat.renderFull = function(oldMsgsWereAdded) {
|
||||||
|
// only keep automatically generated data
|
||||||
|
var data = $.map(chat._publicData, function(entry) {
|
||||||
|
if(entry[1]) return [entry];
|
||||||
|
});
|
||||||
|
chat.renderData(data, 'chatfull', oldMsgsWereAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// common
|
// common
|
||||||
//
|
//
|
||||||
|
|
||||||
|
window.chat.writeDataToHash = function(newData, storageHash, skipSecureMsgs) {
|
||||||
window.chat.renderPlayerMsgsTo = function(isFaction, data, isOldMsgs, dupCheckArr) {
|
$.each(newData.result, function(ind, json) {
|
||||||
var msgs = '';
|
|
||||||
var prevTime = null;
|
|
||||||
|
|
||||||
$.each(data.result.reverse(), function(ind, json) { // oldest first!
|
|
||||||
if(json[2].plext.plextType !== 'PLAYER_GENERATED') return true;
|
|
||||||
|
|
||||||
// avoid duplicates
|
// avoid duplicates
|
||||||
if(dupCheckArr.indexOf(json[0]) !== -1) return true;
|
if(json[0] in storageHash) return true;
|
||||||
dupCheckArr.push(json[0]);
|
|
||||||
|
|
||||||
var time = json[1];
|
var time = json[1];
|
||||||
var team = json[2].plext.team === 'ALIENS' ? TEAM_ENL : TEAM_RES;
|
var team = json[2].plext.team === 'ALIENS' ? TEAM_ENL : TEAM_RES;
|
||||||
var msg, nick, pguid;
|
var auto = json[2].plext.plextType !== 'PLAYER_GENERATED';
|
||||||
|
var msg = '', nick, pguid;
|
||||||
$.each(json[2].plext.markup, function(ind, markup) {
|
$.each(json[2].plext.markup, function(ind, markup) {
|
||||||
if(markup[0] === 'SENDER') {
|
switch(markup[0]) {
|
||||||
|
case 'SENDER': // user generated messages
|
||||||
nick = markup[1].plain.slice(0, -2); // cut “: ” at end
|
nick = markup[1].plain.slice(0, -2); // cut “: ” at end
|
||||||
pguid = markup[1].guid;
|
pguid = markup[1].guid;
|
||||||
window.setPlayerName(pguid, nick); // free nick name resolves
|
break;
|
||||||
if(!isOldMsgs) window.chat.addNickForAutocomplete(nick, isFaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(markup[0] === 'TEXT') {
|
case 'PLAYER': // automatically generated messages
|
||||||
msg = markup[1].plain.autoLink();
|
pguid = markup[1].guid;
|
||||||
msg = msg.replace(window.PLAYER['nickMatcher'], '<em>$1</em>');
|
nick = markup[1].plain;
|
||||||
}
|
team = markup[1].team === 'ALIENS' ? TEAM_ENL : TEAM_RES;
|
||||||
|
if(ind > 0) msg += nick; // don’t repeat nick directly
|
||||||
|
break;
|
||||||
|
|
||||||
if(!isFaction && markup[0] === 'SECURE') {
|
case 'TEXT':
|
||||||
|
var tmp = markup[1].plain.autoLink();
|
||||||
|
msg += tmp.replace(window.PLAYER['nickMatcher'], '<em>$1</em>');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'PORTAL':
|
||||||
|
var latlng = [markup[1].latE6/1E6, markup[1].lngE6/1E6];
|
||||||
|
var js = 'window.zoomToAndShowPortal(\''+markup[1].guid+'\', ['+latlng[0]+', '+latlng[1]+'])';
|
||||||
|
msg += '<a onclick="'+js+'" title="'+markup[1].address+'" class="help">'+markup[1].name+'</a>';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'SECURE':
|
||||||
|
if(skipSecureMsgs) {
|
||||||
nick = null;
|
nick = null;
|
||||||
return false; // aka break
|
return false; // breaks $.each
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!nick) return true; // aka next
|
if(!nick) return true; // aka next
|
||||||
|
|
||||||
var nowTime = new Date(time).toLocaleDateString();
|
// format: timestamp, autogenerated, HTML message, player guid
|
||||||
if(prevTime && prevTime !== nowTime)
|
storageHash[json[0]] = [json[1], auto, chat.renderMsg(msg, nick, time, team), pguid];
|
||||||
msgs += chat.renderDivider(nowTime);
|
|
||||||
|
|
||||||
msgs += chat.renderMsg(msg, nick, time, team);
|
window.setPlayerName(pguid, nick); // free nick name resolves
|
||||||
prevTime = nowTime;
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// renders data from the data-hash to the element defined by the given
|
||||||
|
// ID. Set 3rd argument to true if it is likely that old data has been
|
||||||
|
// added. Latter is only required for scrolling.
|
||||||
|
window.chat.renderData = function(data, element, likelyWereOldMsgs) {
|
||||||
|
var elm = $('#'+element);
|
||||||
|
if(elm.is(':hidden')) return;
|
||||||
|
|
||||||
|
// discard guids and sort old to new
|
||||||
|
var vals = $.map(data, function(v, k) { return [v]; });
|
||||||
|
vals = vals.sort(function(a, b) { return a[0]-b[0]; });
|
||||||
|
|
||||||
|
// render to string with date separators inserted
|
||||||
|
var msgs = '';
|
||||||
|
var prevTime = null;
|
||||||
|
$.each(vals, function(ind, msg) {
|
||||||
|
var nextTime = new Date(msg[0]).toLocaleDateString();
|
||||||
|
if(prevTime && prevTime !== nextTime)
|
||||||
|
msgs += chat.renderDivider(nextTime);
|
||||||
|
msgs += msg[2];
|
||||||
|
prevTime = nextTime;
|
||||||
});
|
});
|
||||||
|
|
||||||
var addTo = isFaction ? $('#chatfaction') : $('#chatpublic');
|
var scrollBefore = scrollBottom(elm);
|
||||||
|
elm.html(msgs);
|
||||||
// if there is a change of day between two requests, handle the
|
chat.keepScrollPosition(elm, scrollBefore, likelyWereOldMsgs);
|
||||||
// divider insertion here.
|
|
||||||
if(isOldMsgs) {
|
|
||||||
var ts = addTo.find('time:first').data('timestamp');
|
|
||||||
var nextTime = new Date(ts).toLocaleDateString();
|
|
||||||
if(prevTime && prevTime !== nextTime && ts)
|
|
||||||
msgs += chat.renderDivider(nextTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isOldMsgs)
|
|
||||||
addTo.prepend(msgs);
|
|
||||||
else
|
|
||||||
addTo.append(msgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window.chat.renderDivider = function(text) {
|
window.chat.renderDivider = function(text) {
|
||||||
return '<summary>─ '+text+' ────────────────────────────────────────────────────────────────────────────</summary>';
|
return '<summary>─ '+text+' ───────────────────────────────────────────────────────────</summary>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -486,25 +365,29 @@ window.chat.toggle = function() {
|
|||||||
|
|
||||||
window.chat.request = function() {
|
window.chat.request = function() {
|
||||||
console.log('refreshing chat');
|
console.log('refreshing chat');
|
||||||
chat.requestNewFaction();
|
chat.requestFaction(false);
|
||||||
chat.requestNewPublic();
|
chat.requestPublic(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// checks if there are enough messages in the selected chat tab and
|
// checks if there are enough messages in the selected chat tab and
|
||||||
// loads more if not.
|
// loads more if not.
|
||||||
window.chat.needMoreMessages = function() {
|
window.chat.needMoreMessages = function() {
|
||||||
var activeChat = $('#chat > :visible');
|
var activeTab = chat.getActive();
|
||||||
if(scrollBottom(activeChat) !== 0 || activeChat.scrollTop() !== 0) return;
|
|
||||||
var activeTab = $('#chatcontrols .active').text();
|
|
||||||
if(activeTab === 'debug') return;
|
if(activeTab === 'debug') return;
|
||||||
|
|
||||||
console.log('no scrollbar in active chat, requesting more msgs');
|
var activeChat = $('#chat > :visible');
|
||||||
|
|
||||||
|
var hasScrollbar = scrollBottom(activeChat) !== 0 || activeChat.scrollTop() !== 0;
|
||||||
|
var nearTop = activeChat.scrollTop() <= CHAT_REQUEST_SCROLL_TOP;
|
||||||
|
if(hasScrollbar && !nearTop) return;
|
||||||
|
|
||||||
|
console.log('No scrollbar or near top in active chat. Requesting more data.');
|
||||||
|
|
||||||
if(activeTab === 'faction')
|
if(activeTab === 'faction')
|
||||||
chat.requestOldFaction();
|
chat.requestFaction(true);
|
||||||
else
|
else
|
||||||
chat.requestOldPublic();
|
chat.requestPublic(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -525,26 +408,26 @@ window.chat.chooser = function(event) {
|
|||||||
case 'faction':
|
case 'faction':
|
||||||
span.css('color', '');
|
span.css('color', '');
|
||||||
span.text('tell faction:');
|
span.text('tell faction:');
|
||||||
elm = $('#chatfaction');
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'public':
|
case 'public':
|
||||||
span.css('cssText', 'color: red !important');
|
span.css('cssText', 'color: red !important');
|
||||||
span.text('broadcast:');
|
span.text('broadcast:');
|
||||||
elm = $('#chatpublic');
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'automated':
|
case 'compact':
|
||||||
|
case 'full':
|
||||||
span.css('cssText', 'color: #bbb !important');
|
span.css('cssText', 'color: #bbb !important');
|
||||||
span.text('tell Jarvis:');
|
span.text('tell Jarvis:');
|
||||||
chat.renderAutomatedMsgsTo();
|
|
||||||
elm = $('#chatautomated');
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw('chat.chooser was asked to handle unknown button: ' + tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!elm) throw('chat button handled by chat.chooser, yet it is null');
|
var elm = $('#chat' + tt);
|
||||||
|
|
||||||
elm.show();
|
elm.show();
|
||||||
|
eval('chat.render' + tt.capitalize() + '(false);');
|
||||||
if(elm.data('needsScrollTop')) {
|
if(elm.data('needsScrollTop')) {
|
||||||
elm.data('ignoreNextScroll', true);
|
elm.data('ignoreNextScroll', true);
|
||||||
elm.scrollTop(elm.data('needsScrollTop'));
|
elm.scrollTop(elm.data('needsScrollTop'));
|
||||||
@ -588,7 +471,7 @@ window.chat.setup = function() {
|
|||||||
|
|
||||||
$('#chatcontrols a:first').click(window.chat.toggle);
|
$('#chatcontrols a:first').click(window.chat.toggle);
|
||||||
$('#chatcontrols a').each(function(ind, elm) {
|
$('#chatcontrols a').each(function(ind, elm) {
|
||||||
if($.inArray($(elm).text(), ['automated', 'public', 'faction']) !== -1)
|
if($.inArray($(elm).text(), ['full', 'compact', 'public', 'faction']) !== -1)
|
||||||
$(elm).click(window.chat.chooser);
|
$(elm).click(window.chat.chooser);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -603,15 +486,15 @@ window.chat.setup = function() {
|
|||||||
$('#chatfaction').scroll(function() {
|
$('#chatfaction').scroll(function() {
|
||||||
var t = $(this);
|
var t = $(this);
|
||||||
if(t.data('ignoreNextScroll')) return t.data('ignoreNextScroll', false);
|
if(t.data('ignoreNextScroll')) return t.data('ignoreNextScroll', false);
|
||||||
if(t.scrollTop() < 200) chat.requestOldFaction();
|
if(t.scrollTop() < CHAT_REQUEST_SCROLL_TOP) chat.requestFaction(true);
|
||||||
if(scrollBottom(t) === 0) chat.requestNewFaction();
|
if(scrollBottom(t) === 0) chat.requestFaction(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#chatpublic, #chatautomated').scroll(function() {
|
$('#chatpublic, #chatfull, #chatcompact').scroll(function() {
|
||||||
var t = $(this);
|
var t = $(this);
|
||||||
if(t.data('ignoreNextScroll')) return t.data('ignoreNextScroll', false);
|
if(t.data('ignoreNextScroll')) return t.data('ignoreNextScroll', false);
|
||||||
if(t.scrollTop() < 200) chat.requestOldPublic();
|
if(t.scrollTop() < CHAT_REQUEST_SCROLL_TOP) chat.requestPublic(true);
|
||||||
if(scrollBottom(t) === 0) chat.requestNewPublic();
|
if(scrollBottom(t) === 0) chat.requestPublic(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
chat.request();
|
chat.request();
|
||||||
@ -670,7 +553,8 @@ window.chat.setupPosting = function() {
|
|||||||
|
|
||||||
window.chat.postMsg = function() {
|
window.chat.postMsg = function() {
|
||||||
var c = chat.getActive();
|
var c = chat.getActive();
|
||||||
if(c === 'automated') return alert('Jarvis: A strange game. The only winning move is not to play. How about a nice game of chess?');
|
if(c === 'full' || c === 'compact')
|
||||||
|
return alert('Jarvis: A strange game. The only winning move is not to play. How about a nice game of chess?');
|
||||||
|
|
||||||
var msg = $.trim($('#chatinput input').val());
|
var msg = $.trim($('#chatinput input').val());
|
||||||
if(!msg || msg === '') return;
|
if(!msg || msg === '') return;
|
||||||
@ -691,7 +575,7 @@ window.chat.postMsg = function() {
|
|||||||
window.postAjax('sendPlext', data,
|
window.postAjax('sendPlext', data,
|
||||||
function(response) {
|
function(response) {
|
||||||
if(response.error) alert(errMsg);
|
if(response.error) alert(errMsg);
|
||||||
if(public) chat.requestNewPublic(); else chat.requestNewFaction(); },
|
if(public) chat.requestPublic(false); else chat.requestFaction(false); },
|
||||||
function() {
|
function() {
|
||||||
alert(errMsg);
|
alert(errMsg);
|
||||||
}
|
}
|
||||||
|
@ -25,10 +25,8 @@ window.requests.abort = function() {
|
|||||||
|
|
||||||
window.activeRequests = [];
|
window.activeRequests = [];
|
||||||
window.failedRequestCount = 0;
|
window.failedRequestCount = 0;
|
||||||
window.chat._requestOldPublicRunning = false;
|
window.chat._requestPublicRunning = false;
|
||||||
window.chat._requestNewPublicRunning = false;
|
window.chat._requestFactionRunning = false;
|
||||||
window.chat._requestOldFactionRunning = false;
|
|
||||||
window.chat._requestNewFactionRunning = false;
|
|
||||||
|
|
||||||
renderUpdateStatus();
|
renderUpdateStatus();
|
||||||
}
|
}
|
||||||
|
12
main.js
12
main.js
@ -62,12 +62,14 @@ document.getElementsByTagName('head')[0].innerHTML = ''
|
|||||||
document.getElementsByTagName('body')[0].innerHTML = ''
|
document.getElementsByTagName('body')[0].innerHTML = ''
|
||||||
+ '<div id="map">Loading, please wait</div>'
|
+ '<div id="map">Loading, please wait</div>'
|
||||||
+ '<div id="chatcontrols" style="display:none">'
|
+ '<div id="chatcontrols" style="display:none">'
|
||||||
+ ' <a><span class="toggle expand"></span></a><a>automated</a><a>public</a><a class="active">faction</a>'
|
+ ' <a><span class="toggle expand"></span></a>'
|
||||||
|
+ '<a>full</a><a>compact</a><a>public</a><a class="active">faction</a>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '<div id="chat" style="display:none">'
|
+ '<div id="chat" style="display:none">'
|
||||||
+ ' <div id="chatfaction"></div>'
|
+ ' <div id="chatfaction"></div>'
|
||||||
+ ' <div id="chatpublic"></div>'
|
+ ' <div id="chatpublic"></div>'
|
||||||
+ ' <div id="chatautomated"></div>'
|
+ ' <div id="chatcompact"></div>'
|
||||||
|
+ ' <div id="chatfull"></div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '<form id="chatinput" style="display:none"><time></time><span>tell faction:</span><input type="text"/></form>'
|
+ '<form id="chatinput" style="display:none"><time></time><span>tell faction:</span><input type="text"/></form>'
|
||||||
+ '<a id="sidebartoggle"><span class="toggle close"></span></a>'
|
+ '<a id="sidebartoggle"><span class="toggle close"></span></a>'
|
||||||
@ -115,8 +117,10 @@ var CHAT_MIN_RANGE = 6;
|
|||||||
var VIEWPORT_PAD_RATIO = 0.3;
|
var VIEWPORT_PAD_RATIO = 0.3;
|
||||||
|
|
||||||
// how many items to request each query
|
// how many items to request each query
|
||||||
var CHAT_PUBLIC_ITEMS = 200
|
var CHAT_PUBLIC_ITEMS = 200;
|
||||||
var CHAT_FACTION_ITEMS = 50
|
var CHAT_FACTION_ITEMS = 50;
|
||||||
|
// how many pixels to the top before requesting new data
|
||||||
|
var CHAT_REQUEST_SCROLL_TOP = 200;
|
||||||
|
|
||||||
// Leaflet will get very slow for MANY items. It’s better to display
|
// Leaflet will get very slow for MANY items. It’s better to display
|
||||||
// only some instead of crashing the browser.
|
// only some instead of crashing the browser.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user