Profiler/Completions

* show completion info for claimed characters in infobox on
      appropriate db pages
This commit is contained in:
Sarjuuk 2025-11-03 18:00:50 +01:00
parent 37380ff515
commit e3d6f7b3a7
25 changed files with 640 additions and 39 deletions

View file

@ -124,10 +124,7 @@ class AchievementBaseResponse extends TemplateResponse implements ICache
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `realm` IS NOT NULL AND `realmGUID` IS NOT NULL AND `cuFlags` & ?d = 0', PROFILER_CU_NEEDS_RESYNC);
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
// - js component missing;
// - can't yet assign styles to li element
// if (User::getPinnedCharacter())
// $infobox[] = Lang::profiler('completion') . '[span class="compact-completion-display"][/span]'; // [li style="display:none"]...[/li]
// completion row added by InfoboxMarkup
}
// original name
@ -135,7 +132,7 @@ class AchievementBaseResponse extends TemplateResponse implements ICache
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
if ($infobox)
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', !($this->subject->getField('flags') & ACHIEVEMENT_FLAG_COUNTER));
/**********/

View file

@ -106,18 +106,15 @@ class FactionBaseResponse extends TemplateResponse implements ICache
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `realm` IS NOT NULL AND `realmGUID` IS NOT NULL AND `cuFlags` & ?d = 0', PROFILER_CU_NEEDS_RESYNC);
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
// - js component missing;
// - can't yet assign styles to li element
// if (User::getPinnedCharacter())
// $infobox[] = Lang::profiler('completion') . '[span class="compact-completion-display"][/span]'; // [li style="display:none"]...[/li]
// completion row added by InfoboxMarkup
}
// original name
if (Lang::getLocale() != Locale::EN)
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
if ($infobox)
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
if ($infobox) // unsure if this should be tracked (needs data dump in User::getCompletion())
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', 0);
/****************/

View file

@ -319,12 +319,15 @@ class ItemBaseResponse extends TemplateResponse implements ICache
if ($_bagFamily & 0x0100)
$infobox[] = Lang::item('atKeyring');
// completion row added by InfoboxMarkup
// original name
if (Lang::getLocale() != Locale::EN)
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
$hasCompletion = !($this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW) && ($_class == ITEM_CLASS_RECIPE || ($_class == ITEM_CLASS_MISC && in_array($_subClass, [2, 5, -7])));
if ($infobox)
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', $hasCompletion);
/****************/

View file

@ -64,6 +64,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
$_flags = $this->subject->getField('flags');
$_specialFlags = $this->subject->getField('specialFlags');
$_side = ChrRace::sideFromMask($this->subject->getField('reqRaceMask'));
$hasCompletion = !($_flags & QUEST_FLAG_UNAVAILABLE || $this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW);
/*************/
@ -275,16 +276,13 @@ class QuestBaseResponse extends TemplateResponse implements ICache
$infobox[] = Lang::quest('id') . $this->typeId;
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
if (Cfg::get('PROFILER_ENABLE') && !($_flags & QUEST_FLAG_UNAVAILABLE || $this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW))
if (Cfg::get('PROFILER_ENABLE') && $hasCompletion)
{
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_quests WHERE `questId` = ?d', $this->typeId);
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `realm` IS NOT NULL AND `realmGUID` IS NOT NULL AND `cuFlags` & ?d = 0', PROFILER_CU_NEEDS_RESYNC);
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
// - js component missing;
// - can't yet assign styles to li element
// if (User::getPinnedCharacter())
// $infobox[] = Lang::profiler('completion') . '[span class="compact-completion-display"][/span]'; // [li style="display:none"]...[/li]
// completion row added by InfoboxMarkup
}
// original name
@ -292,7 +290,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
if ($infobox)
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', $hasCompletion);
/*******************/

View file

@ -2352,8 +2352,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
private function createInfobox() : void
{
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
$typeCat = $this->subject->getField('typeCat');
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
$typeCat = $this->subject->getField('typeCat');
$hasCompletion = in_array($typeCat, [-5, -6]) && !($this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW);
// level
if (!in_array($typeCat, [-5, -6])) // not mount or vanity pet
@ -2445,16 +2446,13 @@ class SpellBaseResponse extends TemplateResponse implements ICache
}
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
if (Cfg::get('PROFILER_ENABLE') && in_array($this->subject->getField('typeCat'), [-5, -6]) && !($this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW))
if (Cfg::get('PROFILER_ENABLE') && $hasCompletion)
{
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_spells WHERE `spellId` = ?d', $this->typeId);
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `realm` IS NOT NULL AND `realmGUID` IS NOT NULL AND `cuFlags` & ?d = 0', PROFILER_CU_NEEDS_RESYNC);
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
// - js component missing;
// - can't yet assign styles to li element
// if (User::getPinnedCharacter())
// $infobox[] = Lang::profiler('completion') . '[span class="compact-completion-display"][/span]'; // [li style="display:none"]...[/li]
// completion row added by InfoboxMarkup
}
// original name
@ -2484,7 +2482,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
$infobox[] = 'Script'.Lang::main('colon').$_;
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', $hasCompletion);
// append glyph symbol if available
$glyphId = 0;

View file

@ -94,10 +94,7 @@ class TitleBaseResponse extends TemplateResponse implements ICache
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `realm` IS NOT NULL AND `realmGUID` IS NOT NULL AND `cuFlags` & ?d = 0', PROFILER_CU_NEEDS_RESYNC);
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
// - js component missing;
// - can't yet assign styles to li element
// if (User::getPinnedCharacter())
// $infobox[] = Lang::profiler('completion') . '[span class="compact-completion-display"][/span]'; // [li style="display:none"]...[/li]
// completion row added by InfoboxMarkup
}
// original name
@ -105,7 +102,7 @@ class TitleBaseResponse extends TemplateResponse implements ICache
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
if ($infobox)
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', 1);
/****************/

View file

@ -8,7 +8,7 @@ if (!defined('AOWOW_REVISION'))
class InfoboxMarkup extends Markup
{
public function __construct(private array $items, array $opts, string $parent = '')
public function __construct(private array $items, array $opts, string $parent = '', private int $completionRowType = 0)
{
parent::__construct('', $opts, $parent);
}
@ -31,6 +31,10 @@ class InfoboxMarkup extends Markup
public function __toString() : string
{
// inject before output to avoid adding it to cache
if ($this->completionRowType && User::getCharacters())
$this->items[] = [Lang::profiler('completion') . '[span class="compact-completion-display"][/span]', ['style' => 'display:none']];
if ($_ = $this->prepare())
$this->replace($_);

View file

@ -487,6 +487,11 @@ class ItemList extends DBTypeList
'quality' => $this->curTpl['quality'],
'icon' => $this->curTpl['iconString']
);
if ($this->curTpl['class'] == ITEM_CLASS_RECIPE)
$data[Type::ITEM][$id]['completion_category'] = $this->curTpl['class'];
else if ($this->curTpl['class'] == ITEM_CLASS_MISC && in_array($this->curTpl['subClass'], [2, 5, -7]))
$data[Type::ITEM][$id]['completion_category'] = $this->curTpl['class'].'-'.$this->curTpl['subClass'];
}
if ($addMask & GLOBALINFO_EXTRA)

View file

@ -415,7 +415,15 @@ class QuestList extends DBTypeList
}
if ($addMask & GLOBALINFO_SELF)
{
$data[Type::QUEST][$this->id] = ['name' => $this->getField('name', true)];
if ($this->curTpl['flags'] & QUEST_FLAG_DAILY)
$data[Type::QUEST][$this->id]['daily'] = true;
if ($this->curTpl['flags'] & QUEST_FLAG_WEEKLY)
$data[Type::QUEST][$this->id]['weekly'] = true;
}
}
return $data;

View file

@ -2150,8 +2150,11 @@ class SpellList extends DBTypeList
{
$data[Type::SPELL][$id] = array(
'icon' => $this->curTpl['iconStringAlt'] ?: $this->curTpl['iconString'],
'name' => $this->getField('name', true),
'name' => $this->getField('name', true)
);
if (($_ = $this->curTpl['typeCat']) && in_array($_, [-5, -6, 9, 11]))
$data[Type::SPELL][$id]['completion_category'] = $_;
}
if ($addMask & GLOBALINFO_EXTRA)

View file

@ -569,6 +569,7 @@ class User
$gUser['downvoteRep'] = Cfg::get('REP_REQ_DOWNVOTE');
$gUser['upvoteRep'] = Cfg::get('REP_REQ_UPVOTE');
$gUser['characters'] = self::getCharacters();
$gUser['completion'] = self::getCompletion();
$gUser['excludegroups'] = self::$excludeGroups;
if (self::$debug)
@ -723,6 +724,58 @@ class User
return $data;
}
public static function getCompletion() : array
{
$ids = [];
foreach (self::$profiles->iterate() as $_)
if (!self::$profiles->isCustom())
$ids[] = self::$profiles->id;
if (!$ids)
return [];
$completion = [];
$x = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `questId` AS ARRAY_KEY2, `questId` FROM ?_profiler_completion_quests WHERE `id` IN (?a)', $ids);
$completion[Type::QUEST] = $x ? array_map(array_values(...), $x) : [];
$x = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `achievementId` AS ARRAY_KEY2, `achievementId` FROM ?_profiler_completion_achievements WHERE `id` IN (?a)', $ids);
$completion[Type::ACHIEVEMENT] = $x ? array_map(array_values(...), $x) : [];
$x = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `titleId` AS ARRAY_KEY2, `titleId` FROM ?_profiler_completion_titles WHERE `id` IN (?a)', $ids);
$completion[Type::TITLE] = $x ? array_map(array_values(...), $x) : [];
$completion[Type::ITEM] = [];
$spells = DB::Aowow()->select(
'SELECT pcs.`id` AS ARRAY_KEY, pcs.`spellId` AS ARRAY_KEY2, pcs.`spellId`, i.`id` AS "itemId"
FROM ?_spell s
JOIN ?_profiler_completion_spells pcs ON s.`id` = pcs.`spellId`
LEFT JOIN ?_items i ON i.spellId1 IN (?a) AND i.spellId2 = pcs.spellId
WHERE s.`typeCat` IN (?a) AND pcs.`id` IN (?a)',
LEARN_SPELLS, [-5, -6, 9, 11], $ids
);
if ($spells)
{
$completion[Type::SPELL] = array_map(fn($x) => array_column($x, 'spellId'), $spells);
if ($recipes = array_map(fn($x) => array_filter(array_column($x, 'itemId')), $spells))
foreach ($ids as $id) // array_merge_recursive does not respect numeric keys
$completion[Type::ITEM][$id] = array_merge($completion[Type::ITEM][$id] ?? [], $recipes[$id] ?? []);
}
else
$completion[Type::SPELL] = [];
// init empty result sets
foreach ($completion as &$c)
foreach ($ids as $id)
if (!isset($c[$id]))
$c[$id] = [];
return $completion;
}
}
?>

View file

@ -0,0 +1 @@
UPDATE `aowow_dbversion` SET `build` = CONCAT(IFNULL(`build`, ''), ' globaljs tooltips');

View file

@ -905,6 +905,43 @@ Listview.templates = {
var _ = Listview.funcBox.getItemType;
return $WH.strcmp(_(a.classs, a.subclass, a.subsubclass).text, _(b.classs, b.subclass, b.subsubclass).text);
}
},
{
id: 'completed', // Listview.COLUMN_ID_COMPLETION
name: LANG.completion, // WH.TERMS.completion
hidden: true,
compute: function (item, td)
{
var skip = !item.hasOwnProperty('classs') || !Listview.templates.item._validCompletionCategory(item.classs, item.subclass, item.quality);
$WH.addCompletionIcons(td, 3, item.id, skip);
},
sortFunc: function (a, b)
{
// return $WH.stringCompare(
return $WH.strcmp(
$WH.getCompletionFlags(3, a.id),
$WH.getCompletionFlags(3, b.id)
);
},
getValue: function (item) {
var value = 0;
var completionData = g_user.completion?.hasOwnProperty(3) ? g_user.completion[3] : {};
if (!item.hasOwnProperty('classs') || !Listview.templates.item._validCompletionCategory(item.classs, item.subclass, item.quality))
return -1;
for (var i in g_user.characters)
{
var profile = g_user.characters[i];
if (!(profile.id in completionData))
continue;
if ($WH.in_array(completionData[profile.id], item.id) != -1)
value++;
}
return value;
}
}
],
@ -912,6 +949,12 @@ Listview.templates = {
return item.name.charAt(0) == '@' ? 'javascript:;' : '?item=' + item.id;
},
_validCompletionCategory: function (classs, subclass, quality) {
return $WH.in_array(g_completion_categories[3], classs) != -1 ||
$WH.in_array(g_completion_categories[3], '' + classs + '-' + subclass) != -1 ||
$WH.in_array(g_completion_categories[3], '' + classs + 'q' + quality) != -1
},
onBeforeCreate: function() {
var nComparable = false;
@ -930,6 +973,23 @@ Listview.templates = {
this.mode = Listview.MODE_CHECKBOX;
this._nComparable = nComparable;
}
for (var i in this.columns)
{
if (this.columns[i].id == 'completed' && this.columns[i].hidden)
{
if ($WH.isset('g_user') && 'characters' in g_user && $WH.in_array(this.hiddenCols, this.columns[i].id) == -1)
{
var n = 0;
for (var j in this.data)
if (this.data[j].hasOwnProperty('classs') && Listview.templates.item._validCompletionCategory(this.data[j].classs, this.data[j].subclass, this.data[j].quality))
n++;
if (n > this.data.length * 0.1)
this.visibility.push(parseInt(i));
}
}
}
},
createCbControls: function(div, topBar) {
@ -1148,7 +1208,7 @@ Listview.templates = {
}
}
else {
return - 1;
return -1;
}
},
sortFunc: function(a, b, col) {
@ -1902,11 +1962,69 @@ Listview.templates = {
var _ = Listview.funcBox.getQuestCategory;
return $WH.strcmp(_(a.category), _(b.category));
}
},
{
id: 'completed', // Listview.COLUMN_ID_COMPLETION
name: LANG.completion, // WH.TERMS.completion
hidden: true,
compute: function (quest, td)
{
if (quest.daily || quest.weekly)
return;
$WH.addCompletionIcons(td, 5, quest.id)
},
sortFunc: function (a, b)
{
// return $WH.stringCompare(
return $WH.strcmp(
$WH.getCompletionFlags(5, a.id),
$WH.getCompletionFlags(5, b.id)
);
},
getValue: function (quest) {
var value = 0;
var completionData = g_user.completion?.hasOwnProperty(5) ? g_user.completion[5] : {};
if (quest.daily || quest.weekly)
return -1;
for (var i in g_user.characters)
{
var profile = g_user.characters[i];
if (!(profile.id in completionData))
continue;
if ($WH.in_array(completionData[profile.id], quest.id) != -1)
value++;
}
return value;
}
}
],
getItemLink: function(quest) {
return '?quest=' + quest.id;
},
onBeforeCreate: function () {
for (var i in this.columns)
{
if (this.columns[i].id == 'completed' && this.columns[i].hidden)
{
if ($WH.isset('g_user') && 'characters' in g_user && $WH.in_array(this.hiddenCols, this.columns[i].id) == -1)
{
var n = 0;
for (var j in this.data)
if (!this.data[j].daily && !this.data[j].weekly)
n++;
if (n > this.data.length * 0.1)
this.visibility.push(parseInt(i));
}
}
}
}
},
@ -3432,12 +3550,74 @@ Listview.templates = {
return 0;
}
}
},
/* AoWoW: custom end */
{
id: 'completed', // Listview.COLUMN_ID_COMPLETION
name: LANG.completion, // WH.TERMS.completion
hidden: true,
compute: function (spell, td)
{
if (!spell.hasOwnProperty('cat') || !Listview.templates.spell._validCompletionCategory(spell.cat))
return;
$WH.addCompletionIcons(td, 6, spell.id)
},
sortFunc: function (a, b)
{
// return $WH.stringCompare(
return $WH.strcmp(
$WH.getCompletionFlags(6, a.id),
$WH.getCompletionFlags(6, b.id)
);
},
getValue: function (spell) {
var value = 0;
var completionData = g_user.completion?.hasOwnProperty(6) ? g_user.completion[6] : {};
if (!spell.hasOwnProperty('cat') || !Listview.templates.spell._validCompletionCategory(spell.cat))
return -1;
for (var i in g_user.characters)
{
var profile = g_user.characters[i];
if (!(profile.id in completionData))
continue;
if ($WH.in_array(completionData[profile.id], spell.id) != -1)
value++;
}
return value;
}
}
],
getItemLink: function(spell) {
return '?spell=' + spell.id;
},
_validCompletionCategory: function (category) {
return $WH.in_array(g_completion_categories[6], category) != -1;
},
onBeforeCreate: function () {
for (var i in this.columns)
{
if (this.columns[i].id == 'completed' && this.columns[i].hidden)
{
if ($WH.isset('g_user') && 'characters' in g_user && $WH.in_array(this.hiddenCols, this.columns[i].id) == -1)
{
var n = 0;
for (var j in this.data)
if (this.data[j].hasOwnProperty('cat') && Listview.templates.spell._validCompletionCategory(this.data[j].cat))
n++;
if (n > this.data.length * 0.1)
this.visibility.push(parseInt(i));
}
}
}
}
},
@ -5834,11 +6014,69 @@ Listview.templates = {
return $WH.strcmp(g_achievement_categories[a.category], g_achievement_categories[b.category]);
},
hidden: true
},
{
id: 'completed', // Listview.COLUMN_ID_COMPLETION
name: LANG.completion, // WH.TERMS.completion
hidden: true,
compute: function (achievement, td)
{
if (achievement.type)
return;
$WH.addCompletionIcons(td, 10, achievement.id)
},
sortFunc: function (a, b)
{
// return $WH.stringCompare(
return $WH.strcmp(
$WH.getCompletionFlags(10, a.id),
$WH.getCompletionFlags(10, b.id)
);
},
getValue: function (achievement) {
var value = 0;
var completionData = g_user.completion?.hasOwnProperty(10) ? g_user.completion[10] : {};
if (achievement.type)
return -1;
for (var i in g_user.characters)
{
var profile = g_user.characters[i];
if (!(profile.id in completionData))
continue;
if ($WH.in_array(completionData[profile.id], achievement.id) != -1)
value++;
}
return value;
}
}
],
getItemLink: function(achievement) {
return '?achievement=' + achievement.id;
},
onBeforeCreate: function () {
for (var i in this.columns)
{
if (this.columns[i].id == 'completed' && this.columns[i].hidden)
{
if ($WH.isset('g_user') && 'characters' in g_user && $WH.in_array(this.hiddenCols, this.columns[i].id) == -1)
{
var n = 0;
for (var j in this.data)
if (!this.data[j].type)
n++;
if (n > this.data.length * 0.1)
this.visibility.push(parseInt(i));
}
}
}
}
},
@ -6052,11 +6290,55 @@ Listview.templates = {
return $WH.strcmp(g_title_categories[a.category], g_title_categories[b.category]);
},
hidden: true
},
{
id: 'completed', // Listview.COLUMN_ID_COMPLETION
name: LANG.completion, // WH.TERMS.completion
hidden: true,
compute: function (title, td)
{
$WH.addCompletionIcons(td, 11, title.id)
},
sortFunc: function (a, b)
{
// return $WH.stringCompare(
return $WH.strcmp(
$WH.getCompletionFlags(11, a.id),
$WH.getCompletionFlags(11, b.id)
);
},
getValue: function (title) {
var value = 0;
var completionData = g_user.completion?.hasOwnProperty(11) ? g_user.completion[11] : {};
for (var i in g_user.characters)
{
var profile = g_user.characters[i];
if (!(profile.id in completionData))
continue;
if ($WH.in_array(completionData[profile.id], title.id) != -1)
value++;
}
return value;
}
}
],
getItemLink: function(title) {
return '?title=' + title.id;
},
onBeforeCreate: function () {
for (var i in this.columns)
{
if (this.columns[i].id == 'completed' && this.columns[i].hidden)
{
if ($WH.isset('g_user') && 'characters' in g_user && $WH.in_array(this.hiddenCols, this.columns[i].id) == -1)
this.visibility.push(parseInt(i));
}
}
}
},

View file

@ -17,3 +17,137 @@ function g_getProfileUrl(profile) {
function g_getProfileRealmUrl(profile) {
return '?profiles=' + profile.region + '.' + profile.realm;
}
$WH.prepInfobox = function () {
$('.infobox').each(function ()
{
var row = $(this);
if (row.data('infobox-completion-info-added') !== true && g_user.characters &&
typeof g_pageInfo == 'object' && typeof g_pageInfo.type == 'number' && typeof g_pageInfo.typeId == 'number')
{
var wardrobe = $('.compact-completion-display', row);
if (wardrobe.length)
{
var completionIcon = $('span', wardrobe);
if (completionIcon.length)
{
var i = 0;
completionIcon.each(function ()
{
var e = $(this);
var t = e.html();
try { t = JSON.parse(t) }
catch (e) { return }
var a;
for (var n = 0, s; s = g_user.characters[n]; n++)
{
if (s.id == t.id)
{
a = s;
break
}
}
if (a)
{
e.parent().append($WH.createCompletionIcon(a, t.completed ? 1 : 0, t.rel));
e.remove();
i++
}
});
if (i)
wardrobe.parent().parent().show()
}
else if (wardrobe.is(':empty') && $WH.addCompletionIcons(wardrobe.get(0), g_pageInfo.type, g_pageInfo.typeId))
wardrobe.parent().parent().show()
}
row.data('infobox-completion-info-added', true)
}
});
};
$WH.addCompletionIcons = function (parent, type, typeIdOrData, skipIncomplete) {
var nComplete = 0;
for (var i in g_user.characters)
{
if (!g_user.characters.hasOwnProperty(i))
continue;
let profile = g_user.characters[i];
let completion = 0;
let completionData = g_user.completion?.hasOwnProperty(type) ? g_user.completion[type] : {};
if (!completionData.hasOwnProperty(profile.id))
continue;
completion = completionData[profile.id].includes(typeIdOrData) ? 1 : 0;
if (skipIncomplete && !completion)
continue;
$WH.ae(parent, $WH.createCompletionIcon(profile, completion));
nComplete++;
}
return nComplete;
};
$WH.createCompletionIcon = function (profile, completePct, rel) {
var icon = $WH.ce('a');
icon.href = '?profile=' + profile.region + '.' + profile.realm + '.' + profile.name;
// aowow - so the generic tooltips dont override our completion tooltip
icon.setAttribute('data-disable-wowhead-tooltip', true);
icon.className = 'progress-icon progress-' + (completePct ? Math.max(1, Math.floor(completePct * 8)) : 0);
$WH.Tooltip.simple(icon, $WH.getCompletionTooltip(profile, completePct), null, true);
if (rel)
icon.rel = rel;
return icon;
};
$WH.getCompletionTooltip = function (profile, completePct) {
let tooltip = $WH.ce('div');
$WH.ae(tooltip, $WH.ce('span', { className: 'q' }, $WH.ct((completePct >= 1 ? LANG.complete : LANG.incomplete) + LANG.colon)));
$WH.ae(tooltip, $WH.ce('br'));
let charRow = $WH.ce('span', { style: { whiteSpace: 'nowrap' } });
$WH.ae(tooltip, charRow);
$WH.ae(charRow, $WH.ce('b', { className: 'c' + profile.classs }, $WH.ct(profile.name)));
let server = [' ', profile.realmname];
if (profile.hasOwnProperty('region'))
server.push(profile.region.toUpperCase());
$WH.ae(charRow, $WH.ce('span', { className: 'q0' }, $WH.ct(server.join(' '))));
if (completePct > 0 && completePct < 1)
$WH.ae(charRow, $WH.ct( $WH.sprintf(LANG.parens_format, '', Math.round(completePct * 100) + '%') ));
return tooltip.innerHTML;
};
$WH.getCompletionFlags = function (type, typeId) {
var flags = 0;
var profiles = g_user.characters || [];
let completionData = g_user.completion?.hasOwnProperty(type) ? g_user.completion[type] : {};
for (var i = profiles.length - 1; i >= 0; i--)
{
var profile = profiles[i];
if (!(profile.id in completionData))
continue
flags = flags << 1 | (completionData[profile.id].includes(typeId) ? 1 : 0)
}
return flags;
};

View file

@ -269,6 +269,12 @@ var g_types = {
504: 'mail'
};
var g_completion_categories = {
// 1: [12], // NPCs: Battle Pets
3: [9, "15-2", "15-5", "15--7"], // Items: Recipes, Minipets, Mounts (Ground), Mounts (Flying)
6: [-5, -6, 9, 11] // Spells: Mounts, Minipets, Sec. Skills, Prim. Skills
};
// Items
$WH.cO(g_items, {
add: function(id, json)

View file

@ -644,6 +644,49 @@ if (typeof $WowheadPower == "undefined") {
}
}
if (!isRemote && window.g_user && g_user.characters)
{
var completion = '';
let completionData = g_user.completion.hasOwnProperty(currentType) ? g_user.completion[currentType] : false;
let entity = {};
if (currentType == TYPE_QUEST && $WH.isset('g_quests'))
entity = g_quests[currentId] || {};
if (currentType == TYPE_ACHIEVEMENT && $WH.isset('g_achievements'))
entity = g_achievements[currentId] || {};
if (currentType == TYPE_ITEM && $WH.isset('g_items'))
entity = g_items[currentId] || {};
if (currentType == TYPE_SPELL && $WH.isset('g_spells'))
entity = g_spells[currentId] || {};
if ((!LOOKUPS[currentType][0] || LOOKUPS[currentType][0][currentId].status[currentLocale] !== STATUS_OK) ||
(currentType === TYPE_QUEST && (entity.daily || entity.weekly)) ||
(currentType === TYPE_ACHIEVEMENT && entity.type))
completionData = false;
let CompetionWithoutCatg = !(completionData && currentType in g_completion_categories && $WH.in_array(g_completion_categories[currentType], entity.completion_category) === -1);
if (completionData)
{
for (var i in g_user.characters)
{
var profile = g_user.characters[i];
if (!(profile.id in completionData))
continue;
let isComplete = $WH.in_array(completionData[profile.id], currentId) !== - 1;
if (!isComplete && !CompetionWithoutCatg)
continue;
completion += '<br><span class="progress-icon ' + (isComplete ? 'progress-8' : 'progress-0') + '"></span> ';
completion += profile.name + ' - ' + profile.realmname + ' ' + profile.region.toUpperCase();
}
}
if (completion !== '')
html += '<br><span class="q">' + LANG.completion + ':</span>' + completion;
}
if (currentParams.map && map && map.getMap) {
html2 = map.getMap();
}

View file

@ -4260,3 +4260,33 @@ a.button-red.fa-clipboard > em > span {
.fav-star-1 {
background-position: -65px center;
}
/* imported from lists */
.compact-completion-display a {
margin-left: 2px;
vertical-align: text-top; /* middle; */
}
.progress-icon {
/* background: url(/images/ListManager/completion.png?4) no-repeat; */
background: url(../images/ui/check.png) no-repeat -1px -15px;
border-radius: 99px;
display: inline-block;
height: 13px; /* 16px; */
line-height: 16px;
vertical-align: sub; /* bottom; */
width: 13px; /* 16px; */
}
.progress-icon:focus {
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.5);
}
/* newer atlas has 9 icons */
.progress-icon.progress-8 {
background-position: -1px 0px;
}
.progress-icon.with-text {
padding-left: 16px;
}

View file

@ -8538,10 +8538,15 @@ function ProfilerCompletion(_parent) {
_tabsListview.show((_subtotal[_category].complete[_subcategory] ? 2 : 3));
if (_opt.subname) {
_listview.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_listview, _listview.columns[_listview.columns.length - 2], ''));
_excluded.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_excluded, _listview.columns[_listview.columns.length - 2], ''));
setTimeout(Listview.headerFilter.bind(_listview, _listview.columns[_listview.columns.length - 2], _opt.subname(_subcategory)), 1);
setTimeout(Listview.headerFilter.bind(_excluded, _excluded.columns[_excluded.columns.length - 2], _opt.subname(_subcategory)), 1);
// aowow - adressing col by offset breaks everytime we add/remove cols in a listview template
// _listview.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_listview, _listview.columns[_listview.columns.length - 2], ''));
// _excluded.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_excluded, _listview.columns[_listview.columns.length - 2], ''));
// setTimeout(Listview.headerFilter.bind(_listview, _listview.columns[_listview.columns.length - 2], _opt.subname(_subcategory)), 1);
// setTimeout(Listview.headerFilter.bind(_excluded, _excluded.columns[_excluded.columns.length - 2], _opt.subname(_subcategory)), 1);
_listview.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_listview, _listview.columns.find((x) => x.id == (_opt.catgcol || 'category')), ''));
_excluded.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_excluded, _listview.columns.find((x) => x.id == (_opt.catgcol || 'category')), ''));
setTimeout(Listview.headerFilter.bind(_listview, _listview.columns.find((x) => x.id == (_opt.catgcol || 'category')), _opt.subname(_subcategory)), 1);
setTimeout(Listview.headerFilter.bind(_excluded, _excluded.columns.find((x) => x.id == (_opt.catgcol || 'category')), _opt.subname(_subcategory)), 1);
}
}
}

View file

@ -4899,6 +4899,12 @@ var LANG = {
/* AoWoW: start custom */
// Profiler completions import
completion: 'Vervollständigung', // WH.TERMS.completion
complete: 'Vollständig', // WH.TERMS.complete
incomplete: 'Unvollständig', // WH.TERMS.incomplete
parens_format: '$1 ($2)', // WH.TERMS.parens_format
// click to copy fn
copied: 'Kopiert',
clickToCopy: 'Klicke zum Kopieren',

View file

@ -4947,6 +4947,12 @@ var LANG = {
/* AoWoW: start custom */
// Profiler completions import
completion: 'Completion', // WH.TERMS.completion
complete: 'Complete', // WH.TERMS.complete
incomplete: 'Incomplete', // WH.TERMS.incomplete
parens_format: '$1 ($2)', // WH.TERMS.parens_format
// click to copy fn
copied: 'Copied',
clickToCopy: 'Click to Copy',

View file

@ -4901,6 +4901,12 @@ var LANG = {
/* AoWoW: start custom */
// Profiler completions import
completion: 'Terminación', // WH.TERMS.completion
complete: 'Completo', // WH.TERMS.complete
incomplete: 'Incompleto', // WH.TERMS.incomplete
parens_format: '$1 ($2)', // WH.TERMS.parens_format
// click to copy fn
copied: 'Copiado',
clickToCopy: 'Click para copiar',

View file

@ -4901,6 +4901,12 @@ var LANG = {
/* AoWoW: start custom */
// Profiler completions import
completion: 'Achèvement', // WH.TERMS.completion
complete: 'Complète', // WH.TERMS.complete
incomplete: 'Incomplet', // WH.TERMS.incomplete
parens_format: '$1 ($2)', // WH.TERMS.parens_format
// click to copy fn
copied: 'Copié',
clickToCopy: 'Cliquer pour Copier',

View file

@ -4903,6 +4903,12 @@ var LANG = {
/* AoWoW: start custom */
// Profiler completions import
completion: 'Завершено', // WH.TERMS.completion
complete: 'Завершено', // WH.TERMS.complete
incomplete: 'Не завершено', // WH.TERMS.incomplete
parens_format: '$1 ($2)', // WH.TERMS.parens_format
// click to copy fn
copied: 'Скопировано',
clickToCopy: 'Нажмите, чтобы скопировать',

View file

@ -4927,6 +4927,12 @@ var LANG = {
/* AoWoW: start custom */
// Profiler completions import
completion: '达成', // WH.TERMS.completion
complete: '完成', // WH.TERMS.complete
incomplete: '未完成', // WH.TERMS.incomplete
parens_format: '$1$2', // WH.TERMS.parens_format
// click to copy fn
copied: '已复制',
clickToCopy: '点击复制',

View file

@ -51,6 +51,7 @@ echo " <table class=\"infobox\">\n";
?>
<tr><th id="infobox-videos"><?=Lang::main('videos'); ?></th></tr>
<tr><td><div class="infobox-spacer"></div><div id="infobox-sticky-vi"></div></td></tr>
<script type="text/javascript">$WH.prepInfobox()</script>
<?php
endif;