mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Future/Frontend
* create php classes, each mirroring a js object * each frontend class implements __toString and json_serialize and as such can be directly used by the template * also allows for sane object creation before js screams in agony * usage TBD
This commit is contained in:
@@ -28,7 +28,7 @@ class AjaxGetdescription extends AjaxHandler
|
|||||||
if (!User::canWriteGuide())
|
if (!User::canWriteGuide())
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
$desc = (new Markup($this->_post['description']))->stripTags();
|
$desc = Markup::stripTags($this->_post['description']);
|
||||||
|
|
||||||
return Lang::trimTextClean($desc, 120);
|
return Lang::trimTextClean($desc, 120);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ class CommunityContent
|
|||||||
|
|
||||||
foreach ($results as $r)
|
foreach ($results as $r)
|
||||||
{
|
{
|
||||||
(new Markup($r['body']))->parseGlobalsFromText(self::$jsGlobals);
|
Markup::parseTags($r['body'], self::$jsGlobals);
|
||||||
|
|
||||||
$reply = array(
|
$reply = array(
|
||||||
'commentid' => $commentId,
|
'commentid' => $commentId,
|
||||||
@@ -359,7 +359,7 @@ class CommunityContent
|
|||||||
$i = 0;
|
$i = 0;
|
||||||
foreach ($results as $r)
|
foreach ($results as $r)
|
||||||
{
|
{
|
||||||
(new Markup($r['body']))->parseGlobalsFromText(self::$jsGlobals);
|
Markup::parseTags($r['body'], self::$jsGlobals);
|
||||||
|
|
||||||
self::$jsGlobals[Type::USER][$r['userId']] = $r['userId'];
|
self::$jsGlobals[Type::USER][$r['userId']] = $r['userId'];
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ class CommunityContent
|
|||||||
$c['responseroles'] = $r['responseRoles'];
|
$c['responseroles'] = $r['responseRoles'];
|
||||||
$c['responseuser'] = $r['responseUser'];
|
$c['responseuser'] = $r['responseUser'];
|
||||||
|
|
||||||
(new Markup($r['responseBody']))->parseGlobalsFromText(self::$jsGlobals);
|
Markup::parseTags($r['responseBody'], self::$jsGlobals);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($r['editCount']) // lastEdit
|
if ($r['editCount']) // lastEdit
|
||||||
|
|||||||
69
includes/components/frontend/announcement.class.php
Normal file
69
includes/components/frontend/announcement.class.php
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class Announcement implements \JsonSerializable
|
||||||
|
{
|
||||||
|
public const MODE_PAGE_TOP = 0;
|
||||||
|
public const MODE_CONTENT_TOP = 1;
|
||||||
|
|
||||||
|
public const STATUS_DISABLED = 0;
|
||||||
|
public const STATUS_ENABLED = 1;
|
||||||
|
public const STATUS_DELETED = 2;
|
||||||
|
|
||||||
|
public readonly int $status;
|
||||||
|
private bool $editable = false;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public readonly int $id,
|
||||||
|
private string $name,
|
||||||
|
private LocString $text,
|
||||||
|
private int $mode = self::MODE_CONTENT_TOP,
|
||||||
|
int $status = self::STATUS_ENABLED,
|
||||||
|
private string $style = '')
|
||||||
|
{
|
||||||
|
// a negative id displays ENABLE/DISABLE and DELETE links for this announcement
|
||||||
|
// TODO - the ugroup check mirrors the js. Add other checks like ownership status? (ownership currently not stored)
|
||||||
|
if (User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU) /* && User::$id == $authorId */)
|
||||||
|
$this->editable = true;
|
||||||
|
|
||||||
|
if ($this->mode != self::MODE_PAGE_TOP && $this->mode != self::MODE_CONTENT_TOP)
|
||||||
|
$this->mode = self::MODE_PAGE_TOP;
|
||||||
|
|
||||||
|
if ($status != self::STATUS_DISABLED && $status != self::STATUS_ENABLED && $status != self::STATUS_DELETED)
|
||||||
|
$this->status = self::STATUS_DELETED;
|
||||||
|
else
|
||||||
|
$this->status = $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() : array
|
||||||
|
{
|
||||||
|
$json = array(
|
||||||
|
'parent' => 'announcement-' . abs($this->id),
|
||||||
|
'id' => $this->editable ? -$this->id : $this->id,
|
||||||
|
'mode' => $this->mode,
|
||||||
|
'status' => $this->status,
|
||||||
|
'name' => $this->name,
|
||||||
|
'text' => (string)$this->text // force LocString to naive string for display
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($this->style)
|
||||||
|
$json['style'] = $this->style;
|
||||||
|
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
if ($this->status == self::STATUS_DELETED)
|
||||||
|
return '';
|
||||||
|
|
||||||
|
return "new Announcement(".Util::toJSON($this).");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
50
includes/components/frontend/book.class.php
Normal file
50
includes/components/frontend/book.class.php
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class Book implements \JsonSerializable
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private array $pages, // js:array of html
|
||||||
|
private string $parent = 'book-generic', // HTMLNode.id
|
||||||
|
private ?int $page = null) // start page; defaults to 1
|
||||||
|
{
|
||||||
|
if (!$this->parent)
|
||||||
|
trigger_error(self::class.'::__construct - initialized without parent element', E_USER_WARNING);
|
||||||
|
|
||||||
|
if (!$this->pages)
|
||||||
|
trigger_error(self::class.'::__construct - initialized without content', E_USER_WARNING);
|
||||||
|
else
|
||||||
|
$this->pages = Util::parseHtmlText($this->pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function &iterate() : \Generator
|
||||||
|
{
|
||||||
|
reset($this->pages);
|
||||||
|
|
||||||
|
foreach ($this->pages as $idx => &$page)
|
||||||
|
yield $idx => $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() : array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($this as $prop => $val)
|
||||||
|
if ($val !== null && $prop[0] != '_')
|
||||||
|
$result[$prop] = $val;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
return "new Book(".Util::toJSON($this).");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
159
includes/components/frontend/iconelement.class.php
Normal file
159
includes/components/frontend/iconelement.class.php
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class IconElement
|
||||||
|
{
|
||||||
|
public const SIZE_SMALL = 0;
|
||||||
|
public const SIZE_MEDIUM = 1;
|
||||||
|
public const SIZE_LARGE = 2;
|
||||||
|
|
||||||
|
private const CREATE_ICON_TPL = "\$WH.ge('%s%d').appendChild(%s.createIcon(%s));\n";
|
||||||
|
|
||||||
|
private int $idx = 0;
|
||||||
|
private string $href = '';
|
||||||
|
private bool $noIcon = false;
|
||||||
|
|
||||||
|
public readonly string $quality;
|
||||||
|
public readonly ?string $align;
|
||||||
|
public readonly int $size;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public readonly int $type,
|
||||||
|
public readonly int $typeId,
|
||||||
|
public readonly string $text,
|
||||||
|
public readonly int|string $num = '',
|
||||||
|
public readonly int|string $qty = '',
|
||||||
|
?string $quality = null,
|
||||||
|
int $size = self::SIZE_MEDIUM,
|
||||||
|
bool $link = true,
|
||||||
|
string $url = '',
|
||||||
|
?string $align = null,
|
||||||
|
public readonly string $element = 'icontab-icon',
|
||||||
|
public ?string $extraText = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (is_numeric($quality))
|
||||||
|
$this->quality = 'q'.$quality;
|
||||||
|
else if ($quality !== null)
|
||||||
|
$this->quality = 'q';
|
||||||
|
else
|
||||||
|
$this->quality = '';
|
||||||
|
|
||||||
|
if ($size < self::SIZE_SMALL || $size > self::SIZE_LARGE)
|
||||||
|
{
|
||||||
|
trigger_error('IconElement::__construct - invalid icon size '.$size.'. Normalied to 1 [small]', E_USER_WARNING);
|
||||||
|
$this->size = self::SIZE_SMALL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$this->size = $size;
|
||||||
|
|
||||||
|
if ($align && !in_array($align, ['left', 'right', 'center', 'justify']))
|
||||||
|
{
|
||||||
|
trigger_error('IconElement::__construct - unset invalid align value "'.$align.'".', E_USER_WARNING);
|
||||||
|
$this->align = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$this->align = $align;
|
||||||
|
|
||||||
|
if ($type && $typeId && !Type::validateIds($type, $typeId))
|
||||||
|
{
|
||||||
|
$link = false;
|
||||||
|
trigger_error('IconElement::__construct - invalid typeId '.$typeId.' for '.Type::getFileString($type).'.', E_USER_WARNING);
|
||||||
|
}
|
||||||
|
else if (!$type || !$typeId)
|
||||||
|
$link = false;
|
||||||
|
|
||||||
|
if ($link || $url)
|
||||||
|
$this->href = $url ?: '?'.Type::getFileString($this->type).'='.$this->typeId;
|
||||||
|
|
||||||
|
// see Spell/Tools having icon container but no actual icon and having to be inline with other IconElements
|
||||||
|
$this->noIcon = !$typeId || !Type::hasIcon($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderContainer(int $lpad = 0, int &$iconIdxOffset = 0, bool $rowWrap = false) : string
|
||||||
|
{
|
||||||
|
if (!$this->noIcon)
|
||||||
|
$this->idx = ++$iconIdxOffset;
|
||||||
|
|
||||||
|
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||||
|
|
||||||
|
$td = $dom->createElement('td');
|
||||||
|
$th = $dom->createElement('th');
|
||||||
|
|
||||||
|
if ($this->noIcon) // see Spell/Tools or AchievementCriteria having no actual icon, but placeholder
|
||||||
|
{
|
||||||
|
$ul = $dom->createElement('ul');
|
||||||
|
$li = $dom->createElement('li');
|
||||||
|
$var = $dom->createElement('var', ' ');
|
||||||
|
$li->appendChild($var);
|
||||||
|
$ul->appendChild($li);
|
||||||
|
$th->appendChild($ul);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$th->setAttribute('id', $this->element . $this->idx);
|
||||||
|
if ($this->align)
|
||||||
|
$th->setAttribute('align', $this->align);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->href)
|
||||||
|
($a = $dom->createElement('a', $this->text))->setAttribute('href', $this->href);
|
||||||
|
else
|
||||||
|
$a = $dom->createTextNode($this->text);
|
||||||
|
|
||||||
|
if ($this->quality)
|
||||||
|
{
|
||||||
|
($sp = $dom->createElement('span'))->setAttribute('class', $this->quality);
|
||||||
|
$sp->appendChild($a);
|
||||||
|
$td->appendChild($sp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$td->appendChild($a);
|
||||||
|
|
||||||
|
// extraText can be HTML, so import it as a fragment
|
||||||
|
if ($this->extraText)
|
||||||
|
{
|
||||||
|
$fragment = $dom->createDocumentFragment();
|
||||||
|
$fragment->appendXML(' '.$this->extraText);
|
||||||
|
$td->appendChild($fragment);
|
||||||
|
}
|
||||||
|
// only for objectives list..?
|
||||||
|
if ($this->num && $this->size == self::SIZE_SMALL)
|
||||||
|
$td->appendChild($dom->createTextNode(' ('.$this->num.')'));
|
||||||
|
|
||||||
|
if ($rowWrap)
|
||||||
|
{
|
||||||
|
$tr = $dom->createElement('tr');
|
||||||
|
$tr->appendChild($th);
|
||||||
|
$tr->appendChild($td);
|
||||||
|
$dom->append($tr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$dom->append($th, $td);
|
||||||
|
|
||||||
|
return str_repeat(' ', $lpad) . $dom->saveHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
// $WH.ge('icontab-icon1').appendChild(g_spells.createIcon(40120, 1, '1-4', 0));
|
||||||
|
|
||||||
|
public function renderJS(int $lpad = 0) : string
|
||||||
|
{
|
||||||
|
if ($this->noIcon)
|
||||||
|
return '';
|
||||||
|
|
||||||
|
$params = [$this->typeId, $this->size];
|
||||||
|
if ($this->num || $this->qty)
|
||||||
|
$params[] = is_numeric($this->num) ? $this->num : "'".$this->num."'";
|
||||||
|
if ($this->qty)
|
||||||
|
$params[] = is_numeric($this->qty) ? $this->qty : "'".$this->qty."'";
|
||||||
|
|
||||||
|
return str_repeat(' ', $lpad) . sprintf(self::CREATE_ICON_TPL, $this->element, $this->idx, Type::getJSGlobalString($this->type), implode(', ', $params));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
49
includes/components/frontend/infoboxmarkup.class.php
Normal file
49
includes/components/frontend/infoboxmarkup.class.php
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class InfoboxMarkup extends Markup
|
||||||
|
{
|
||||||
|
public function __construct(private array $items = [], array $opts, string $parent = '')
|
||||||
|
{
|
||||||
|
parent::__construct('', $opts, $parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addItem(string $item, ?int $pos = null) : void
|
||||||
|
{
|
||||||
|
if (is_null($pos) || $pos >= count($this->items))
|
||||||
|
$this->items[] = $item;
|
||||||
|
else
|
||||||
|
array_splice($this->items, $pos, 0, $item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function append(string $text) : self
|
||||||
|
{
|
||||||
|
if ($this->items && !$this->__text)
|
||||||
|
$this->replace('[ul][li]' . implode('[/li][li]', $this->items) . '[/li][/ul]');
|
||||||
|
|
||||||
|
return parent::append($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
if ($this->items && !$this->__text)
|
||||||
|
$this->replace('[ul][li]' . implode('[/li][li]', $this->items) . '[/li][/ul]');
|
||||||
|
|
||||||
|
return parent::__toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJsGlobals() : array
|
||||||
|
{
|
||||||
|
if ($this->items && !$this->__text)
|
||||||
|
$this->replace('[ul][li]' . implode('[/li][li]', $this->items) . '[/li][/ul]');
|
||||||
|
|
||||||
|
return parent::getJsGlobals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
174
includes/components/frontend/listview.class.php
Normal file
174
includes/components/frontend/listview.class.php
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class Listview implements \JsonSerializable
|
||||||
|
{
|
||||||
|
public const MODE_DEFAULT = 0;
|
||||||
|
public const MODE_CHECKBOX = 1;
|
||||||
|
public const MODE_DIV = 2;
|
||||||
|
public const MODE_TILED = 3;
|
||||||
|
public const MODE_CALENDAR = 4;
|
||||||
|
public const MODE_FLEXGRID = 5;
|
||||||
|
|
||||||
|
private const TEMPLATES = array(
|
||||||
|
'achievement' => ['template' => 'achievement', 'id' => 'achievements', 'name' => '$LANG.tab_achievements' ],
|
||||||
|
'areatrigger' => ['template' => 'areatrigger', 'id' => 'areatrigger', ],
|
||||||
|
'calendar' => ['template' => 'holidaycal', 'id' => 'calendar', 'name' => '$LANG.tab_calendar' ],
|
||||||
|
'class' => ['template' => 'classs', 'id' => 'classes', 'name' => '$LANG.tab_classes' ],
|
||||||
|
'commentpreview' => ['template' => 'commentpreview', 'id' => 'comments', 'name' => '$LANG.tab_comments' ],
|
||||||
|
'npc' => ['template' => 'npc', 'id' => 'npcs', 'name' => '$LANG.tab_npcs' ],
|
||||||
|
'currency' => ['template' => 'currency', 'id' => 'currencies', 'name' => '$LANG.tab_currencies' ],
|
||||||
|
'emote' => ['template' => 'emote', 'id' => 'emotes', ],
|
||||||
|
'enchantment' => ['template' => 'enchantment', 'id' => 'enchantments', ],
|
||||||
|
'event' => ['template' => 'holiday', 'id' => 'holidays', 'name' => '$LANG.tab_holidays' ],
|
||||||
|
'faction' => ['template' => 'faction', 'id' => 'factions', 'name' => '$LANG.tab_factions' ],
|
||||||
|
'genericmodel' => ['template' => 'genericmodel', 'id' => 'same-model-as', 'name' => '$LANG.tab_samemodelas' ],
|
||||||
|
'icongallery' => ['template' => 'icongallery', 'id' => 'icons', ],
|
||||||
|
'item' => ['template' => 'item', 'id' => 'items', 'name' => '$LANG.tab_items' ],
|
||||||
|
'itemset' => ['template' => 'itemset', 'id' => 'itemsets', 'name' => '$LANG.tab_itemsets' ],
|
||||||
|
'mail' => ['template' => 'mail', 'id' => 'mails', ],
|
||||||
|
'model' => ['template' => 'model', 'id' => 'gallery', 'name' => '$LANG.tab_gallery' ],
|
||||||
|
'object' => ['template' => 'object', 'id' => 'objects', 'name' => '$LANG.tab_objects' ],
|
||||||
|
'pet' => ['template' => 'pet', 'id' => 'hunter-pets', 'name' => '$LANG.tab_pets' ],
|
||||||
|
'profile' => ['template' => 'profile', 'id' => 'profiles', 'name' => '$LANG.tab_profiles' ],
|
||||||
|
'quest' => ['template' => 'quest', 'id' => 'quests', 'name' => '$LANG.tab_quests' ],
|
||||||
|
'race' => ['template' => 'race', 'id' => 'races', 'name' => '$LANG.tab_races' ],
|
||||||
|
'replypreview' => ['template' => 'replypreview', 'id' => 'comment-replies', 'name' => '$LANG.tab_commentreplies'],
|
||||||
|
'reputationhistory' => ['template' => 'reputationhistory', 'id' => 'reputation', 'name' => '$LANG.tab_reputation' ],
|
||||||
|
'screenshot' => ['template' => 'screenshot', 'id' => 'screenshots', 'name' => '$LANG.tab_screenshots' ],
|
||||||
|
'skill' => ['template' => 'skill', 'id' => 'skills', 'name' => '$LANG.tab_skills' ],
|
||||||
|
'sound' => ['template' => 'sound', 'id' => 'sounds', 'name' => '$LANG.types[19][2]' ],
|
||||||
|
'spell' => ['template' => 'spell', 'id' => 'spells', 'name' => '$LANG.tab_spells' ],
|
||||||
|
'title' => ['template' => 'title', 'id' => 'titles', 'name' => '$LANG.tab_titles' ],
|
||||||
|
'topusers' => ['template' => 'topusers', 'id' => 'topusers', 'name' => '$LANG.topusers' ],
|
||||||
|
'video' => ['template' => 'video', 'id' => 'videos', 'name' => '$LANG.tab_videos' ],
|
||||||
|
'zone' => ['template' => 'zone', 'id' => 'zones', 'name' => '$LANG.tab_zones' ],
|
||||||
|
'guide' => ['template' => 'guide', 'id' => 'guides', ]
|
||||||
|
);
|
||||||
|
|
||||||
|
private string $id = '';
|
||||||
|
private ?string $name = null;
|
||||||
|
private ?array $data = null; // js:array of object <RowDefinitions>
|
||||||
|
private ?string $tabs = null; // js:Object; instance of "Tabs"
|
||||||
|
private ?string $parent = 'lv-generic'; // HTMLNode.id; can be null but is pretty much always 'lv-generic'
|
||||||
|
private ?string $template = null;
|
||||||
|
private ?int $mode = null; // js:int; defaults to MODE_DEFAULT
|
||||||
|
private ?string $note = null; // text in top band
|
||||||
|
|
||||||
|
private ?int $poundable = null; // 0 (no); 1 (always); 2 (yes, w/o sorting); defaults to 1
|
||||||
|
private ?int $searchable = null; // js:bool; defaults to FALSE
|
||||||
|
private ?int $filtrable = null; // js:bool; defaults to FALSE
|
||||||
|
private ?int $sortable = null; // js:bool; defaults to FALSE
|
||||||
|
private ?int $searchDelay = null; // in ms; defalts to 333
|
||||||
|
private ?int $clickable = null; // js:bool; defaults to TRUE
|
||||||
|
private ?int $hideBands = null; // js:int; 1:top, 2:bottom, 3:both;
|
||||||
|
private ?int $hideNav = null; // js:int; 1:top, 2:bottom, 3:both;
|
||||||
|
private ?int $hideHeader = null; // js:bool
|
||||||
|
private ?int $hideCount = null; // js:bool
|
||||||
|
private ?int $debug = null; // js:bool
|
||||||
|
private ?int $_truncated = null; // js:bool; adds predefined note to top band, because there was too much data to display
|
||||||
|
private ?int $_errors = null; // js:bool; adds predefined note to top band, because there was an error
|
||||||
|
private ?int $_petTalents = null; // js:bool; applies modifier for talent levels
|
||||||
|
|
||||||
|
private ?int $nItemsPerPage = null; // js:int; defaults to 50
|
||||||
|
private ?int $_totalCount = null; // js:int; used by loot and comments
|
||||||
|
private ?array $clip = null; // js:array of int {w:<width>, h:<height>}
|
||||||
|
private ?string $customPound = null;
|
||||||
|
private ?string $genericlinktype = null; // sometimes set when expecting to display model
|
||||||
|
private ?array $_upgradeIds = null; // js:array of int (itemIds)
|
||||||
|
|
||||||
|
private null|array|string $extraCols = null; // js:callable or js:array of object <ColumnDefinition>
|
||||||
|
private null|array|string $visibleCols = null; // js:callable or js:array of string <colIds>
|
||||||
|
private null|array|string $hiddenCols = null; // js:callable or js:array of string <colIds>
|
||||||
|
private null|array|string $sort = null; // js:callable or js:array of colIndizes
|
||||||
|
|
||||||
|
private ?string $onBeforeCreate = null; // js:callable
|
||||||
|
private ?string $onAfterCreate = null; // js:callable
|
||||||
|
private ?string $onNoData = null; // js:callable
|
||||||
|
private ?string $computeDataFunc = null; // js:callable
|
||||||
|
private ?string $onSearchSubmit = null; // js:callable
|
||||||
|
private ?string $createNote = null; // js:callable
|
||||||
|
private ?string $createCbControls = null; // js:callable
|
||||||
|
private ?string $customFilter = null; // js:callable
|
||||||
|
private ?string $getItemLink = null; // js:callable
|
||||||
|
private ?array $sortOptions = null; // js:array of object {id:<colId>, name:<name>, hidden:<bool>, type:"text", sortFunc:<callable>}
|
||||||
|
|
||||||
|
private string $__addIn = '';
|
||||||
|
|
||||||
|
public function __construct(array $opts, string $template = '', string $addIn = '')
|
||||||
|
{
|
||||||
|
if ($template && isset(self::TEMPLATES[$template]))
|
||||||
|
foreach (self::TEMPLATES[$template] as $k => $v)
|
||||||
|
$this->$k = $v;
|
||||||
|
|
||||||
|
foreach ($opts as $k => $v)
|
||||||
|
{
|
||||||
|
if (property_exists($this, $k))
|
||||||
|
{
|
||||||
|
// reindex arrays to force json_encode to treat them as arrays
|
||||||
|
if (is_array($v)) // in_array($k, ['data', 'extraCols', 'visibleCols', 'hiddenCols', 'sort', 'sortOptions']))
|
||||||
|
$v = array_values($v);
|
||||||
|
$this->$k = $v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
trigger_error(self::class.'::__construct - unrecognized option: ' . $k);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($addIn && !Template\PageTemplate::test('listviews/', $addIn.'.tpl'))
|
||||||
|
trigger_error('Nonexistent Listview addin requested: template/listviews/'.$addIn.'.tpl', E_USER_ERROR);
|
||||||
|
else if ($addIn)
|
||||||
|
$this->__addIn = 'template/listviews/'.$addIn.'.tpl';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function &iterate() : \Generator
|
||||||
|
{
|
||||||
|
reset($this->data);
|
||||||
|
|
||||||
|
foreach ($this->data as $idx => &$row)
|
||||||
|
yield $idx => $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplate() : string
|
||||||
|
{
|
||||||
|
return $this->template;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTabs(string $tabVar) : void
|
||||||
|
{
|
||||||
|
if ($tabVar[0] !== '$') // expects a jsVar, which we denote with a prefixed $
|
||||||
|
$tabVar = '$' . $tabVar;
|
||||||
|
|
||||||
|
$this->tabs = $tabVar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setError() : void
|
||||||
|
{
|
||||||
|
$this->_errors = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() : array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($this as $prop => $val)
|
||||||
|
if ($val !== null && substr($prop, 0, 2) != '__')
|
||||||
|
$result[$prop] = $val;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
if ($this->__addIn)
|
||||||
|
include($this->__addIn);
|
||||||
|
|
||||||
|
return "new Listview(".Util::toJSON($this).");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
291
includes/components/frontend/markup.class.php
Normal file
291
includes/components/frontend/markup.class.php
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class Markup implements \JsonSerializable
|
||||||
|
{
|
||||||
|
private const DB_TAG_PATTERN = '/(?<!\\\\)\[(npc|object|item|itemset|quest|spell|zone|faction|pet|achievement|statistic|title|event|class|race|skill|currency|emote|enchantment|money|sound|icondb)=(-?\d+)[^\]]*\]/i';
|
||||||
|
|
||||||
|
// const val
|
||||||
|
public const MARKUP_MODE_COMMENT = 1;
|
||||||
|
public const MARKUP_MODE_ARTICLE = 2;
|
||||||
|
public const MARKUP_MODE_QUICKFACTS = 3;
|
||||||
|
public const MARKUP_MODE_SIGNATURE = 4;
|
||||||
|
public const MARKUP_MODE_REPLY = 5;
|
||||||
|
|
||||||
|
// js var
|
||||||
|
public const MODE_COMMENT = '$Markup.MODE_COMMENT';
|
||||||
|
public const MODE_ARTICLE = '$Markup.MODE_ARTICLE';
|
||||||
|
public const MODE_QUICKFACTS = '$Markup.MODE_QUICKFACTS';
|
||||||
|
public const MODE_SIGNATURE = '$Markup.MODE_SIGNATURE';
|
||||||
|
public const MODE_REPLY = '$Markup.MODE_REPLY';
|
||||||
|
|
||||||
|
// const val
|
||||||
|
public const MARKUP_CLASS_ADMIN = 40;
|
||||||
|
public const MARKUP_CLASS_STAFF = 30;
|
||||||
|
public const MARKUP_CLASS_PREMIUM = 20;
|
||||||
|
public const MARKUP_CLASS_USER = 10;
|
||||||
|
public const MARKUP_CLASS_PENDING = 1;
|
||||||
|
|
||||||
|
// js var
|
||||||
|
public const CLASS_ADMIN = '$Markup.CLASS_ADMIN';
|
||||||
|
public const CLASS_STAFF = '$Markup.CLASS_STAFF';
|
||||||
|
public const CLASS_PREMIUM = '$Markup.CLASS_PREMIUM';
|
||||||
|
public const CLASS_USER = '$Markup.CLASS_USER';
|
||||||
|
public const CLASS_PENDING = '$Markup.CLASS_PENDING';
|
||||||
|
|
||||||
|
// options
|
||||||
|
private ?string $prepend = null; // html in front of article
|
||||||
|
private ?string $append = null; // html trailing the article
|
||||||
|
private ?int $locale = null; // forces tooltips in the article to adhere to another locale
|
||||||
|
private ?int $inBlog = null; // js:bool; unused by aowow
|
||||||
|
private ?string $mode = null; // defaults to Markup.MODE_ARTICLE, which is what we want.
|
||||||
|
private ?string $allow = null; // defaults to Markup.CLASS_STAFF
|
||||||
|
private ?int $roles = null; // if allow is null, get allow from roles (user group); also mode will be set to MODE_ARTICLE for staff groups
|
||||||
|
private ?int $stopAtBreak = null; // js:bool; only parses text until substring "[break]" is encountered; some debug option...?
|
||||||
|
private ?string $highlight = null; // HTMLNode selector
|
||||||
|
|
||||||
|
private ?int $skipReset = null; // js:bool; unsure, if TRUE the next settings in this block get skipped
|
||||||
|
private ?string $uid = null; // defaults to 'abc'; unsure, key under which media is stored and referenced in g_screenshots and g_videos
|
||||||
|
private ?string $root = null; // unsure, something to with Markup Tags that need to be subordinate to other tags (e.g.: [li] to [ol])
|
||||||
|
private ?int $preview = null; // unsure, appends '-preview' to the div created by the [tabs] tag and prevents scrolling. Forum feature?
|
||||||
|
private ?int $dbpage = null; // js:bool; set on db type detail pages; adds article edit links to admin menu
|
||||||
|
|
||||||
|
protected string $__text;
|
||||||
|
|
||||||
|
private string $__parent = 'article-generic';
|
||||||
|
|
||||||
|
public function __construct(string $text, array $opts, string $parent = '')
|
||||||
|
{
|
||||||
|
foreach ($opts as $k => $v)
|
||||||
|
{
|
||||||
|
if (property_exists($this, $k))
|
||||||
|
$this->$k = $v;
|
||||||
|
else
|
||||||
|
trigger_error(self::class.'::__construct - unrecognized option: ' . $k);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->__text = $text;
|
||||||
|
|
||||||
|
if ($parent)
|
||||||
|
$this->__parent = $parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJsGlobals() : array
|
||||||
|
{
|
||||||
|
return $this->_parseTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent() : string
|
||||||
|
{
|
||||||
|
return $this->__parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************/
|
||||||
|
/* Markup tag handling */
|
||||||
|
/***********************/
|
||||||
|
|
||||||
|
private function _parseTags(array &$jsg = []) : array
|
||||||
|
{
|
||||||
|
return self::parseTags($this->__text, $jsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parseTags(string $text, array &$jsg = []) : array
|
||||||
|
{
|
||||||
|
$jsGlobals = [];
|
||||||
|
|
||||||
|
if (preg_match_all(self::DB_TAG_PATTERN, $text, $matches, PREG_SET_ORDER))
|
||||||
|
{
|
||||||
|
foreach ($matches as $match)
|
||||||
|
{
|
||||||
|
if ($match[1] == 'statistic')
|
||||||
|
$match[1] = 'achievement';
|
||||||
|
else if ($match[1] == 'icondb')
|
||||||
|
$match[1] = 'icon';
|
||||||
|
|
||||||
|
if ($match[1] == 'money')
|
||||||
|
{
|
||||||
|
if (stripos($match[0], 'items'))
|
||||||
|
{
|
||||||
|
if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch))
|
||||||
|
{
|
||||||
|
$sm = explode(',', $submatch[1]);
|
||||||
|
for ($i = 0; $i < count($sm); $i+=2)
|
||||||
|
$jsGlobals[Type::ITEM][$sm[$i]] = $sm[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stripos($match[0], 'currency'))
|
||||||
|
{
|
||||||
|
if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch))
|
||||||
|
{
|
||||||
|
$sm = explode(',', $submatch[1]);
|
||||||
|
for ($i = 0; $i < count($sm); $i+=2)
|
||||||
|
$jsGlobals[Type::CURRENCY][$sm[$i]] = $sm[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1]))
|
||||||
|
$jsGlobals[$type][$match[2]] = $match[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Util::mergeJsGlobals($jsg, $jsGlobals);
|
||||||
|
|
||||||
|
return $jsGlobals;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _stripTags(array $jsgData = []) : string
|
||||||
|
{
|
||||||
|
return self::stripTags($this->__text, $jsgData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stripTags(string $text, array $jsgData = []) : string
|
||||||
|
{
|
||||||
|
// replace DB Tags
|
||||||
|
$text = preg_replace_callback(self::DB_TAG_PATTERN, function ($match) use ($jsgData) {
|
||||||
|
if ($match[1] == 'statistic')
|
||||||
|
$match[1] = 'achievement';
|
||||||
|
else if ($match[1] == 'icondb')
|
||||||
|
$match[1] = 'icon';
|
||||||
|
else if ($match[1] == 'money')
|
||||||
|
{
|
||||||
|
$moneys = [];
|
||||||
|
if (stripos($match[0], 'items'))
|
||||||
|
{
|
||||||
|
if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch))
|
||||||
|
{
|
||||||
|
$sm = explode(',', $submatch[1]);
|
||||||
|
for ($i = 0; $i < count($sm); $i += 2)
|
||||||
|
{
|
||||||
|
if (!empty($jsgData[Type::ITEM][1][$sm[$i]]))
|
||||||
|
$moneys[] = $jsgData[Type::ITEM][1][$sm[$i]]['name'];
|
||||||
|
else
|
||||||
|
$moneys[] = Util::ucFirst(Lang::game('item')).' #'.$sm[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stripos($match[0], 'currency'))
|
||||||
|
{
|
||||||
|
if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch))
|
||||||
|
{
|
||||||
|
$sm = explode(',', $submatch[1]);
|
||||||
|
for ($i = 0; $i < count($sm); $i += 2)
|
||||||
|
{
|
||||||
|
if (!empty($jsgData[Type::CURRENCY][1][$sm[$i]]))
|
||||||
|
$moneys[] = $jsgData[Type::CURRENCY][1][$sm[$i]]['name'];
|
||||||
|
else
|
||||||
|
$moneys[] = Util::ucFirst(Lang::game('curency')).' #'.$sm[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lang::concat($moneys);
|
||||||
|
}
|
||||||
|
if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1]))
|
||||||
|
{
|
||||||
|
if (!empty($jsgData[$type][1][$match[2]]))
|
||||||
|
return $jsgData[$type][1][$match[2]]['name'];
|
||||||
|
else
|
||||||
|
return Util::ucFirst(Lang::game($match[1])).' #'.$match[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger_error('Markup::stripTags() - encountered unhandled db-tag: '.var_export($match));
|
||||||
|
return '';
|
||||||
|
}, $text);
|
||||||
|
|
||||||
|
// replace line endings
|
||||||
|
$text = str_replace('[br]', "\n", $text);
|
||||||
|
|
||||||
|
// strip other Tags
|
||||||
|
$stripped = '';
|
||||||
|
$inTag = false;
|
||||||
|
for ($i = 0; $i < strlen($text); $i++)
|
||||||
|
{
|
||||||
|
if ($text[$i] == '[' && (!$i || $text[$i - 1] != '\\'))
|
||||||
|
$inTag = true;
|
||||||
|
if (!$inTag)
|
||||||
|
$stripped .= $text[$i];
|
||||||
|
if ($inTag && $text[$i] == ']' && (!$i || $text[$i - 1] != '\\'))
|
||||||
|
$inTag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stripped;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************/
|
||||||
|
/* String Operations */
|
||||||
|
/*********************/
|
||||||
|
|
||||||
|
public function append(string $text) : self
|
||||||
|
{
|
||||||
|
$this->__text .= $text;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepend(string $text) : self
|
||||||
|
{
|
||||||
|
$this->__text = $text . $this->__text;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apply(\Closure $fn) : void
|
||||||
|
{
|
||||||
|
$this->__text = $fn($this->__text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function replace(string $middle, int $offset = 0, ?int $len = null) : self
|
||||||
|
{
|
||||||
|
// y no mb_substr_replace >:(
|
||||||
|
$start = $end = '';
|
||||||
|
|
||||||
|
if ($offset < 0)
|
||||||
|
$offset = mb_strlen($this->__text) + $offset;
|
||||||
|
|
||||||
|
$start = mb_substr($this->__text, 0, $offset);
|
||||||
|
|
||||||
|
if (!is_null($len) && $len >= 0)
|
||||||
|
$end = mb_substr($this->__text, $offset + $len);
|
||||||
|
else if (!is_null($len) && $len < 0)
|
||||||
|
$end = mb_substr($this->__text, $offset + mb_strlen($this->__text) + $len);
|
||||||
|
|
||||||
|
$this->__text = $start . $middle . $end;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanText() : string
|
||||||
|
{
|
||||||
|
// break script-tags, unify newlines
|
||||||
|
$val = preg_replace(['/script\s*\>/i', "/\r\n/", "/\r/"], ['script>', "\n", "\n"], $this->__text);
|
||||||
|
|
||||||
|
return strtr(Util::jsEscape($val), ['script>' => 'scr"+"ipt>']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() : array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($this as $prop => $val)
|
||||||
|
if ($val !== null && $prop[0] != '_')
|
||||||
|
$result[$prop] = $val;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
if ($this->jsonSerialize())
|
||||||
|
return 'Markup.printHtml("'.$this->cleanText().'", "'.$this->__parent.'", '.Util::toJSON($this).");\n";
|
||||||
|
|
||||||
|
return 'Markup.printHtml("'.$this->cleanText().'", "'.$this->__parent."\");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
70
includes/components/frontend/summary.class.php
Normal file
70
includes/components/frontend/summary.class.php
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class Summary implements \JsonSerializable
|
||||||
|
{
|
||||||
|
private string $id = ''; // HTMLNode.id
|
||||||
|
private ?string $parent = ''; // HTMLNode.id; if set $id is created and attached here instead of searched for
|
||||||
|
private string $template = ''; //
|
||||||
|
private ?int $editable = null; // js:bool; defaults to TRUE
|
||||||
|
private ?int $draggable = null; // js:bool; defaults to $editable
|
||||||
|
private ?int $searchable = null; // js:bool; defaults to $editable && $draggable
|
||||||
|
private ?int $weightable = null; // js:bool; defaults to $editable
|
||||||
|
private ?int $textable = null; // js:bool; defaults to FALSE
|
||||||
|
private ?int $enhanceable = null; // js:bool; defaults to $editable
|
||||||
|
private ?int $level = null; // js:int; defaults to 80
|
||||||
|
private array $groups = []; // js:array; defaults to GET-params
|
||||||
|
private ?array $weights = null; // js:array; defaults to GET-params
|
||||||
|
|
||||||
|
public function __construct(array $opts)
|
||||||
|
{
|
||||||
|
foreach ($opts as $k => $v)
|
||||||
|
{
|
||||||
|
if (property_exists($this, $k))
|
||||||
|
$this->$k = $v;
|
||||||
|
else
|
||||||
|
trigger_error(self::class.'::__construct - unrecognized option: ' . $k);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->template)
|
||||||
|
trigger_error(self::class.'::__construct - initialized without template', E_USER_WARNING);
|
||||||
|
if (!$this->id)
|
||||||
|
trigger_error(self::class.'::__construct - initialized without HTMLNode#id to reference', E_USER_WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function &iterate() : \Generator
|
||||||
|
{
|
||||||
|
reset($this->groups);
|
||||||
|
|
||||||
|
foreach ($this->groups as $idx => &$group)
|
||||||
|
yield $idx => $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addGroup(array $group) : void
|
||||||
|
{
|
||||||
|
$this->groups[] = $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() : array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($this as $prop => $val)
|
||||||
|
if ($val !== null && $prop[0] != '_')
|
||||||
|
$result[$prop] = $val;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
return "new Summary(".Util::toJSON($this).");\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
142
includes/components/frontend/tabs.class.php
Normal file
142
includes/components/frontend/tabs.class.php
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class Tabs implements \JsonSerializable, \Countable
|
||||||
|
{
|
||||||
|
private array $__tabs = [];
|
||||||
|
|
||||||
|
private string $parent = ''; // HTMLNode
|
||||||
|
private ?int $poundable = null; // js:bool
|
||||||
|
private ?int $forceScroll = null; // js:bool
|
||||||
|
private ?int $noScroll = null; // js:bool
|
||||||
|
private ?string $trackable = null; // String to track in Google Analytics .. often a DB Type
|
||||||
|
|
||||||
|
private ?string $onLoad = null; // js::callable
|
||||||
|
private ?string $onShow = null; // js::callable
|
||||||
|
private ?string $onHide = null; // js::callable
|
||||||
|
|
||||||
|
public function __construct(array $opts, public readonly string $__tabVar = 'myTabs', private bool $__forceTabs = false)
|
||||||
|
{
|
||||||
|
foreach ($opts as $k => $v)
|
||||||
|
{
|
||||||
|
if (property_exists($this, $k))
|
||||||
|
$this->$k = $v;
|
||||||
|
else
|
||||||
|
trigger_error(self::class.'::__construct - unrecognized option: ' . $k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function &iterate() : \Generator
|
||||||
|
{
|
||||||
|
reset($this->__tabs);
|
||||||
|
|
||||||
|
foreach ($this->__tabs as $idx => &$tab)
|
||||||
|
yield $idx => $tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addListviewTab(Listview $lv) : void
|
||||||
|
{
|
||||||
|
$this->__tabs[] = $lv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addDataTab(string $id, string $name, string $data) : void
|
||||||
|
{
|
||||||
|
$this->__tabs[] = ['id' => $id, 'name' => $name, 'data' => $data];
|
||||||
|
$this->__forceTabs = true; // otherwise a single DataTab could not be accessed
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataContainer() : \Generator
|
||||||
|
{
|
||||||
|
foreach ($this->__tabs as $tab)
|
||||||
|
if (is_array($tab))
|
||||||
|
yield '<div class="text tabbed-contents" id="tab-'.$tab['id'].'" style="display:none;">'.$tab['data'].'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFlush() : string
|
||||||
|
{
|
||||||
|
if ($this->isTabbed())
|
||||||
|
return $this->__tabVar.".flush();";
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isTabbed() : bool
|
||||||
|
{
|
||||||
|
return count($this->__tabs) > 1 || $this->__forceTabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************/
|
||||||
|
/* enable deep cloning */
|
||||||
|
/***********************/
|
||||||
|
|
||||||
|
public function __clone()
|
||||||
|
{
|
||||||
|
foreach ($this->__tabs as $idx => $tab)
|
||||||
|
{
|
||||||
|
if (is_array($tab))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$this->__tabs[$idx] = clone $tab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************/
|
||||||
|
/* make countable */
|
||||||
|
/******************/
|
||||||
|
|
||||||
|
public function count() : int
|
||||||
|
{
|
||||||
|
return count($this->__tabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************/
|
||||||
|
/* make Tabs stringable */
|
||||||
|
/************************/
|
||||||
|
|
||||||
|
public function jsonSerialize() : array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($this as $prop => $val)
|
||||||
|
if ($val !== null && $prop[0] != '_')
|
||||||
|
$result[$prop] = $val;
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
$result = '';
|
||||||
|
|
||||||
|
if ($this->isTabbed())
|
||||||
|
$result .= "var ".$this->__tabVar." = new Tabs(".Util::toJSON($this).");\n";
|
||||||
|
|
||||||
|
foreach ($this->__tabs as $tab)
|
||||||
|
{
|
||||||
|
if (is_array($tab))
|
||||||
|
{
|
||||||
|
$n = $tab['name'][0] == '$' ? substr($tab['name'], 1) : "'".$tab['name']."'";
|
||||||
|
$result .= $this->__tabVar.".add(".$n.", { id: '".$tab['id']."' });\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($this->isTabbed())
|
||||||
|
$tab->setTabs($this->__tabVar);
|
||||||
|
|
||||||
|
$result .= $tab; // Listview::__toString here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
60
includes/components/frontend/tooltip.class.php
Normal file
60
includes/components/frontend/tooltip.class.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aowow;
|
||||||
|
|
||||||
|
if (!defined('AOWOW_REVISION'))
|
||||||
|
die('illegal access');
|
||||||
|
|
||||||
|
|
||||||
|
class Tooltip implements \JsonSerializable
|
||||||
|
{
|
||||||
|
private ?string $name = null;
|
||||||
|
private ?string $tooltip = null;
|
||||||
|
private ?\StdClass $map = null; // secondary tooltip
|
||||||
|
private ?string $icon = null;
|
||||||
|
private ?int $quality = null; // icon border color coded
|
||||||
|
private ?bool $daily = null;
|
||||||
|
private ?array $spells = null;
|
||||||
|
private ?string $buff = null;
|
||||||
|
private ?array $buffspells = null;
|
||||||
|
|
||||||
|
public function __construct(private string $__powerTpl, private string $__subject, array $opts = [])
|
||||||
|
{
|
||||||
|
foreach ($opts as $k => $v)
|
||||||
|
{
|
||||||
|
if (property_exists($this, $k))
|
||||||
|
$this->$k = $v;
|
||||||
|
else
|
||||||
|
trigger_error(self::class.'::__construct - unrecognized option: ' . $k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() : array
|
||||||
|
{
|
||||||
|
$out = [];
|
||||||
|
|
||||||
|
$locString = Lang::getLocale()->json();
|
||||||
|
|
||||||
|
foreach ($this as $k => $v)
|
||||||
|
{
|
||||||
|
if ($v === null || $k[0] == '_')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ($k == 'icon')
|
||||||
|
$out[$k] = rawurldecode($v);
|
||||||
|
else if ($k == 'quality' || $k == 'map' || $k == 'daily')
|
||||||
|
$out[$k] = $v;
|
||||||
|
else
|
||||||
|
$out[$k . '_' . $locString] = $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() : string
|
||||||
|
{
|
||||||
|
return sprintf($this->__powerTpl, Util::toJSON($this->__subject, JSON_AOWOW_POWER), Lang::getLocale()->value, Util::toJSON($this, JSON_AOWOW_POWER))."\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Aowow;
|
|
||||||
|
|
||||||
if (!defined('AOWOW_REVISION'))
|
|
||||||
die('illegal access');
|
|
||||||
|
|
||||||
/*
|
|
||||||
this is just a skeleton for now
|
|
||||||
at some point i'll need to (at least rudamentary) parse
|
|
||||||
back and forth between markup and html
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Markup
|
|
||||||
{
|
|
||||||
private $text = '';
|
|
||||||
private $jsGlobals = [];
|
|
||||||
|
|
||||||
private static $dbTagPattern = '/(?<!\\\\)\[(npc|object|item|itemset|quest|spell|zone|faction|pet|achievement|statistic|title|event|class|race|skill|currency|emote|enchantment|money|sound|icondb)=(-?\d+)[^\]]*\]/i';
|
|
||||||
|
|
||||||
public function __construct($text)
|
|
||||||
{
|
|
||||||
$this->text = $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function parseGlobalsFromText(&$jsg = [])
|
|
||||||
{
|
|
||||||
if (preg_match_all(self::$dbTagPattern, $this->text, $matches, PREG_SET_ORDER))
|
|
||||||
{
|
|
||||||
foreach ($matches as $match)
|
|
||||||
{
|
|
||||||
if ($match[1] == 'statistic')
|
|
||||||
$match[1] = 'achievement';
|
|
||||||
else if ($match[1] == 'icondb')
|
|
||||||
$match[1] = 'icon';
|
|
||||||
|
|
||||||
if ($match[1] == 'money')
|
|
||||||
{
|
|
||||||
if (stripos($match[0], 'items'))
|
|
||||||
{
|
|
||||||
if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch))
|
|
||||||
{
|
|
||||||
$sm = explode(',', $submatch[1]);
|
|
||||||
for ($i = 0; $i < count($sm); $i+=2)
|
|
||||||
$this->jsGlobals[Type::ITEM][$sm[$i]] = $sm[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stripos($match[0], 'currency'))
|
|
||||||
{
|
|
||||||
if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch))
|
|
||||||
{
|
|
||||||
$sm = explode(',', $submatch[1]);
|
|
||||||
for ($i = 0; $i < count($sm); $i+=2)
|
|
||||||
$this->jsGlobals[Type::CURRENCY][$sm[$i]] = $sm[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1]))
|
|
||||||
$this->jsGlobals[$type][$match[2]] = $match[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Util::mergeJsGlobals($jsg, $this->jsGlobals);
|
|
||||||
|
|
||||||
return $this->jsGlobals;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stripTags($globals = [])
|
|
||||||
{
|
|
||||||
// since this is an article the db-tags should already be parsed
|
|
||||||
$text = preg_replace_callback(self::$dbTagPattern, function ($match) use ($globals) {
|
|
||||||
if ($match[1] == 'statistic')
|
|
||||||
$match[1] = 'achievement';
|
|
||||||
else if ($match[1] == 'icondb')
|
|
||||||
$match[1] = 'icon';
|
|
||||||
else if ($match[1] == 'money')
|
|
||||||
{
|
|
||||||
$moneys = [];
|
|
||||||
if (stripos($match[0], 'items'))
|
|
||||||
{
|
|
||||||
if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch))
|
|
||||||
{
|
|
||||||
$sm = explode(',', $submatch[1]);
|
|
||||||
for ($i = 0; $i < count($sm); $i += 2)
|
|
||||||
{
|
|
||||||
if (!empty($globals[Type::ITEM][1][$sm[$i]]))
|
|
||||||
$moneys[] = $globals[Type::ITEM][1][$sm[$i]]['name'];
|
|
||||||
else
|
|
||||||
$moneys[] = Util::ucFirst(Lang::game('item')).' #'.$sm[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stripos($match[0], 'currency'))
|
|
||||||
{
|
|
||||||
if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch))
|
|
||||||
{
|
|
||||||
$sm = explode(',', $submatch[1]);
|
|
||||||
for ($i = 0; $i < count($sm); $i += 2)
|
|
||||||
{
|
|
||||||
if (!empty($globals[Type::CURRENCY][1][$sm[$i]]))
|
|
||||||
$moneys[] = $globals[Type::CURRENCY][1][$sm[$i]]['name'];
|
|
||||||
else
|
|
||||||
$moneys[] = Util::ucFirst(Lang::game('curency')).' #'.$sm[$i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Lang::concat($moneys);
|
|
||||||
}
|
|
||||||
if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1]))
|
|
||||||
{
|
|
||||||
if (!empty($globals[$type][1][$match[2]]))
|
|
||||||
return $globals[$type][1][$match[2]]['name'];
|
|
||||||
else
|
|
||||||
return Util::ucFirst(Lang::game($match[1])).' #'.$match[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger_error('Markup::stripTags() - encountered unhandled db-tag: '.var_export($match));
|
|
||||||
return '';
|
|
||||||
}, $this->text);
|
|
||||||
|
|
||||||
$text = str_replace('[br]', "\n", $text);
|
|
||||||
$stripped = '';
|
|
||||||
|
|
||||||
$inTag = false;
|
|
||||||
for ($i = 0; $i < strlen($text); $i++)
|
|
||||||
{
|
|
||||||
if ($text[$i] == '[')
|
|
||||||
$inTag = true;
|
|
||||||
if (!$inTag)
|
|
||||||
$stripped .= $text[$i];
|
|
||||||
if ($text[$i] == ']')
|
|
||||||
$inTag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $stripped;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fromHtml()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toHtml()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -65,6 +65,8 @@ spl_autoload_register(function ($class)
|
|||||||
|
|
||||||
if (file_exists('includes/components/'.strtolower($class).'.class.php'))
|
if (file_exists('includes/components/'.strtolower($class).'.class.php'))
|
||||||
require_once 'includes/components/'.strtolower($class).'.class.php';
|
require_once 'includes/components/'.strtolower($class).'.class.php';
|
||||||
|
else if (file_exists('includes/components/frontend/'.strtolower($class).'.class.php'))
|
||||||
|
require_once 'includes/components/frontend/'.strtolower($class).'.class.php';
|
||||||
});
|
});
|
||||||
|
|
||||||
// TC systems in components
|
// TC systems in components
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class GuideList extends BaseType
|
|||||||
$this->article[$a['rev']] = $a['article'];
|
$this->article[$a['rev']] = $a['article'];
|
||||||
if ($this->article[$a['rev']])
|
if ($this->article[$a['rev']])
|
||||||
{
|
{
|
||||||
(new Markup($this->article[$a['rev']]))->parseGlobalsFromText($this->jsGlobals);
|
Markup::parseTags($this->article[$a['rev']], $this->jsGlobals);
|
||||||
return $this->article[$a['rev']];
|
return $this->article[$a['rev']];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -559,9 +559,9 @@ class GenericPage
|
|||||||
if ($article)
|
if ($article)
|
||||||
{
|
{
|
||||||
if ($article['article'])
|
if ($article['article'])
|
||||||
(new Markup($article['article']))->parseGlobalsFromText($this->jsgBuffer);
|
Markup::parseTags($article['article'], $this->jsgBuffer);
|
||||||
if ($article['quickInfo'])
|
if ($article['quickInfo'])
|
||||||
(new Markup($article['quickInfo']))->parseGlobalsFromText($this->jsgBuffer);
|
Markup::parseTags($article['quickInfo'], $this->jsgBuffer);
|
||||||
|
|
||||||
$this->article = array(
|
$this->article = array(
|
||||||
'text' => Util::jsEscape(Util::defStatic($article['article'])),
|
'text' => Util::jsEscape(Util::defStatic($article['article'])),
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ class GuidePage extends GenericPage
|
|||||||
'specId' => $this->_post['specId'],
|
'specId' => $this->_post['specId'],
|
||||||
'title' => $this->_post['title'],
|
'title' => $this->_post['title'],
|
||||||
'name' => $this->_post['name'],
|
'name' => $this->_post['name'],
|
||||||
'description' => $this->_post['description'] ?: Lang::trimTextClean((new Markup($this->_post['body']))->stripTags(), 120),
|
'description' => $this->_post['description'] ?: Lang::trimTextClean(Markup::stripTags($this->_post['body']), 120),
|
||||||
'locale' => $this->_post['locale'],
|
'locale' => $this->_post['locale'],
|
||||||
'roles' => User::$groups,
|
'roles' => User::$groups,
|
||||||
'status' => GUIDE_STATUS_DRAFT
|
'status' => GUIDE_STATUS_DRAFT
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class HomePage extends GenericPage
|
|||||||
|
|
||||||
$this->featuredBox['text'] = Util::localizedString($this->featuredBox, 'text', true);
|
$this->featuredBox['text'] = Util::localizedString($this->featuredBox, 'text', true);
|
||||||
|
|
||||||
if ($_ = (new Markup($this->featuredBox['text']))->parseGlobalsFromText())
|
if ($_ = Markup::parseTags($this->featuredBox['text']))
|
||||||
$this->extendGlobalData($_);
|
$this->extendGlobalData($_);
|
||||||
|
|
||||||
if (empty($this->featuredBox['boxBG']))
|
if (empty($this->featuredBox['boxBG']))
|
||||||
|
|||||||
Reference in New Issue
Block a user