pokemon-showdown-client/js/search.js
Guangcong Luo 6c38107fbe Use DexSearch for the teambuilder search engine
This will prevent us from needing to maintain two search engines in
the future.

The new DexSearch doesn't have too much in the way of new features so
far, but it does show filtered things in categories, and list illegal
results in-filter even after sorting.

These are really minor differences, though; the main thing is just that
its architecture should make it much easier to maintain, and in
particular, to add more filters.
2020-05-05 20:16:23 -07:00

819 lines
30 KiB
JavaScript

/**
* Search
*
* Basically just an improved version of utilichart
*
* Dependencies: jQuery, battledata, search-index
* Optional dependencies: pokedex, moves, items, abilities
*
* @author Guangcong Luo <guangcongluo@gmail.com>
*/
(function (exports, $) {
'use strict';
function Search(elem, viewport) {
this.$el = $(elem);
this.el = this.$el[0];
this.$viewport = (viewport ? $(viewport) : $(window));
this.urlRoot = '';
this.q = undefined; // uninitialized
this.exactMatch = false;
this.resultSet = null;
this.filters = null;
this.sortCol = null;
this.renderedIndex = 0;
this.renderingDone = true;
this.externalFilter = false;
this.cur = {};
this.$inputEl = null;
this.gen = 8;
this.mod = null;
this.engine = new DexSearch();
window.search = this;
var self = this;
this.$el.on('click', '.more button', function (e) {
e.preventDefault();
self.updateScroll(true);
});
this.$el.on('click', '.filter', function (e) {
e.preventDefault();
self.removeFilter(e);
if (self.$inputEl) self.$inputEl.focus();
});
this.$el.on('click', '.sortcol', function (e) {
e.preventDefault();
e.stopPropagation();
var sortCol = e.currentTarget.dataset.sort;
self.engine.toggleSort(sortCol);
self.sortCol = self.engine.sortCol;
self.find('');
});
}
Search.prototype.$ = function (query) {
return this.$el.find(query);
};
//
// Search functions
//
Search.prototype.find = function (query, firstElem) {
if (!this.engine.find(query)) return; // nothing changed
this.exactMatch = this.engine.exactMatch;
this.q = this.engine.query;
this.resultSet = this.engine.results;
if (firstElem) {
this.resultSet = [[this.engine.typedSearch.searchType, firstElem]].concat(this.resultSet);
if (this.resultSet.length > 1 && ['sortpokemon', 'sortmove'].includes(this.resultSet[1][0])) {
var sortRow = this.resultSet[1];
this.resultSet[1] = this.resultSet[0];
this.resultSet[0] = sortRow;
}
}
if (this.filters) {
this.resultSet = [['html', this.getFilterText()]].concat(this.resultSet);
}
this.renderedIndex = 0;
this.renderingDone = false;
this.updateScroll();
return true;
};
Search.prototype.addFilter = function (node) {
if (!node.dataset.entry) return false;
var entry = node.dataset.entry.split('|');
var result = this.engine.addFilter(entry);
this.filters = this.engine.filters;
return result;
};
Search.prototype.removeFilter = function (e) {
var result;
if (e) {
result = this.engine.removeFilter(e.currentTarget.value.split(':'));
} else {
result = this.engine.removeFilter();
}
this.filters = this.engine.filters;
this.find('');
return result;
};
Search.prototype.getFilterText = function (q) {
var buf = '<p>Filters: ';
for (var i = 0; i < this.filters.length; i++) {
var text = this.filters[i][1];
if (this.filters[i][0] === 'move') text = Dex.getMove(text).name;
if (this.filters[i][0] === 'pokemon') text = Dex.getSpecies(text).name;
buf += '<button class="filter" value="' + BattleLog.escapeHTML(this.filters[i].join(':')) + '">' + text + ' <i class="fa fa-times-circle"></i></button> ';
}
if (!q) buf += '<small style="color: #888">(backspace = delete filter)</small>';
return buf + '</p>';
};
Search.prototype.updateScroll = function (forceAdd) {
if (this.renderingDone) return;
var top = this.$viewport.scrollTop();
var bottom = top + this.$viewport.height();
var windowHeight = $(window).height();
var i = this.renderedIndex;
var finalIndex = Math.floor(bottom / 33) + 1;
if (!forceAdd && finalIndex <= i) return;
if (finalIndex < i + 20) finalIndex = i + 20;
if (bottom - top > windowHeight && !i) finalIndex = 20;
if (forceAdd && finalIndex > i + 40) finalIndex = i + 40;
var resultSet = this.resultSet;
var buf = '';
while (i < finalIndex) {
if (!resultSet[i]) {
this.renderingDone = true;
break;
}
var row = resultSet[i];
var errorMessage = '';
var label;
if ((label = this.engine.filterLabel(row[0]))) {
errorMessage = '<span class="col filtercol"><em>' + label + '</em></span>';
} else if ((label = this.engine.illegalLabel(row[1]))) {
errorMessage = '<span class="col illegalcol"><em>' + label + '</em></span>';
}
var mStart = 0;
var mEnd = 0;
if (row.length > 3) {
mStart = row[2];
mEnd = row[3];
}
buf += this.renderRow(row[1], row[0], mStart, mEnd, errorMessage, row[1] in this.cur ? ' class="cur"' : '');
i++;
}
if (!this.renderedIndex) {
this.el.innerHTML = '<ul class="utilichart" style="height:' + (resultSet.length * 33) + 'px">' + buf + (!this.renderingDone ? '<li class="result more"><p><button class="button big">More</button></p></li>' : '') + '</ul>';
this.moreVisible = true;
} else {
if (this.moreVisible) {
this.$el.find('.more').remove();
if (!forceAdd) this.moreVisible = false;
}
$(this.el.firstChild).append(buf + (forceAdd && !this.renderingDone ? '<li class="result more"><p><button class="button big">More</button></p></li>' : ''));
}
this.renderedIndex = i;
};
Search.prototype.setType = function (qType, format, set, cur) {
this.engine.setType(qType, format, set);
this.cur = cur || {};
var firstElem;
for (var id in cur) {
firstElem = id;
break;
}
this.find('', firstElem);
};
/*********************************************************
* Rendering functions
*********************************************************/
// These all have static versions
Search.prototype.renderRow = function (id, type, matchStart, matchLength, errorMessage, attrs) {
// errorMessage = '<span class="col illegalcol"><em>' + errorMessage + '</em></span>';
switch (type) {
case 'html':
return '<li class="result">' + id + '</li>';
case 'header':
return '<li class="result"><h3>' + id + '</h3></li>';
case 'sortpokemon':
return this.renderPokemonSortRow();
case 'sortmove':
return this.renderMoveSortRow();
case 'pokemon':
var pokemon = this.engine.dex.getSpecies(id);
return this.renderPokemonRow(pokemon, matchStart, matchLength, errorMessage, attrs);
case 'move':
var move = BattleMovedex[id];
return this.renderMoveRow(move, matchStart, matchLength, errorMessage, attrs);
case 'item':
var item = BattleItems[id];
return this.renderItemRow(item, matchStart, matchLength, errorMessage, attrs);
case 'ability':
var ability = BattleAbilities[id];
return this.renderAbilityRow(ability, matchStart, matchLength, errorMessage, attrs);
case 'type':
var type = {name: id[0].toUpperCase() + id.substr(1)};
return this.renderTypeRow(type, matchStart, matchLength, errorMessage);
case 'egggroup':
// very hardcode
var egName;
if (id === 'humanlike') egName = 'Human-Like';
else if (id === 'water1') egName = 'Water 1';
else if (id === 'water2') egName = 'Water 2';
else if (id === 'water3') egName = 'Water 3';
if (egName) {
if (matchLength > 5) matchLength++;
} else {
egName = id[0].toUpperCase() + id.substr(1);
}
var egggroup = {name: egName};
return this.renderEggGroupRow(egggroup, matchStart, matchLength, errorMessage);
case 'tier':
// very hardcode
var tierTable = {
uber: "Uber",
ou: "OU",
uu: "UU",
ru: "RU",
nu: "NU",
pu: "PU",
zu: "(PU)",
nfe: "NFE",
lcuber: "LC Uber",
lc: "LC",
cap: "CAP",
caplc: "CAP LC",
capnfe: "CAP NFE",
uubl: "UUBL",
rubl: "RUBL",
nubl: "NUBL",
publ: "PUBL"
};
var tier = {name: tierTable[id]};
return this.renderTierRow(tier, matchStart, matchLength, errorMessage);
case 'category':
var category = {name: id[0].toUpperCase() + id.substr(1), id: id};
return this.renderCategoryRow(category, matchStart, matchLength, errorMessage);
case 'article':
var articleTitle = (window.BattleArticleTitles && BattleArticleTitles[id]) || (id[0].toUpperCase() + id.substr(1));
var article = {name: articleTitle, id: id};
return this.renderArticleRow(article, matchStart, matchLength, errorMessage);
}
return 'Error: not found';
};
Search.prototype.renderPokemonSortRow = function () {
var buf = '<li class="result"><div class="sortrow">';
buf += '<button class="sortcol numsortcol' + (!this.sortCol ? ' cur' : '') + '">' + (!this.sortCol ? 'Sort: ' : this.engine.firstPokemonColumn) + '</button>';
buf += '<button class="sortcol pnamesortcol' + (this.sortCol === 'name' ? ' cur' : '') + '" data-sort="name">Name</button>';
buf += '<button class="sortcol typesortcol' + (this.sortCol === 'type' ? ' cur' : '') + '" data-sort="type">Types</button>';
buf += '<button class="sortcol abilitysortcol' + (this.sortCol === 'ability' ? ' cur' : '') + '" data-sort="ability">Abilities</button>';
buf += '<button class="sortcol statsortcol' + (this.sortCol === 'hp' ? ' cur' : '') + '" data-sort="hp">HP</button>';
buf += '<button class="sortcol statsortcol' + (this.sortCol === 'atk' ? ' cur' : '') + '" data-sort="atk">Atk</button>';
buf += '<button class="sortcol statsortcol' + (this.sortCol === 'def' ? ' cur' : '') + '" data-sort="def">Def</button>';
buf += '<button class="sortcol statsortcol' + (this.sortCol === 'spa' ? ' cur' : '') + '" data-sort="spa">SpA</button>';
buf += '<button class="sortcol statsortcol' + (this.sortCol === 'spd' ? ' cur' : '') + '" data-sort="spd">SpD</button>';
buf += '<button class="sortcol statsortcol' + (this.sortCol === 'spe' ? ' cur' : '') + '" data-sort="spe">Spe</button>';
buf += '<button class="sortcol statsortcol' + (this.sortCol === 'bst' ? ' cur' : '') + '" data-sort="bst">BST</button>';
buf += '</div></li>';
return buf;
};
Search.prototype.renderMoveSortRow = function () {
var buf = '<li class="result"><div class="sortrow">';
buf += '<button class="sortcol movenamesortcol' + (this.sortCol === 'name' ? ' cur' : '') + '" data-sort="name">Name</button>';
buf += '<button class="sortcol movetypesortcol' + (this.sortCol === 'type' ? ' cur' : '') + '" data-sort="type">Type</button>';
buf += '<button class="sortcol movetypesortcol' + (this.sortCol === 'category' ? ' cur' : '') + '" data-sort="category">Cat</button>';
buf += '<button class="sortcol powersortcol' + (this.sortCol === 'power' ? ' cur' : '') + '" data-sort="power">Pow</button>';
buf += '<button class="sortcol accuracysortcol' + (this.sortCol === 'accuracy' ? ' cur' : '') + '" data-sort="accuracy">Acc</button>';
buf += '<button class="sortcol ppsortcol' + (this.sortCol === 'pp' ? ' cur' : '') + '" data-sort="pp">PP</button>';
buf += '</div></li>';
return buf;
};
Search.prototype.renderPokemonRow = function (pokemon, matchStart, matchLength, errorMessage, attrs) {
if (!attrs) attrs = '';
if (!pokemon) return '<li class="result">Unrecognized pokemon</li>';
var id = toID(pokemon.name);
if (Search.urlRoot) attrs += ' href="' + Search.urlRoot + 'pokemon/' + id + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="pokemon|' + BattleLog.escapeHTML(pokemon.name) + '">';
// number
// buf += '<span class="col numcol">' + (pokemon.num >= 0 ? pokemon.num : 'CAP') + '</span> ';
buf += '<span class="col numcol">' + this.engine.getTier(pokemon) + '</span> ';
// icon
buf += '<span class="col iconcol">';
buf += '<span style="' + Dex.getPokemonIcon(pokemon.name) + '"></span>';
buf += '</span> ';
// name
var name = pokemon.name;
var tagStart = (pokemon.forme ? name.length - pokemon.forme.length - 1 : 0);
if (tagStart) name = name.substr(0, tagStart);
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
if (tagStart) {
if (matchLength && matchStart + matchLength > tagStart) {
if (matchStart < tagStart) {
matchLength -= tagStart - matchStart;
matchStart = tagStart;
}
name += '<small>' + pokemon.name.substr(tagStart, matchStart - tagStart) + '<b>' + pokemon.name.substr(matchStart, matchLength) + '</b>' + pokemon.name.substr(matchStart + matchLength) + '</small>';
} else {
name += '<small>' + pokemon.name.substr(tagStart) + '</small>';
}
}
buf += '<span class="col pokemonnamecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
var gen = this.gen;
// type
buf += '<span class="col typecol">';
var types = pokemon.types;
for (var i = 0; i < types.length; i++) {
buf += Dex.getTypeIcon(types[i]);
}
buf += '</span> ';
// abilities
if (gen >= 3) {
var abilities = Dex.forGen(gen).getSpecies(id).abilities;
if (abilities['1']) {
buf += '<span class="col twoabilitycol">' + abilities['0'] + '<br />' +
abilities['1'] + '</span>';
} else {
buf += '<span class="col abilitycol">' + abilities['0'] + '</span>';
}
if (gen >= 5) {
var unreleasedHidden = pokemon.unreleasedHidden;
if (unreleasedHidden === 'Past' && (this.mod === 'natdex' || gen < 8)) unreleasedHidden = false;
if (abilities['S']) {
buf += '<span class="col twoabilitycol' + (unreleasedHidden ? ' unreleasedhacol' : '') + '">' + (abilities['H'] || '') + '<br />' + abilities['S'] + '</span>';
} else if (abilities['H']) {
buf += '<span class="col abilitycol' + (unreleasedHidden ? ' unreleasedhacol' : '') + '">' + abilities['H'] + '</span>';
} else {
buf += '<span class="col abilitycol"></span>';
}
}
}
// base stats
var stats = pokemon.baseStats;
buf += '<span class="col statcol"><em>HP</em><br />' + stats.hp + '</span> ';
buf += '<span class="col statcol"><em>Atk</em><br />' + stats.atk + '</span> ';
buf += '<span class="col statcol"><em>Def</em><br />' + stats.def + '</span> ';
if (gen >= 2) {
buf += '<span class="col statcol"><em>SpA</em><br />' + stats.spa + '</span> ';
buf += '<span class="col statcol"><em>SpD</em><br />' + stats.spd + '</span> ';
} else {
buf += '<span class="col statcol"><em>Spc</em><br />' + stats.spa + '</span> ';
}
buf += '<span class="col statcol"><em>Spe</em><br />' + stats.spe + '</span> ';
var bst = 0;
for (i in stats) bst += stats[i];
buf += '<span class="col bstcol"><em>BST<br />' + bst + '</em></span> ';
buf += '</a></li>';
return buf;
};
Search.prototype.renderTaggedPokemonRowInner = function (pokemon, tag, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'pokemon/' + toID(pokemon.name) + '" data-target="push"';
var buf = '<a' + attrs + ' data-entry="pokemon|' + BattleLog.escapeHTML(pokemon.name) + '">';
// tag
buf += '<span class="col tagcol shorttagcol">' + tag + '</span> ';
// icon
buf += '<span class="col iconcol">';
buf += '<span style="' + Dex.getPokemonIcon(pokemon.name) + '"></span>';
buf += '</span> ';
// name
var name = pokemon.name;
var tagStart = (pokemon.forme ? name.length - pokemon.forme.length - 1 : 0);
if (tagStart) name = name.substr(0, tagStart) + '<small>' + pokemon.name.substr(tagStart) + '</small>';
buf += '<span class="col shortpokemonnamecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
// type
buf += '<span class="col typecol">';
for (var i = 0; i < pokemon.types.length; i++) {
buf += Dex.getTypeIcon(pokemon.types[i]);
}
buf += '</span> ';
// abilities
buf += '<span style="float:left;min-height:26px">';
if (pokemon.abilities['1']) {
buf += '<span class="col twoabilitycol">';
} else {
buf += '<span class="col abilitycol">';
}
for (var i in pokemon.abilities) {
var ability = pokemon.abilities[i];
if (!ability) continue;
if (i === '1') buf += '<br />';
if (i === 'H') ability = '</span><span class="col abilitycol"><em>' + pokemon.abilities[i] + '</em>';
buf += ability;
}
if (!pokemon.abilities['H']) buf += '</span><span class="col abilitycol">';
buf += '</span>';
buf += '</span>';
// base stats
buf += '<span style="float:left;min-height:26px">';
buf += '<span class="col statcol"><em>HP</em><br />' + pokemon.baseStats.hp + '</span> ';
buf += '<span class="col statcol"><em>Atk</em><br />' + pokemon.baseStats.atk + '</span> ';
buf += '<span class="col statcol"><em>Def</em><br />' + pokemon.baseStats.def + '</span> ';
buf += '<span class="col statcol"><em>SpA</em><br />' + pokemon.baseStats.spa + '</span> ';
buf += '<span class="col statcol"><em>SpD</em><br />' + pokemon.baseStats.spd + '</span> ';
buf += '<span class="col statcol"><em>Spe</em><br />' + pokemon.baseStats.spe + '</span> ';
var bst = 0;
for (i in pokemon.baseStats) bst += pokemon.baseStats[i];
buf += '<span class="col bstcol"><em>BST<br />' + bst + '</em></span> ';
buf += '</span>';
buf += '</a>';
return buf;
};
Search.prototype.renderItemRow = function (item, matchStart, matchLength, errorMessage, attrs) {
if (!attrs) attrs = '';
if (!item) return '<li class="result">Unrecognized item</li>';
var id = toID(item.name);
if (Search.urlRoot) attrs += ' href="' + Search.urlRoot + 'items/' + id + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="item|' + BattleLog.escapeHTML(item.name) + '">';
// icon
buf += '<span class="col itemiconcol">';
buf += '<span style="' + Dex.getItemIcon(item) + '"></span>';
buf += '</span> ';
// name
var name = item.name;
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
buf += '<span class="col namecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
// desc
var desc = (item.shortDesc || item.desc);
if (this.gen < 8) {
for (var i = this.gen; i < 8; i++) {
if (id in BattleTeambuilderTable['gen' + i].overrideItemDesc) {
desc = BattleTeambuilderTable['gen' + i].overrideItemDesc[id];
break;
}
}
}
buf += '<span class="col itemdesccol">' + BattleLog.escapeHTML(desc) + '</span> ';
buf += '</a></li>';
return buf;
};
Search.prototype.renderAbilityRow = function (ability, matchStart, matchLength, errorMessage, attrs) {
if (!attrs) attrs = '';
if (!ability) return '<li class="result">Unrecognized ability</li>';
var id = toID(ability.name);
if (Search.urlRoot) attrs += ' href="' + Search.urlRoot + 'abilities/' + id + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="ability|' + BattleLog.escapeHTML(ability.name) + '">';
// name
var name = ability.name;
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
buf += '<span class="col namecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
var desc = (ability.shortDesc || ability.desc);
if (this.gen < 8) {
for (var i = this.gen; i < 8; i++) {
if (id in BattleTeambuilderTable['gen' + i].overrideAbilityDesc) {
desc = BattleTeambuilderTable['gen' + i].overrideAbilityDesc[id];
break;
}
}
}
buf += '<span class="col abilitydesccol">' + BattleLog.escapeHTML(desc) + '</span> ';
buf += '</a></li>';
return buf;
};
Search.prototype.renderMoveRow = function (move, matchStart, matchLength, errorMessage, attrs) {
if (!attrs) attrs = '';
if (!move) return '<li class="result">Unrecognized move</li>';
var id = toID(move.name);
if (Search.urlRoot) attrs += ' href="' + Search.urlRoot + 'moves/' + id + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="move|' + BattleLog.escapeHTML(move.name) + '">';
// name
var name = move.name;
var tagStart = (name.substr(0, 12) === 'Hidden Power' ? 12 : 0);
if (tagStart) name = name.substr(0, tagStart);
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
if (tagStart) {
if (matchLength && matchStart + matchLength > tagStart) {
if (matchStart < tagStart) {
matchLength -= tagStart - matchStart;
matchStart = tagStart;
}
name += '<small>' + move.name.substr(tagStart, matchStart - tagStart) + '<b>' + move.name.substr(matchStart, matchLength) + '</b>' + move.name.substr(matchStart + matchLength) + '</small>';
} else {
name += '<small>' + move.name.substr(tagStart) + '</small>';
}
}
buf += '<span class="col movenamecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
var table = (this.gen < 8 ? BattleTeambuilderTable['gen' + this.gen] : null);
// type
buf += '<span class="col typecol">';
var type = move.type;
if (table && id in table.overrideMoveType) type = table.overrideMoveType[id];
buf += Dex.getTypeIcon(type);
var category = this.gen > 3 || move.category === 'Status' ? move.category : Dex.getGen3Category(type);
buf += '<img src="' + Dex.resourcePrefix + 'sprites/categories/' + category + '.png" alt="' + category + '" height="14" width="32" />';
buf += '</span> ';
// power, accuracy, pp
var basePower = move.basePower;
var accuracy = move.accuracy;
var pp = move.pp;
if (table) {
if (id in table.overrideBP) basePower = table.overrideBP[id];
if (id in table.overrideAcc) accuracy = table.overrideAcc[id];
if (id in table.overridePP) pp = table.overridePP[id];
}
buf += '<span class="col labelcol">' + (move.category !== 'Status' ? ('<em>Power</em><br />' + (basePower || '&mdash;')) : '') + '</span> ';
buf += '<span class="col widelabelcol"><em>Accuracy</em><br />' + (accuracy && accuracy !== true ? accuracy + '%' : '&mdash;') + '</span> ';
buf += '<span class="col pplabelcol"><em>PP</em><br />' + (pp === 1 || move.noPPBoosts ? pp : pp * 8 / 5) + '</span> ';
// desc
var desc = (move.shortDesc || move.desc);
if (this.gen < 8) {
for (var i = this.gen; i < 8; i++) {
if (id in BattleTeambuilderTable['gen' + i].overrideMoveDesc) {
desc = BattleTeambuilderTable['gen' + i].overrideMoveDesc[id];
break;
}
}
}
buf += '<span class="col movedesccol">' + BattleLog.escapeHTML(desc) + '</span> ';
buf += '</a></li>';
return buf;
};
Search.prototype.renderMoveRowInner = function (move, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'moves/' + toID(move.name) + '" data-target="push"';
var buf = '<a' + attrs + ' data-entry="move|' + BattleLog.escapeHTML(move.name) + '">';
// name
var name = move.name;
var tagStart = (name.substr(0, 12) === 'Hidden Power' ? 12 : 0);
if (tagStart) name = name.substr(0, tagStart) + '<small>' + move.name.substr(tagStart) + '</small>';
buf += '<span class="col movenamecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
// type
buf += '<span class="col typecol">';
buf += Dex.getTypeIcon(move.type);
buf += '<img src="' + Dex.resourcePrefix + 'sprites/categories/' + move.category + '.png" alt="' + move.category + '" height="14" width="32" />';
buf += '</span> ';
// power, accuracy, pp
buf += '<span class="col labelcol">' + (move.category !== 'Status' ? ('<em>Power</em><br />' + (move.basePower || '&mdash;')) : '') + '</span> ';
buf += '<span class="col widelabelcol"><em>Accuracy</em><br />' + (move.accuracy && move.accuracy !== true ? move.accuracy + '%' : '&mdash;') + '</span> ';
buf += '<span class="col pplabelcol"><em>PP</em><br />' + (move.pp === 1 || move.noPPBoosts ? move.pp : move.pp * 8 / 5) + '</span> ';
// desc
buf += '<span class="col movedesccol">' + BattleLog.escapeHTML(move.shortDesc || move.desc) + '</span> ';
buf += '</a>';
return buf;
};
Search.prototype.renderTaggedMoveRow = function (move, tag, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'moves/' + toID(move.name) + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="move|' + BattleLog.escapeHTML(move.name) + '">';
// tag
buf += '<span class="col tagcol">' + tag + '</span> ';
// name
var name = move.name;
if (name.substr(0, 12) === 'Hidden Power') name = 'Hidden Power';
buf += '<span class="col shortmovenamecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
// type
buf += '<span class="col typecol">';
buf += Dex.getTypeIcon(move.type);
buf += '<img src="' + Dex.resourcePrefix + 'sprites/categories/' + move.category + '.png" alt="' + move.category + '" height="14" width="32" />';
buf += '</span> ';
// power, accuracy, pp
buf += '<span class="col labelcol">' + (move.category !== 'Status' ? ('<em>Power</em><br />' + (move.basePower || '&mdash;')) : '') + '</span> ';
buf += '<span class="col widelabelcol"><em>Accuracy</em><br />' + (move.accuracy && move.accuracy !== true ? move.accuracy + '%' : '&mdash;') + '</span> ';
buf += '<span class="col pplabelcol"><em>PP</em><br />' + (move.pp !== 1 ? move.pp * 8 / 5 : move.pp) + '</span> ';
// desc
buf += '<span class="col movedesccol">' + BattleLog.escapeHTML(move.shortDesc || move.desc) + '</span> ';
buf += '</a></li>';
return buf;
};
Search.prototype.renderTypeRow = function (type, matchStart, matchLength, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'types/' + toID(type.name) + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="type|' + BattleLog.escapeHTML(type.name) + '">';
// name
var name = type.name;
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
buf += '<span class="col namecol">' + name + '</span> ';
// type
buf += '<span class="col typecol">';
buf += Dex.getTypeIcon(type.name);
buf += '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
buf += '</a></li>';
return buf;
};
Search.prototype.renderCategoryRow = function (category, matchStart, matchLength, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'categories/' + category.id + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="category|' + BattleLog.escapeHTML(category.name) + '">';
// name
var name = category.name;
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
buf += '<span class="col namecol">' + name + '</span> ';
// category
buf += '<span class="col typecol">';
buf += '<img src="' + Dex.resourcePrefix + 'sprites/categories/' + category.name + '.png" alt="' + category.name + '" height="14" width="32" />';
buf += '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
buf += '</a></li>';
return buf;
};
Search.prototype.renderArticleRow = function (article, matchStart, matchLength, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'articles/' + article.id + '" data-target="push"';
var isSearchType = (article.id === 'pokemon' || article.id === 'moves');
if (isSearchType) attrs = ' href="' + article.id + '/" data-target="replace"';
var buf = '<li class="result"><a' + attrs + ' data-entry="article|' + BattleLog.escapeHTML(article.name) + '">';
// name
var name = article.name;
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
buf += '<span class="col namecol">' + name + '</span> ';
// article
if (isSearchType) {
buf += '<span class="col movedesccol">(search type)</span> ';
} else {
buf += '<span class="col movedesccol">(article)</span> ';
}
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
buf += '</a></li>';
return buf;
};
Search.prototype.renderEggGroupRow = function (egggroup, matchStart, matchLength, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'egggroups/' + toID(egggroup.name) + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="egggroup|' + BattleLog.escapeHTML(egggroup.name) + '">';
// name
var name = egggroup.name;
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
buf += '<span class="col namecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
buf += '</a></li>';
return buf;
};
Search.prototype.renderTierRow = function (tier, matchStart, matchLength, errorMessage) {
var attrs = '';
if (Search.urlRoot) attrs = ' href="' + Search.urlRoot + 'tiers/' + toID(tier.name) + '" data-target="push"';
var buf = '<li class="result"><a' + attrs + ' data-entry="tier|' + BattleLog.escapeHTML(tier.name) + '">';
// name
var name = tier.name;
if (matchLength) {
name = name.substr(0, matchStart) + '<b>' + name.substr(matchStart, matchLength) + '</b>' + name.substr(matchStart + matchLength);
}
buf += '<span class="col namecol">' + name + '</span> ';
// error
if (errorMessage) {
buf += errorMessage + '</a></li>';
return buf;
}
buf += '</a></li>';
return buf;
};
Search.gen = 8;
Search.renderRow = Search.prototype.renderRow;
Search.renderPokemonRow = Search.prototype.renderPokemonRow;
Search.renderTaggedPokemonRowInner = Search.prototype.renderTaggedPokemonRowInner;
Search.renderItemRow = Search.prototype.renderItemRow;
Search.renderAbilityRow = Search.prototype.renderAbilityRow;
Search.renderMoveRow = Search.prototype.renderMoveRow;
Search.renderMoveRowInner = Search.prototype.renderMoveRowInner;
Search.renderTaggedMoveRow = Search.prototype.renderTaggedMoveRow;
Search.renderTypeRow = Search.prototype.renderTypeRow;
Search.renderCategoryRow = Search.prototype.renderCategoryRow;
Search.renderEggGroupRow = Search.prototype.renderEggGroupRow;
Search.renderTierRow = Search.prototype.renderTierRow;
exports.BattleSearch = Search;
})(window, jQuery);