pokemon-showdown-client/js/utilichart.js
Cathy J. Fitzpatrick d82b5e6b7b Rename sanitisation and escaping functions
- `window.sanitize` is now `Tools.escapeHTML`
- `window.unsanitize` is now `Tools.unescapeHTML`
- `window.jsEscape` is now `Tools.escapeQuotes`
- `window.htmlSanitize' is now `Tools.sanitizeHTML`
- `battle.escape` has been eliminated and replaced by calls
   to `Tools.escapeHTML`
2013-04-14 21:49:51 -06:00

563 lines
15 KiB
JavaScript

function BattleChart()
{
var self = this;
this.firstResult = '';
this.exactResult = false;
// I know, I know, lots of memory
// but these are arrays of pointers, so it's not _horrible_
// and this let me cache sorting
this.pokemon = [];
for (var i in BattlePokedex)
{
BattlePokedex[i].name = BattlePokedex[i].species;
this.pokemon.push(BattlePokedex[i]);
}
this.items = [];
for (var i in BattleItems)
{
this.items.push(BattleItems[i]);
}
this.abilities = [];
for (var i in BattleAbilities)
{
this.abilities.push(BattleAbilities[i]);
}
this.moves = [];
for (var i in BattleMovedex)
{
this.moves.push(BattleMovedex[i]);
}
this.lastPokemonSort = null;
this.lastItemSort = null;
this.lastAbilitySort = null;
this.lastMoveSort = null;
this.illegalBuckets = {
'Illegal': 'Illegal'
};
this.selectCallback = null;
this.select = function(x) {
if (self.selectCallback) self.selectCallback(x);
};
this.row = function(thing, attrs, match, isFirst) {
if (isFirst)
{
self.firstResult = thing.name;
}
attrs = attrs || '';
switch (match.thingType)
{
case 'pokemon':
return self.pokemonRow(thing, attrs, match, isFirst);
break;
case 'item':
return self.itemRow(thing, attrs, match, isFirst);
break;
case 'ability':
return self.abilityRow(thing, attrs, match, isFirst);
break;
case 'move':
return self.moveRow(thing, attrs, match, isFirst);
break;
}
};
this.pokemonRow = function(pokemon, attrs, match, isFirst) {
var text = '<li class="result'+(isFirst?' firstresult':'')+'"><a'+attrs+' onclick="Chart.select(\''+Tools.escapeHTML(pokemon.species,true)+'\')">';
text += '<span class="col numcol">'+(pokemon.num)+'</span> ';
var name = Tools.escapeHTML(pokemon.name);
if (pokemon.forme && pokemon.baseSpecies) name = pokemon.baseSpecies;
if (match.name)
{
name = name.substr(0, match.name.start)+'<b>'+name.substr(match.name.start, match.name.end-match.name.start)+'</b>'+name.substr(match.name.end);
}
if (pokemon.forme && pokemon.baseSpecies)
{
if (match.name && match.name.end > pokemon.baseSpecies.length)
{
if (match.name.start < pokemon.baseSpecies.length+1) match.name.start = pokemon.baseSpecies.length+1;
name += '<small>-'+pokemon.forme.substr(0, match.name.start-(pokemon.baseSpecies.length+1))+'<b>'+pokemon.name.substr(match.name.start, match.name.end-match.name.start)+'</b>'+pokemon.name.substr(match.name.end)+'</small>';
}
else
{
name += '<small>-'+pokemon.forme+'</small>';
}
}
/* if (match.name)
{
name = name.substr(0, match.name.start)+'<b>'+name.substr(match.name.start, match.name.end-match.name.start)+'</b>'+name.substr(match.name.end);
} */
text += '<span class="col iconcol">';
text += '<span style="'+Tools.getIcon(pokemon)+'"></span>';
text += '</span> ';
text += '<span class="col pokemonnamecol" style="white-space:nowrap">'+name+'</span> ';
if (self.illegalBuckets[match.bucket])
{
text += '<span class="col illegalcol"><em>'+self.illegalBuckets[match.bucket]+'</em></span> ';
text += '</a></li>';
return text;
}
text += '<span class="col typecol">';
for (var i=0; i<pokemon.types.length; i++)
{
text += Tools.getTypeIcon(pokemon.types[i], (match.type&&match.type[i]));
}
text += '</span> ';
text += '<span style="float:left;min-height:26px">';
if (pokemon.abilities['1'])
{
text += '<span class="col twoabilitycol">';
}
else
{
text += '<span class="col abilitycol">';
}
for (var i in pokemon.abilities)
{
var ability = pokemon.abilities[i];
if (!ability) continue;
if (i === '1') text += '<br />';
if (match.ability && match.ability[i])
{
ability = ability.substr(0, match.ability[i].start)+'<b>'+ability.substr(match.ability[i].start, match.ability[i].end-match.ability[i].start)+'</b>'+ability.substr(match.ability[i].end);
}
if (i == 'DW') ability = '</span><span class="col abilitycol"><em>'+ability+'</em>';
text += ability;
}
if (!pokemon.abilities['DW']) text += '</span><span class="col abilitycol">';
text += '</span>';
text += '</span>';
text += '<span style="float:left;min-height:26px">';
text += '<span class="col statcol"><em>HP</em><br />'+pokemon.baseStats.hp+'</span> ';
text += '<span class="col statcol"><em>Atk</em><br />'+pokemon.baseStats.atk+'</span> ';
text += '<span class="col statcol"><em>Def</em><br />'+pokemon.baseStats.def+'</span> ';
text += '<span class="col statcol"><em>SpA</em><br />'+pokemon.baseStats.spa+'</span> ';
text += '<span class="col statcol"><em>SpD</em><br />'+pokemon.baseStats.spd+'</span> ';
text += '<span class="col statcol"><em>Spe</em><br />'+pokemon.baseStats.spe+'</span> ';
var bst = 0;
for (i in pokemon.baseStats) bst += pokemon.baseStats[i];
text += '<span class="col bstcol"><em>BST<br />'+bst+'</em></span> ';
text += '</span>';
text += '</a></li>';
return text;
};
this.itemRow = function(item, attrs, match, isFirst) {
var text = '<li class="result'+(isFirst?' firstresult':'')+'"><a'+attrs+' onclick="Chart.select(\''+Tools.escapeHTML(item.name,true)+'\')">';
var url = item.name.toLowerCase().replace(/ /g, '-').replace(/[^a-z-]+/g, '');
url = '/sprites/itemicons/'+url+'.png';
text += '<span class="col itemiconcol">';
text += '<span style="'+Tools.getItemIcon(item)+'"></span>';
text += '</span> ';
var name = Tools.escapeHTML(item.name);
if (match.name)
{
name = name.substr(0, match.name.start)+'<b>'+name.substr(match.name.start, match.name.end-match.name.start)+'</b>'+name.substr(match.name.end);
}
text += '<span class="col namecol">'+name+'</span> ';
if (self.illegalBuckets[match.bucket])
{
text += '<span class="col illegalcol"><em>'+self.illegalBuckets[match.bucket]+'</em></span> ';
text += '</a></li>';
return text;
}
text += '<span class="col itemdesccol">'+Tools.escapeHTML(item.shortDesc || item.desc)+'</span> ';
text += '</a></li>';
return text;
};
this.abilityRow = function(ability, attrs, match, isFirst) {
var text = '<li class="result'+(isFirst?' firstresult':'')+'"><a'+attrs+' onclick="Chart.select(\''+Tools.escapeHTML(ability.name,true)+'\')">';
var name = Tools.escapeHTML(ability.name);
if (match.name)
{
name = name.substr(0, match.name.start)+'<b>'+name.substr(match.name.start, match.name.end-match.name.start)+'</b>'+name.substr(match.name.end);
}
text += '<span class="col namecol">'+name+'</span> ';
if (self.illegalBuckets[match.bucket])
{
text += '<span class="col illegalcol"><em>'+self.illegalBuckets[match.bucket]+'</em></span> ';
text += '</a></li>';
return text;
}
text += '<span class="col abilitydesccol">'+Tools.escapeHTML(ability.shortDesc || ability.desc)+'</span> ';
text += '</a></li>';
return text;
};
this.moveRow = function(move, attrs, match, isFirst) {
var text = '<li class="result'+(isFirst?' firstresult':'')+'"><a'+attrs+' onclick="Chart.select(\''+Tools.escapeHTML(move.name,true)+'\')">';
var name = Tools.escapeHTML(move.name);
var hplen = 'Hidden Power'.length;
if (name.substr(0, hplen) === 'Hidden Power') name = 'Hidden Power';
if (match.name)
{
name = name.substr(0, match.name.start)+'<b>'+name.substr(match.name.start, match.name.end-match.name.start)+'</b>'+name.substr(match.name.end);
}
if (move.name.substr(0, hplen) === 'Hidden Power')
{
if (match.name && match.name.end > hplen)
{
if (match.name.start < hplen+1) match.name.start = hplen+1;
name += '<small> '+move.name.substr(hplen+1, match.name.start-(hplen+1))+'<b>'+move.name.substr(match.name.start, match.name.end-match.name.start)+'</b>'+move.name.substr(match.name.end)+'</small>';
}
else
{
name += '<small> '+move.name.substr(hplen+1)+'</small>';
}
}
text += '<span class="col movenamecol">'+name+'</span> ';
if (self.illegalBuckets[match.bucket])
{
text += '<span class="col illegalcol"><em>'+self.illegalBuckets[match.bucket]+'</em></span> ';
text += '</a></li>';
return text;
}
text += '<span class="col typecol">';
text += Tools.getTypeIcon(move.type, match.type);
text += '<img src="' + Tools.resourcePrefix + 'sprites/categories/'+move.category+'.png" alt="'+move.category+'" height="14" width="32"'+(match.category?' class="b"':'')+' />';
text += '</span> ';
text += '<span class="col labelcol">'+(move.category!=='Status'?('<em>Power</em><br />'+(move.basePower||'&mdash;')):'')+'</span> ';
text += '<span class="col widelabelcol"><em>Accuracy</em><br />'+(move.accuracy && move.accuracy!==true?move.accuracy+'%':'&mdash;')+'</span> ';
text += '<span class="col movedesccol">'+Tools.escapeHTML(move.shortDesc || move.desc)+'</span> ';
text += '</a></li>';
return text;
};
this.chart = function(searchTerm, type, init, thisArrange, thisSort) {
var chartData = {
exact: {},
start: {},
contains: {},
illegalstart: {},
illegalcontains: {},
fullstart: {},
illegalfullstart: {},
other: {}
};
thisArrange = thisArrange || self.defaultArrange;
thisSort = thisSort || self.defaultSort;
self.firstResult = '';
self.exactResult = false;
if (!searchTerm) searchTerm = '';
else searchTerm = searchTerm.toLowerCase();
var buckets = thisArrange();
var things = [];
switch (type)
{
case 'pokemon':
if (thisSort !== self.lastPokemonSort)
{
self.pokemon.sort(thisSort);
self.lastPokemonSort = thisSort;
}
things = self.pokemon;
break;
case 'item':
if (thisSort !== self.lastItemSort)
{
self.items.sort(thisSort);
self.lastItemSort = thisSort;
}
things = self.items;
break;
case 'ability':
if (thisSort !== self.lastAbilitySort)
{
self.abilities.sort(thisSort);
self.lastAbilitySort = thisSort;
}
things = self.abilities;
break;
case 'move':
if (thisSort !== self.lastMoveSort)
{
self.moves.sort(thisSort);
self.lastMoveSort = thisSort;
}
things = self.moves;
break;
}
for (var i=0; i<things.length; i++)
{
var thing = things[i];
if (type==='pokemon' && !thing.species || thing.jp) continue;
// fill our buckets!
var bucket = thisArrange(thing);
var match = {thing: thing, thingType: type, bucket: bucket};
var matchType = 'other';
var index = -1;
if (searchTerm)
{
index = thing.name.toLowerCase().indexOf(searchTerm);
if (index === 0)
{
matchType = 'start';
match.name = {
start: index,
end: index+searchTerm.length
};
if (searchTerm.length === thing.name.length)
{
self.exactResult = thing.name;
matchType = 'exact';
}
}
else if (index >= 0)
{
matchType = 'contains';
match.name = {
start: index,
end: index+searchTerm.length
};
}
else if (type === 'pokemon')
{
index = thing.types[0].toLowerCase().indexOf(searchTerm);
if (index == 0)
{
matchType = 'fullstart';
match.type = {0:{
start: 0,
end: searchTerm.length
}};
}
if (thing.types[1])
{
index = thing.types[1].toLowerCase().indexOf(searchTerm);
if (index == 0)
{
matchType = 'fullstart';
match.type = {1:{
start: 0,
end: searchTerm.length
}};
}
}
index = thing.abilities['0'].toLowerCase().indexOf(searchTerm);
if (index == 0)
{
matchType = 'fullstart';
match.ability = {0:{
start: 0,
end: searchTerm.length
}};
}
if (thing.abilities['1'])
{
index = thing.abilities['1'].toLowerCase().indexOf(searchTerm);
if (index == 0)
{
matchType = 'fullstart';
match.ability = {1:{
start: 0,
end: searchTerm.length
}};
}
}
if (thing.abilities['DW'])
{
index = thing.abilities['DW'].toLowerCase().indexOf(searchTerm);
if (index == 0)
{
matchType = 'fullstart';
match.ability = {DW:{
start: 0,
end: searchTerm.length
}};
}
}
}
else if (type === 'move')
{
index = thing.type.toLowerCase().indexOf(searchTerm);
if (index == 0)
{
matchType = 'fullstart';
match.type = {
start: 0,
end: searchTerm.length
};
}
index = thing.category.toLowerCase().indexOf(searchTerm);
if (index == 0)
{
matchType = 'fullstart';
match.category = {
start: 0,
end: searchTerm.length
};
}
}
}
if (self.illegalBuckets[bucket])
{
if (matchType === 'start' || matchType === 'contains' || matchType === 'fullstart')
{
matchType = 'illegal'+matchType;
}
}
if (!chartData[matchType][bucket]) chartData[matchType][bucket] = [];
chartData[matchType][bucket].push(match);
}
// construct a chart from the filled buckets!
var text = '<ul class="utilichart">';
var firstMatch = true;
var noNameMatch = false;
var matchTypes = ['exact', 'start', 'contains', 'illegalstart', 'illegalcontains'];
for (var mtIndex = 0; mtIndex < 5; mtIndex++)
{
var matchType = matchTypes[mtIndex];
for (var i in chartData[matchType])
{
if (!chartData[matchType][i]) continue;
for (var j=0; j<chartData[matchType][i].length; j++)
{
var match = chartData[matchType][i][j];
if (firstMatch)
{
text += '<li><h3>Matches</h3></li>';
}
text += self.row(match.thing, '', match, firstMatch);
firstMatch = false;
}
}
}
if (searchTerm && firstMatch)
{
text += '<li><h3>Matches</h3></li><li><em>No matches</em></li>';
firstMatch = false;
noNameMatch = true;
}
firstMatch = true;
for (var i in chartData.fullstart)
{
if (!chartData.fullstart[i]) continue;
for (var j=0; j<chartData.fullstart[i].length; j++)
{
var match = chartData.fullstart[i][j];
if (firstMatch)
{
text += '<li><h3>Details Matches</h3></li>';
}
text += self.row(match.thing, '', match, firstMatch && noNameMatch);
firstMatch = false;
}
}
for (var i in chartData.illegalfullstart)
{
if (!chartData.illegalfullstart[i]) continue;
for (var j=0; j<chartData.illegalfullstart[i].length; j++)
{
var match = chartData.illegalfullstart[i][j];
if (firstMatch)
{
text += '<li><h3>Details Matches</h3></li>';
}
text += self.row(match.thing, '', match, firstMatch && noNameMatch);
firstMatch = false;
}
}
if (!searchTerm || init)
{
for (var i=0; i<buckets.length; i++)
{
var ib = buckets[i];
if (!chartData.other[ib]) continue;
firstMatch = true;
for (var j=0; j<chartData.other[ib].length; j++)
{
var match = chartData.other[ib][j];
if (firstMatch)
{
text += '<li><h3>'+buckets[i]+'</h3></li>';
firstMatch = false;
}
text += self.row(match.thing, '', match);
}
}
}
text += '</ul>';
return text;
};
this.defaultArrange = function(thing) {
if (!thing)
{
// we want the list of buckets
return ['All'];
}
return 'All';
};
this.defaultSort = function(a,b) {
/* if (!a.num) a.num = 1000;
if (!b.num) b.num = 1000;
if (a.num != b.num)
{
return a.num - b.num;
} */
return (a.name == b.name) ? 0 : ( (a.name > b.name) ? 1 : -1 );
};
}
var Chart = new BattleChart();