Template/Update (Part 35)

* convert dbtype 'icon'
 * improve on IconlistFilter
This commit is contained in:
Sarjuuk
2025-08-13 21:23:09 +02:00
parent 1672883186
commit 0cf9069eb1
7 changed files with 344 additions and 304 deletions

158
endpoints/icon/icon.php Normal file
View File

@@ -0,0 +1,158 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class IconBaseResponse extends TemplateResponse implements ICache
{
use TrDetailPage, TrCache;
protected int $cacheType = CACHE_TYPE_PAGE;
protected string $template = 'icon';
protected string $pageName = 'icon';
protected ?int $activeTab = parent::TAB_DATABASE;
protected array $breadcrumb = [0, 31];
public int $type = Type::ICON;
public int $typeId = 0;
public string $icon = '';
private IconList $subject;
public function __construct(string $id)
{
parent::__construct($id);
$this->typeId = intVal($id);
$this->contribute = Type::getClassAttrib($this->type, 'contribute') ?? CONTRIBUTE_NONE;
}
protected function generate() : void
{
$this->subject = new IconList(array(['id', $this->typeId]));
if ($this->subject->error)
$this->generateNotFound(Lang::game('icon'), Lang::icon('notFound'));
$this->extendGlobalData($this->subject->getJSGlobals());
$this->h1 = $this->subject->getField('name');
$this->icon = $this->subject->getField('name', true, true);
$this->gPageInfo += array(
'type' => $this->type,
'typeId' => $this->typeId,
'name' => $this->h1
);
/*************/
/* Menu Path */
/*************/
$cats = [1 => 'nItems', 2 => 'nSpells', 3 => 'nAchievements', 6 => 'nCurrencies', 9 => 'nPets'/* , 11 => '' */];
$crumb = '';
foreach ($cats as $cat => $field)
{
if (!$this->subject->getField($field))
continue;
if ($crumb)
{
$crumb = 0;
break;
}
$crumb = $cat;
}
if ($crumb)
$this->breadcrumb[] = $crumb;
/**************/
/* Page Title */
/**************/
array_unshift($this->title, $this->h1, Util::ucFirst(Lang::game('icon')));
/****************/
/* Main Content */
/****************/
$this->redButtons = array(
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId],
BUTTON_WOWHEAD => false
);
/**************/
/* Extra Tabs */
/**************/
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
// used by: spell
$ubSpells = new SpellList(array(['iconId', $this->typeId]));
if (!$ubSpells->error)
{
$this->extendGlobalData($ubSpells->getJsGlobals(GLOBALINFO_RELATED | GLOBALINFO_SELF));
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $ubSpells->getListviewData(),
'id' => 'used-by-spell'
), SpellList::$brickFile));
}
// used by: item
$ubItems = new ItemList(array(['iconId', $this->typeId]));
if (!$ubItems->error)
{
$this->extendGlobalData($ubItems->getJsGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $ubItems->getListviewData(),
'id' => 'used-by-item'
), ItemList::$brickFile));
}
// used by: achievement
$ubAchievements = new AchievementList(array(['iconId', $this->typeId]));
if (!$ubAchievements->error)
{
$this->extendGlobalData($ubAchievements->getJsGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $ubAchievements->getListviewData(),
'id' => 'used-by-achievement'
), AchievementList::$brickFile));
}
// used by: currency
$ubCurrencies = new CurrencyList(array(['iconId', $this->typeId]));
if (!$ubCurrencies->error)
{
$this->extendGlobalData($ubCurrencies->getJsGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $ubCurrencies->getListviewData(),
'id' => 'used-by-currency'
), CurrencyList::$brickFile));
}
// used by: hunter pet
$ubPets = new PetList(array(['iconId', $this->typeId]));
if (!$ubPets->error)
{
$this->extendGlobalData($ubPets->getJsGlobals());
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $ubPets->getListviewData(),
'id' => 'used-by-pet'
), PetList::$brickFile));
}
parent::generate();
}
}
?>

109
endpoints/icons/icons.php Normal file
View File

@@ -0,0 +1,109 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class IconsBaseResponse extends TemplateResponse implements ICache
{
use TrListPage, TrCache;
protected int $type = Type::ICON;
protected int $cacheType = CACHE_TYPE_PAGE;
protected string $template = 'icons';
protected string $pageName = 'icons';
protected ?int $activeTab = parent::TAB_DATABASE;
protected array $breadcrumb = [0, 31];
protected array $scripts = [[SC_JS_FILE, 'js/filters.js']];
protected array $expectedGET = array(
'filter' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Filter::PATTERN_PARAM]]
);
protected array $validCats = [0, 1, 2, 3];
public function __construct(string $pageParam)
{
$this->getCategoryFromUrl($pageParam);
parent::__construct($pageParam);
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
$this->filter = new IconListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
$this->filterError = $this->filter->error;
}
protected function generate() : void
{
$this->h1 = Util::ucWords(Lang::game('icons'));
$conditions = [600]; // LIMIT 600 - fits better onto the grid
if (!User::isInGroup(U_GROUP_EMPLOYEE))
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
$this->filter->evalCriteria();
if ($_ = $this->filter->getConditions())
$conditions[] = $_;
$this->filterError = $this->filter->error; // maybe the evalX() caused something
/**************/
/* Page Title */
/**************/
$title = $this->h1;
$setCr = $this->filter->getSetCriteria(1, 2, 3, 6, 9, 11);
if (count($setCr) == 1)
$title = match ($setCr[0])
{
1 => Util::ucFirst(Lang::game('item')),
2 => Util::ucFirst(Lang::game('spell')),
3 => Util::ucFirst(Lang::game('achievement')),
6 => Util::ucFirst(Lang::game('currency')),
9 => Util::ucFirst(Lang::game('pet')),
11 => Util::ucFirst(Lang::game('class')),
} . ' ' . $this->h1;
array_unshift($this->title, $title);
/*************/
/* Menu Path */
/*************/
if (count($setCr) == 1)
$this->breadcrumb[] = $setCr[0];
/****************/
/* Main Content */
/****************/
$this->redButtons[BUTTON_WOWHEAD] = true;
if ($fiQuery = $this->filter->buildGETParam())
$this->wowheadLink .= '&filter='.$fiQuery;
$icons = new IconList($conditions, ['calcTotal' => true]);
$tabData['data'] = $icons->getListviewData();
$this->extendGlobalData($icons->getJSGlobals());
if ($icons->getMatches() > $conditions[0]) // LIMIT
{
$tabData['note'] = sprintf(Util::$tryFilteringEntityString, $icons->getMatches(), 'LANG.types[29][3]', $conditions[0]);
$tabData['_truncated'] = 1;
}
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
$this->lvTabs->addListviewTab(new Listview($tabData, IconList::$brickFile));
parent::generate();
}
}
?>

View File

@@ -101,7 +101,7 @@ class IconList extends DBTypeList
class IconListFilter extends Filter
{
private array $totalUses = [];
private array $iconTotals = [];
private array $criterion2field = array(
1 => '?_items', // items [num]
2 => '?_spell', // spells [num]
@@ -119,13 +119,13 @@ class IconListFilter extends Filter
protected string $type = 'icons';
protected static array $genericFilter = array(
1 => [parent::CR_CALLBACK, 'cbUseAny' ], // items [num]
2 => [parent::CR_CALLBACK, 'cbUseAny' ], // spells [num]
3 => [parent::CR_CALLBACK, 'cbUseAny' ], // achievements [num]
6 => [parent::CR_CALLBACK, 'cbUseAny' ], // currencies [num]
9 => [parent::CR_CALLBACK, 'cbUseAny' ], // hunterpets [num]
11 => [parent::CR_NYI_PH, null, 0], // classes [num]
13 => [parent::CR_CALLBACK, 'cbUseAll' ] // used [num]
1 => [parent::CR_CALLBACK, 'cbUsedBy' ], // items [num]
2 => [parent::CR_CALLBACK, 'cbUsedBy' ], // spells [num]
3 => [parent::CR_CALLBACK, 'cbUsedBy' ], // achievements [num]
6 => [parent::CR_CALLBACK, 'cbUsedBy' ], // currencies [num]
9 => [parent::CR_CALLBACK, 'cbUsedBy' ], // hunterpets [num]
11 => [parent::CR_NYI_PH, null, 0 ], // classes [num]
13 => [parent::CR_CALLBACK, 'cbUsedBy', true] // used [num]
);
protected static array $inputFields = array(
@@ -138,35 +138,6 @@ class IconListFilter extends Filter
public array $extraOpts = [];
private function _getCnd(string $op, int $val, string $tbl) : ?array
{
switch ($op)
{
case '>':
case '>=':
case '=':
$ids = DB::Aowow()->selectCol('SELECT `iconId` AS ARRAY_KEY, COUNT(*) AS "n" FROM ?# GROUP BY `iconId` HAVING n '.$op.' '.$val, $tbl);
return $ids ? ['id', array_keys($ids)] : [1];
case '<=':
if ($val)
$op = '>';
break;
case '<':
if ($val)
$op = '>=';
break;
case '!=':
if ($val)
$op = '=';
break;
default:
return null;
}
$ids = DB::Aowow()->selectCol('SELECT `iconId` AS ARRAY_KEY, COUNT(*) AS "n" FROM ?# GROUP BY `iconId` HAVING n '.$op.' '.$val, $tbl);
return $ids ? ['id', array_keys($ids), '!'] : [1];
}
protected function createSQLForValues() : array
{
$parts = [];
@@ -180,47 +151,54 @@ class IconListFilter extends Filter
return $parts;
}
protected function cbUseAny(int $cr, int $crs, string $crv) : ?array
protected function cbUsedBy(int $cr, int $crs, string $crv, ?bool $all = false) : ?array
{
if (Util::checkNumeric($crv, NUM_CAST_INT) && $this->int2Op($crs))
return $this->_getCnd($crs, $crv, $this->criterion2field[$cr]);
return null;
}
protected function cbUseAll(int $cr, int $crs, string $crv) : ?array
{
if (!Util::checkNumeric($crv, NUM_CAST_INT) || !$this->int2Op($crs))
if (!Util::checkNumeric($crv, NUM_CAST_INT) || ![$filter, $negate] = $this->int2Filter($crs, $crv))
return null;
if (!$this->totalUses)
{
foreach ($this->criterion2field as $tbl)
{
if (!$tbl)
continue;
$total = $this->prepareIconTotals($all ? 0 : $cr);
$res = DB::Aowow()->selectCol('SELECT `iconId` AS ARRAY_KEY, COUNT(*) AS "n" FROM ?# GROUP BY `iconId`', $tbl);
Util::arraySumByKey($this->totalUses, $res);
}
}
$ids = array_filter($total, $filter);
if ($crs == '=')
$crs = '==';
$op = $crs;
if ($crs == '<=' && $crv)
$op = '>';
else if ($crs == '<' && $crv)
$op = '>=';
else if ($crs == '!=' && $crv)
$op = '==';
$ids = array_filter($this->totalUses, fn($x) => eval('return '.$x.' '.$op.' '.$crv.';'));
if ($crs != $op)
if ($negate)
return $ids ? ['id', array_keys($ids), '!'] : [1];
else
return $ids ? ['id', array_keys($ids)] : ['id', array_keys($this->totalUses), '!'];
return $ids ? ['id', array_keys($ids)] : ['id', array_keys($total), '!'];
}
private function int2Filter(mixed $op, int $y) : ?array
{
return match ($op) {
1 => [fn($x) => $x > $y, false],
2 => [fn($x) => $x >= $y, false],
3 => [fn($x) => $x == $y, false],
4 => [fn($x) => $x > $y, true],
5 => [fn($x) => $x >= $y, true],
6 => [fn($x) => $x == $y, true],
default => null
};
}
private function prepareIconTotals(int $forCr = 0) : array
{
foreach ($this->criterion2field as $cr => $tbl)
{
if (!$tbl || isset($this->iconTotals[$cr]) || ($forCr && $forCr != $cr))
continue;
$this->iconTotals[$cr] = DB::Aowow()->selectCol('SELECT `iconId` AS ARRAY_KEY, COUNT(*) AS "n" FROM ?# GROUP BY `iconId`', $tbl);
}
if ($forCr)
return $this->iconTotals[$forCr];
if (!isset($this->iconTotals['all']))
{
$this->iconTotals['all'] = [];
Util::arraySumByKey($this->iconTotals['all'], ...$this->iconTotals);
}
return $this->iconTotals['all'];
}
}

View File

@@ -1,120 +0,0 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
// menuId 31: Icons g_initPath()
// tabId 0: Database g_initHeader()
class IconPage extends GenericPage
{
use TrDetailPage;
protected $icon = '';
protected $type = Type::ICON;
protected $typeId = 0;
protected $tpl = 'icon';
protected $path = [0, 31];
protected $tabId = 0;
protected $mode = CACHE_TYPE_PAGE;
public function __construct($pageCall, $id)
{
parent::__construct($pageCall, $id);
$this->typeId = intVal($id);
$this->subject = new IconList(array(['id', $this->typeId]));
if ($this->subject->error)
$this->notFound(Lang::game('icon'), Lang::icon('notFound'));
$this->extendGlobalData($this->subject->getJSGlobals());
$this->name = $this->subject->getField('name');
$this->icon = $this->subject->getField('name', true, true);
}
protected function generateContent()
{
/****************/
/* Main Content */
/****************/
$this->redButtons = array(
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId],
BUTTON_WOWHEAD => false
);
/**************/
/* Extra Tabs */
/**************/
// used by: spell
$ubSpells = new SpellList(array(['iconId', $this->typeId]));
if (!$ubSpells->error)
{
$this->extendGlobalData($ubSpells->getJsGlobals(GLOBALINFO_RELATED | GLOBALINFO_SELF));
$this->lvTabs[] = [SpellList::$brickFile, array(
'data' => array_values($ubSpells->getListviewData()),
'id' => 'used-by-spell'
)];
}
// used by: item
$ubItems = new ItemList(array(['iconId', $this->typeId]));
if (!$ubItems->error)
{
$this->extendGlobalData($ubItems->getJsGlobals());
$this->lvTabs[] = [ItemList::$brickFile, array(
'data' => array_values($ubItems->getListviewData()),
'id' => 'used-by-item'
)];
}
// used by: achievement
$ubAchievements = new AchievementList(array(['iconId', $this->typeId]));
if (!$ubAchievements->error)
{
$this->extendGlobalData($ubAchievements->getJsGlobals());
$this->lvTabs[] = [AchievementList::$brickFile, array(
'data' => array_values($ubAchievements->getListviewData()),
'id' => 'used-by-achievement'
)];
}
// used by: currency
$ubCurrencies = new CurrencyList(array(['iconId', $this->typeId]));
if (!$ubCurrencies->error)
{
$this->extendGlobalData($ubCurrencies->getJsGlobals());
$this->lvTabs[] = [CurrencyList::$brickFile, array(
'data' => array_values($ubCurrencies->getListviewData()),
'id' => 'used-by-currency'
)];
}
// used by: hunter pet
$ubPets = new PetList(array(['iconId', $this->typeId]));
if (!$ubPets->error)
{
$this->extendGlobalData($ubPets->getJsGlobals());
$this->lvTabs[] = [PetList::$brickFile, array(
'data' => array_values($ubPets->getListviewData()),
'id' => 'used-by-pet'
)];
}
}
protected function generateTitle()
{
array_unshift($this->title, $this->name, Util::ucFirst(Lang::game('icon')));
}
protected function generatePath() { }
}
?>

View File

@@ -1,96 +0,0 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
// menuId 31: Icons g_initPath()
// tabId 0: Database g_initHeader()
class IconsPage extends GenericPage
{
use TrListPage;
protected $type = Type::ICON;
protected $tpl = 'icons';
protected $path = [0, 31];
protected $tabId = 0;
protected $mode = CACHE_TYPE_PAGE;
protected $scripts = [[SC_JS_FILE, 'js/filters.js']];
protected $_get = ['filter' => ['filter' => FILTER_UNSAFE_RAW]];
public function __construct($pageCall)
{
parent::__construct($pageCall);
$this->filterObj = new IconListFilter($this->_get['filter'] ?? '');
$this->name = Util::ucFirst(Lang::game('icons'));
}
protected function generateContent()
{
$tabData = array(
'data' => [],
);
$sqlLimit = 600; // fits better onto the grid
$conditions = [$sqlLimit];
if (!User::isInGroup(U_GROUP_EMPLOYEE))
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
$this->filterObj->evalCriteria();
if ($_ = $this->filterObj->getConditions())
$conditions[] = $_;
$icons = new IconList($conditions, ['calcTotal' => true]);
$tabData['data'] = array_values($icons->getListviewData());
$this->extendGlobalData($icons->getJSGlobals());
if ($icons->getMatches() > $sqlLimit)
{
$tabData['note'] = sprintf(Util::$tryFilteringEntityString, $icons->getMatches(), 'LANG.types[29][3]', $sqlLimit);
$tabData['_truncated'] = 1;
}
if ($this->filterObj->error)
$tabData['_errors'] = 1;
$this->lvTabs[] = [IconList::$brickFile, $tabData];
}
protected function generateTitle()
{
$title = $this->name;
$setCr = $this->filterObj->getSetCriteria(1, 2, 3, 6, 9, 11);
if (count($setCr) == 1)
{
$title = match($setCr[0])
{
1 => Util::ucFirst(Lang::game('item')),
2 => Util::ucFirst(Lang::game('spell')),
3 => Util::ucFirst(Lang::game('achievement')),
6 => Util::ucFirst(Lang::game('currency')),
9 => Util::ucFirst(Lang::game('pet')),
11 => Util::ucFirst(Lang::game('class'))
} . ' ' . $title;
}
array_unshift($this->title, $title);
}
protected function generatePath()
{
$setCr = $this->filterObj->getSetCriteria(1, 2, 3, 6, 9, 11);
if (count($setCr) == 1)
$this->path[] = $setCr[0];
}
}
?>

View File

@@ -1,7 +1,10 @@
<?php namespace Aowow; ?>
<?php
namespace Aowow\Template;
<?php $this->brick('header'); ?>
use \Aowow\Lang;
$this->brick('header');
?>
<div class="main" id="main">
<div class="main-precontents" id="main-precontents"></div>
<div class="main-contents" id="main-contents">
@@ -19,20 +22,20 @@
$this->brick('redButtons');
?>
<h1><?=$this->name; ?></h1>
<h1><?=$this->h1; ?></h1>
<div id="h1-icon-0" class="h1-icon"></div>
<script type="text/javascript">//<![CDATA[
$WH.ge('h1-icon-0').appendChild(Icon.create("<?=$this->icon;?>", 2));
//]]></script>
<?php
$this->brick('article');
$this->brick('markup', ['markup' => $this->article]);
?>
<div class="clear"></div>
<h2 class="clear"><?=Lang::main('related'); ?></h2>
</div>
<?php
$this->brick('lvTabs', ['relTabs' => true]);
$this->brick('lvTabs');
$this->brick('contribute');
?>

View File

@@ -1,10 +1,11 @@
<?php namespace Aowow; ?>
<?php
$this->brick('header');
$f = $this->filterObj->values // shorthand
?>
namespace Aowow\Template;
use \Aowow\Lang;
$this->brick('header');
$f = $this->filter->values; // shorthand
?>
<div class="main" id="main">
<div class="main-precontents" id="main-precontents"></div>
<div class="main-contents" id="main-contents">
@@ -12,17 +13,24 @@ $f = $this->filterObj->values // shorthand
<?php
$this->brick('announcement');
$this->brick('pageTemplate', ['fiQuery' => $this->filterObj->query, 'fiMenuItem' => [101]]);
$this->brick('pageTemplate', ['fiQuery' => $this->filter->query, 'fiMenuItem' => [31]]);
?>
<div id="fi" style="display: <?=($this->filterObj->query ? 'block' : 'none'); ?>;">
<div id="fi" style="display: <?=($this->filter->query ? 'block' : 'none'); ?>;">
<form action="?filter=icons" method="post" name="fi" onsubmit="return fi_submit(this)" onreset="return fi_reset(this)">
<div class="text">
<?php
$this->brick('headIcons');
$this->brick('redButtons');
?>
<h1><?=$this->h1; ?></h1>
</div>
<table>
<tr>
<td><?=Util::ucFirst(Lang::main('name')).Lang::main('colon'); ?></td>
<td><?=$this->ucFirst(Lang::main('name')).Lang::main('colon'); ?></td>
<td colspan="2">
<table><tr>
<td>&nbsp;<input type="text" name="na" size="30" <?=(isset($f['na']) ? 'value="'.Util::htmlEscape($f['na']).'" ' : null); ?>/></td>
<td>&nbsp;<input type="text" name="na" size="30" <?=($f['na'] ? 'value="'.$this->escHTML($f['na']).'" ' : ''); ?>/></td>
</tr></table>
</td>
</tr><tr>
@@ -31,7 +39,7 @@ $this->brick('pageTemplate', ['fiQuery' => $this->filterObj->query, 'fiMenuItem'
<div id="fi_criteria" class="padded criteria"><div></div></div><div><a href="javascript:;" id="fi_addcriteria" onclick="fi_addCriterion(this); return false"><?=Lang::main('addFilter'); ?></a></div>
<div class="padded2">
<?=Lang::main('match').Lang::main('colon'); ?><input type="radio" name="ma" value="" id="ma-0" <?=(!isset($f['ma']) ? 'checked="checked" ' : null); ?>/><label for="ma-0"><?=Lang::main('allFilter'); ?></label><input type="radio" name="ma" value="1" id="ma-1" <?=(isset($f['ma']) ? 'checked="checked" ' : null); ?> /><label for="ma-1"><?=Lang::main('oneFilter'); ?></label>
<?=Lang::main('match'); ?><input type="radio" name="ma" value="" id="ma-0" <?=(!$f['ma'] ? 'checked="checked" ' : ''); ?>/><label for="ma-0"><?=Lang::main('allFilter'); ?></label><input type="radio" name="ma" value="1" id="ma-1" <?=($f['ma'] ? 'checked="checked" ' : ''); ?> /><label for="ma-1"><?=Lang::main('oneFilter'); ?></label>
</div>
<div class="clear"></div>
@@ -45,7 +53,7 @@ $this->brick('pageTemplate', ['fiQuery' => $this->filterObj->query, 'fiMenuItem'
<div class="pad"></div>
</div>
<?php $this->brick('filter'); ?>
<?=$this->renderFilter(12); ?>
<?php $this->brick('lvTabs'); ?>