Merge branch 'master' into highlighter

This commit is contained in:
vita10gy
2013-04-30 22:58:09 -05:00
52 changed files with 4226 additions and 532 deletions

View File

@ -83,6 +83,26 @@ window.setupLayerChooserSelectOne = function() {
});
}
// Setup the function to record the on/off status of overlay layerGroups
window.setupLayerChooserStatusRecorder = function() {
// Record already added layerGroups
$.each(window.layerChooser._layers, function(ind, chooserEntry) {
if(!chooserEntry.overlay) return true;
var display = window.map.hasLayer(chooserEntry.layer);
window.updateDisplayedLayerGroup(chooserEntry.name, display);
});
// Record layerGroups change
window.map.on('layeradd layerremove', function(e) {
var id = L.stamp(e.layer);
var layerGroup = this._layers[id];
if (layerGroup && layerGroup.overlay) {
var display = (e.type === 'layeradd');
window.updateDisplayedLayerGroup(layerGroup.name, display);
}
}, window.layerChooser);
}
window.setupStyles = function() {
$('head').append('<style>' +
[ '#largepreview.enl img { border:2px solid '+COLORS[TEAM_ENL]+'; } ',
@ -206,14 +226,16 @@ window.setupMap = function() {
// update map hooks
map.on('movestart zoomstart', window.requests.abort);
map.on('moveend zoomend', function() { window.startRefreshTimeout(500) });
// run once on init
window.requestData();
window.startRefreshTimeout();
map.on('moveend zoomend', function() { console.log('map moveend'); window.startRefreshTimeout(ON_MOVE_REFRESH*1000) });
window.addResumeFunction(window.requestData);
window.requests.addRefreshFunction(window.requestData);
// start the refresh process with a small timeout, so the first data request happens quickly
// (the code originally called the request function directly, and triggered a normal delay for the nxt refresh.
// however, the moveend/zoomend gets triggered on map load, causing a duplicate refresh. this helps prevent that
window.startRefreshTimeout(ON_MOVE_REFRESH*1000);
};
// renders player details into the website. Since the player info is
@ -370,6 +392,7 @@ function boot() {
window.chat.setup();
window.setupQRLoadLib();
window.setupLayerChooserSelectOne();
window.setupLayerChooserStatusRecorder();
window.setupBackButton();
// read here ONCE, so the URL is only evaluated one time after the
// necessary data has been loaded.

View File

@ -1,96 +1,227 @@
// REDEEMING /////////////////////////////////////////////////////////
window.handleRedeemResponse = function(data, textStatus, jqXHR) {
if(data.error) {
var error = '';
if(data.error === 'ALREADY_REDEEMED') {
error = 'The passcode has already been redeemed.';
} else if(data.error === 'ALREADY_REDEEMED_BY_PLAYER') {
error = 'You have already redeemed this passcode.';
} else if(data.error === 'INVALID_PASSCODE') {
error = 'This passcode is invalid.';
} else {
error = 'There was a problem redeeming the passcode. Try again?';
/* Resource type names mapped to actual names and abbreviations.
* Add more here if necessary.
*/
window.REDEEM_RESOURCES = {
RES_SHIELD: {long: 'Portal Shield', short: 'SH'},
EMITTER_A: {long: 'Resonator', short: 'R'},
EMP_BURSTER: {long: 'XMP Burster', short: 'X'},
POWER_CUBE: {long: 'Power Cube', short: 'C'}
};
/* Redemption errors. Very self-explanatory.
*/
window.REDEEM_ERRORS = {
ALREADY_REDEEMED: 'The passcode has already been redeemed.',
ALREADY_REDEEMED_BY_PLAYER : 'You have already redeemed this passcode.',
INVALID_PASSCODE: 'This passcode is invalid.'
};
/* These are HTTP status codes returned by the redemption API.
* TODO: Move to another file? Use more generally across IITC?
*/
window.REDEEM_STATUSES = {
429: 'You have been rate-limited by the server. Wait a bit and try again.',
500: 'Internal server error'
};
/* Encouragement for people who got it in.
* Just for fun.
*/
window.REDEEM_ENCOURAGEMENT = [
"Passcode accepted!",
"Access granted.",
"Asset transfer in progress.",
"Well done, Agent.",
"Make the " + {'RESISTANCE' : 'Resistance', 'ALIENS' : 'Enlightened'}[PLAYER.team] + " proud!"
];
/* Redemption "handlers" handle decoding and formatting for rewards.
*
* Redemption "decoders" are used for returning the primary attribute (key) from
* different types of items. Pretty self-explanatory.
*
* Redemption "formatters" are used for formatting specific types of password rewards.
* Right now, Ingress has resourceWithLevels (leveled resources) and modResource (mods).
* Resources with levels have levels, and mods have rarity. Format them appropriately.
*/
window.REDEEM_HANDLERS = {
'resourceWithLevels' : {
decode: function(type, resource) {return resource.level;},
format: function(acquired, level) {
var prefix = '<span style="color: ' + (window.COLORS_LVL[level] || 'white') + ';">';
var suffix = '</span>';
return {
table: '<td>' + prefix + 'L' + level + suffix + '</td><td>' + acquired.name.long + ' [' + acquired.count + ']</td>',
html: acquired.count + '&#215;' + acquired.name.short + prefix + level + suffix,
plain: acquired.count + '@' + acquired.name.short + level
};
}
alert('<strong>' + data.error + '</strong>\n' + error);
} else if(data.result) {
var tblResult = $('<table class="redeem-result" />');
tblResult.append($('<tr><th colspan="2">Passcode accepted!</th></tr>'));
if(data.result.apAward)
tblResult.append($('<tr><td>+</td><td>' + data.result.apAward + 'AP</td></tr>'));
if(data.result.xmAward)
tblResult.append($('<tr><td>+</td><td>' + data.result.xmAward + 'XM</td></tr>'));
var resonators = {};
var bursts = {};
var shields = {};
var cubes = {};
for(var i in data.result.inventoryAward) {
var acquired = data.result.inventoryAward[i][2];
if(acquired.modResource) {
if(acquired.modResource.resourceType === 'RES_SHIELD') {
var rarity = acquired.modResource.rarity.split('_').map(function (i) {return i[0]}).join('');
if(!shields[rarity]) shields[rarity] = 0;
shields[rarity] += 1;
}
} else if(acquired.resourceWithLevels) {
if(acquired.resourceWithLevels.resourceType === 'EMITTER_A') {
var level = acquired.resourceWithLevels.level
if(!resonators[level]) resonators[level] = 0;
resonators[level] += 1;
} else if(acquired.resourceWithLevels.resourceType === 'EMP_BURSTER') {
var level = acquired.resourceWithLevels.level
if(!bursts[level]) bursts[level] = 0;
bursts[level] += 1;
} else if(acquired.resourceWithLevels.resourceType === 'POWER_CUBE') {
var level = acquired.resourceWithLevels.level
if(!cubes[level]) cubes[level] = 0;
cubes[level] += 1;
}
}
},
'modResource' : {
decode: function(type, resource) {return resource.rarity;},
format: function(acquired, rarity) {
var prefix = '<span style="color: ' + (window.COLORS_MOD[rarity] || 'white') + ';">';
var suffix = '</span>';
var abbreviation = rarity.split('_').map(function (i) {return i[0];}).join('');
return {
table: '<td>' + prefix + abbreviation + suffix + '</td><td>' + acquired.name.long + ' [' + acquired.count + ']</td>',
html: acquired.count + '&#215;' + prefix + abbreviation + suffix,
plain: acquired.count + '@' + abbreviation
};
}
},
'default' : {
decode: function(type, resource) {return 'UNKNOWN';},
format: function(acquired, group) {
return {
table: '<td>+</td><td>' + acquired.name.long + ' [' + acquired.count + ']</td>',
html: acquired.count + '&#215;' + acquired.name.short,
plain: acquired.count + '@' + acquired.name.short
};
}
$.each(resonators, function(lvl, count) {
var text = 'Resonator';
if(count >= 2) text += ' ('+count+')';
tblResult.append($('<tr ><td style="color: ' +window.COLORS_LVL[lvl]+ ';">L' +lvl+ '</td><td>' + text + '</td></tr>'));
});
$.each(bursts, function(lvl, count) {
var text = 'Xmp Burster';
if(count >= 2) text += ' ('+count+')';
tblResult.append($('<tr ><td style="color: ' +window.COLORS_LVL[lvl]+ ';">L' +lvl+ '</td><td>' + text + '</td></tr>'));
});
$.each(cubes, function(lvl, count) {
var text = 'Power Cube';
if(count >= 2) text += ' ('+count+')';
tblResult.append($('<tr ><td style="color: ' +window.COLORS_LVL[lvl]+ ';">L' +lvl+ '</td><td>' + text + '</td></tr>'));
});
$.each(shields, function(lvl, count) {
var text = 'Portal Shield';
if(count >= 2) text += ' ('+count+')';
tblResult.append($('<tr><td>'+lvl+'</td><td>'+text+'</td></tr>'));
});
alert(tblResult, true);
}
};
/* Redemption "hints" hint at what an unknown resource might be from its object properties.
*/
window.REDEEM_HINTS = {
level: 'resourceWithLevels',
rarity: 'modResource'
};
window.handleRedeemResponse = function(data, textStatus, jqXHR) {
var passcode = this.passcode, to_alert, to_log;
if(data.error) {
to_alert = '<strong>' + data.error + '</strong><br />' + (window.REDEEM_ERRORS[data.error] || 'There was a problem redeeming the passcode. Try again?');
to_log = '[ERROR] ' + data.error;
} else if(data.result) {
var encouragement = window.REDEEM_ENCOURAGEMENT[Math.floor(Math.random() * window.REDEEM_ENCOURAGEMENT.length)];
var payload = {};
var inferred = [];
var results = {
'table' : ['<th colspan="2" style="text-align: left;"><strong>' + encouragement + '</strong></th>'],
'html' : [],
'plain' : []
};
// Track frequencies and levels of items
$.each(data.result.inventoryAward, function (award_idx, award) {
var acquired = award[2], handler, type, key, name;
// The "what the heck is this item" heuristic
$.each(acquired, function (taxonomy, resource) {
if('resourceType' in resource) {
if(taxonomy in window.REDEEM_HANDLERS) {
// Cool. We know how to directly handle this item.
handler = {
functions: window.REDEEM_HANDLERS[taxonomy],
taxonomy: taxonomy,
processed_as: taxonomy
};
} else {
// Let's see if we can get a hint for how we should handle this.
$.each(resource, function (resource_key, resource_value) {
if(resource_key in window.REDEEM_HINTS) {
// We're not sure what this item is, but we can process it like another item
handler = {
functions: (window.REDEEM_HANDLERS[window.REDEEM_HINTS[resource_key]] || window.REDEEM_HANDLERS['default']),
taxonomy: taxonomy,
processed_as: window.REDEEM_HINTS[resource_key]
};
return false;
}
});
// Fall back to the default handler if necessary
handler = handler || {
functions: window.REDEEM_HANDLERS['default'],
taxonomy: taxonomy,
processed_as: 'default'
};
}
// Collect the data that we know
type = resource.resourceType;
key = handler.functions.decode(type, resource);
name = window.REDEEM_RESOURCES[type] || {long: type, short: type[0]};
// Decide if we inferred this resource
if(!(type in window.REDEEM_RESOURCES) || handler.taxonomy !== handler.processed_as) {
name.long += '*';
name.short += '*';
inferred.push({type: type, key: key, handler: handler});
}
return false;
}
});
// Update frequencies
payload[type] = payload[type] || {};
payload[type][key] = payload[type][key] || {};
payload[type][key].handler = payload[type][key].handler || handler;
payload[type][key].type = payload[type][key].type || type;
payload[type][key].name = payload[type][key].name || name;
payload[type][key].count = payload[type][key].count || 0;
payload[type][key].count += 1;
});
// Get AP and XM.
$.each([{label: 'AP', award: parseInt(data.result.apAward)}, {label: 'XM', award: parseInt(data.result.xmAward)}], function(idx, val) {
if(val.award > 0) {
results.table.push('<td>+</td><td>' + digits(val.award) + ' ' + val.label + '</td>');
results.html.push(val.award + ' ' + val.label);
results.plain.push(val.award + ' ' + val.label);
}
});
// Build the formatted results alphabetically
$.each(Object.keys(payload).sort(), function(type_idx, type) {
$.each(Object.keys(payload[type]).sort(), function(key_idx, key) {
var acquired = payload[type][key];
$.each(acquired.handler.functions.format(acquired, key), function(format, string) {
results[format].push(string);
});
});
});
// Let the user know if we had to guess
if (inferred.length > 0) {
results.table.push('<td style="font-family: monospace;">*</td><td style="font-family: monospace;">Guessed (check console)</td>');
$.each(inferred, function (idx, val) {
console.log(passcode +
' => [INFERRED] ' + val.type + ':' + val.key + ' :: ' +
val.handler.taxonomy + ' =~ ' + val.handler.processed_as);
});
}
// Add table footers
results.table.push('<td style="font-family: monospace;">&gt;</td><td><a href="javascript:alert(\'' +
escape('<span style="font-family: monospace;"><strong>' + encouragement + '</strong><br />' + results.html.join('/') + '</span>') +
'\', true);" style="font-family: monospace;">[plaintext]</a>');
// Display formatted versions in a table, plaintext, and the console log
to_alert = '<table class="redeem-result">' + results.table.map(function(a) {return '<tr>' + a + '</tr>';}).join("\n") + '</table>';
to_log = '[SUCCESS] ' + results.plain.join('/');
}
alert(to_alert, true);
console.log(passcode + ' => ' + to_log);
}
window.setupRedeem = function() {
$("#redeem").keypress(function(e) {
if((e.keyCode ? e.keyCode : e.which) != 13) return;
if((e.keyCode ? e.keyCode : e.which) !== 13) return;
var data = {passcode: $(this).val()};
window.postAjax('redeemReward', data, window.handleRedeemResponse,
function(response) {
var extra = '';
if(response && response.status) {
if(response.status === 429) {
extra = 'You have been rate-limited by the server. Wait a bit and try again.';
} else {
extra = 'The server indicated an error.';
}
extra += '\nResponse: HTTP <a href="http://httpstatus.es/' + response.status + '" alt="HTTP ' + response.status + '">' + response.status + '</a>.';
if(response.status) {
extra = (window.REDEEM_STATUSES[response.status] || 'The server indicated an error.') + ' (HTTP ' + response.status + ')';
} else {
extra = 'No status code was returned.';
}

View File

@ -8,6 +8,10 @@ window.failedRequestCount = 0;
window.requests = function() {}
//time of last refresh
window.requests._lastRefreshTime = 0;
window.requests._quickRefreshPending = false;
window.requests.add = function(ajax) {
window.activeRequests.push(ajax);
renderUpdateStatus();
@ -38,17 +42,19 @@ window.renderUpdateStatus = function() {
if(mapRunsUserAction)
t += 'paused during interaction';
else if(isIdle())
t += '<span style="color:red">Idle, not updating.</span>';
t += '<span style="color:#888">Idle, not updating.</span>';
else if(window.activeRequests.length > 0)
t += window.activeRequests.length + ' requests running.';
else if(window.requests._quickRefreshPending)
t += 'refreshing...';
else
t += 'Up to date.';
if(renderLimitReached())
t += ' <span style="color:red" class="help" title="Can only render so much before it gets unbearably slow. Not all entities are shown. Zoom in or increase the limit (search for MAX_DRAWN_*).">RENDER LIMIT</span> '
t += ' <span style="color:#f66" class="help" title="Can only render so much before it gets unbearably slow. Not all entities are shown. Zoom in or increase the limit (search for MAX_DRAWN_*).">RENDER LIMIT</span> '
if(window.failedRequestCount > 0)
t += ' <span style="color:red">' + window.failedRequestCount + ' failed</span>.'
t += ' <span style="color:#f66">' + window.failedRequestCount + ' failed</span>.'
t += '<br/>(';
var minlvl = getMinPortalLevel();
@ -78,19 +84,28 @@ window.startRefreshTimeout = function(override) {
if(refreshTimeout) clearTimeout(refreshTimeout);
var t = 0;
if(override) {
window.requests._quickRefreshPending = true;
t = override;
//ensure override can't cause too fast a refresh if repeatedly used (e.g. lots of scrolling/zooming)
timeSinceLastRefresh = new Date().getTime()-window.requests._lastRefreshTime;
if(timeSinceLastRefresh < 0) timeSinceLastRefresh = 0; //in case of clock adjustments
if(timeSinceLastRefresh < MINIMUM_OVERRIDE_REFRESH*1000)
t = (MINIMUM_OVERRIDE_REFRESH*1000-timeSinceLastRefresh);
} else {
window.requests._quickRefreshPending = false;
t = REFRESH*1000;
var adj = ZOOM_LEVEL_ADJ * (18 - window.map.getZoom());
if(adj > 0) t += adj*1000;
}
var next = new Date(new Date().getTime() + t).toLocaleTimeString();
console.log('planned refresh: ' + next);
console.log('planned refresh in ' + (t/1000) + ' seconds, at ' + next);
refreshTimeout = setTimeout(window.requests._callOnRefreshFunctions, t);
renderUpdateStatus();
}
window.requests._onRefreshFunctions = [];
window.requests._callOnRefreshFunctions = function() {
console.log('running refresh at ' + new Date().toLocaleTimeString());
startRefreshTimeout();
if(isIdle()) {
@ -101,6 +116,9 @@ window.requests._callOnRefreshFunctions = function() {
console.log('refreshing');
//store the timestamp of this refresh
window.requests._lastRefreshTime = new Date().getTime();
$.each(window.requests._onRefreshFunctions, function(ind, f) {
f();
});
@ -121,4 +139,4 @@ window.requests.isLastRequest = function(action) {
}
});
return result;
}
}

View File

@ -3,6 +3,7 @@
window.aboutIITC = function(){
var v = '@@BUILDNAME@@-@@BUILDDATE@@';
var attrib = '@@INCLUDEMD:ATTRIBUTION.md@@';
var contrib = '@@INCLUDEMD:CONTRIBS.md@@'
var a = ''
+ ' <div><b>About IITC</b></div> '
+ ' <div>Ingress Intel Total Conversion</div> '
@ -23,7 +24,9 @@ window.aboutIITC = function(){
+ ' <hr>'
+ ' <div>Version: ' + v + '</div>'
+ ' <hr>'
+ ' <div>' + attrib + '</div>';
+ ' <div>' + attrib + '</div>'
+ ' <hr>'
+ ' <div>' + contrib + '</div>';
alert(a, true, function() {$('.ui-dialog').removeClass('ui-dialog-aboutIITC');});
$('.ui-dialog').addClass('ui-dialog-aboutIITC');
}
@ -82,13 +85,14 @@ window.digits = function(d) {
// able arguments: http://api.jquery.com/jQuery.ajax/
// error: see above. Additionally it is logged if the request failed.
window.postAjax = function(action, data, success, error) {
data = JSON.stringify($.extend({method: 'dashboard.'+action}, data));
var post_data = JSON.stringify($.extend({method: 'dashboard.'+action}, data));
var remove = function(data, textStatus, jqXHR) { window.requests.remove(jqXHR); };
var errCnt = function(jqXHR) { window.failedRequestCount++; window.requests.remove(jqXHR); };
var result = $.ajax({
url: '/rpc/dashboard.'+action,
type: 'POST',
data: data,
data: post_data,
context: data,
dataType: 'json',
success: [remove, success],
error: error ? [errCnt, error] : errCnt,
@ -346,3 +350,25 @@ window.convertTextToTableMagic = function(text) {
window.calcTriArea = function(p) {
return Math.abs((p[0].lat*(p[1].lng-p[2].lng)+p[1].lat*(p[2].lng-p[0].lng)+p[2].lat*(p[0].lng-p[1].lng))/2);
}
// Update layerGroups display status to window.overlayStatus and cookie 'ingress.intelmap.layergroupdisplayed'
window.updateDisplayedLayerGroup = function(name, display) {
overlayStatus[name] = display;
writeCookie('ingress.intelmap.layergroupdisplayed', JSON.stringify(overlayStatus));
}
// Read layerGroup status from window.overlayStatus if it was added to map,
// read from cookie if it has not added to map yet.
// return true if both overlayStatus and cookie didn't have the record
window.isLayerGroupDisplayed = function(name) {
if(typeof(overlayStatus[name]) !== 'undefined') return overlayStatus[name];
var layersJSON = readCookie('ingress.intelmap.layergroupdisplayed');
if(!layersJSON) return true;
var layers = JSON.parse(layersJSON);
// keep latest overlayStatus
overlayStatus = $.extend(layers, overlayStatus);
if(typeof(overlayStatus[name]) === 'undefined') return true;
return overlayStatus[name];
}