mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Template/Endpoints (Base)
* redo page render following the logic of:
Response ─┬─> TextResponse ─> TextResponseImpl
└─> TemplateResponse ─> TemplateResponseImpl
* split up giant files, one per response path
* caching becomes a trait, implemented where necessary
* TextResponses (Ajax) can now be cached
* make use of previously defined php classes for js objects
* Tabs, Listview, Tooltip, Announcement, Markup, Book, ...
* \Aowow\Template\PageTemplate is the new class to be cached
* do not discard error messages generated after vars have been sent to template
and store in session for display at a later time
* implement tracking consent management
* move logic out of template into their respective endpoints
This commit is contained in:
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AjaxHandler
|
||||
{
|
||||
use TrRequestData;
|
||||
|
||||
protected $validParams = [];
|
||||
protected $params = [];
|
||||
protected $handler;
|
||||
|
||||
protected $contentType = MIME_TYPE_JSON;
|
||||
|
||||
public $doRedirect = false;
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
|
||||
$this->initRequestData();
|
||||
}
|
||||
|
||||
public function handle(string &$out) : bool
|
||||
{
|
||||
if (!$this->handler)
|
||||
return false;
|
||||
|
||||
if ($this->validParams)
|
||||
{
|
||||
if (count($this->params) != 1)
|
||||
return false;
|
||||
|
||||
if (!in_array($this->params[0], $this->validParams))
|
||||
return false;
|
||||
}
|
||||
|
||||
$out = $this->{$this->handler}() ?? '';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getContentType() : string
|
||||
{
|
||||
return $this->contentType;
|
||||
}
|
||||
|
||||
protected function reqPOST(string ...$keys) : bool
|
||||
{
|
||||
foreach ($keys as $k)
|
||||
if (!isset($this->_post[$k]) || $this->_post[$k] === null || $this->_post[$k] === '')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function reqGET(string ...$keys) : bool
|
||||
{
|
||||
foreach ($keys as $k)
|
||||
if (!isset($this->_get[$k]) || $this->_get[$k] === null || $this->_get[$k] === '')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -632,10 +632,7 @@ trait spawnHelper
|
||||
$wpSum = [];
|
||||
$wpIdx = 0;
|
||||
$worldPos = [];
|
||||
$spawns = DB::Aowow()->select("SELECT * FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) AND `posX` > 0 AND `posY` > 0", self::$type, $this->getFoundIDs());
|
||||
|
||||
if (!$spawns)
|
||||
return;
|
||||
$spawns = DB::Aowow()->select("SELECT * FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) AND `posX` > 0 AND `posY` > 0", self::$type, $this->getFoundIDs()) ?: [];
|
||||
|
||||
if (!$skipAdmin && User::isInGroup(U_GROUP_MODERATOR))
|
||||
if ($guids = array_column(array_filter($spawns, fn($x) => $x['guid'] > 0 || $x['type'] != Type::NPC), 'guid'))
|
||||
|
||||
@@ -43,7 +43,7 @@ class Announcement implements \JsonSerializable
|
||||
public function jsonSerialize() : array
|
||||
{
|
||||
$json = array(
|
||||
'parent' => 'announcement-' . abs($this->id),
|
||||
'parent' => 'announcement-' . $this->id,
|
||||
'id' => $this->editable ? -$this->id : $this->id,
|
||||
'mode' => $this->mode,
|
||||
'status' => $this->status,
|
||||
|
||||
559
includes/components/pagetemplate.class.php
Normal file
559
includes/components/pagetemplate.class.php
Normal file
@@ -0,0 +1,559 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow\Template;
|
||||
|
||||
use \Aowow\Util, \Aowow\Cfg, \Aowow\Lang, \Aowow\User;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class PageTemplate
|
||||
{
|
||||
|
||||
private const GUIDE_RATING_TPL = "$(document).ready(function() { $('#guiderating').append(GetStars(%.10F, %s, %u, %u)); });\n";
|
||||
|
||||
private readonly \Aowow\Locale $locale;
|
||||
|
||||
private array $displayHooks = [];
|
||||
|
||||
private array $dataLoader = [];
|
||||
private array $scripts = [];
|
||||
private array $js = [];
|
||||
private array $css = [];
|
||||
|
||||
// generic data, that's just accessed from the template
|
||||
private array $rawData = []; // copied from $context
|
||||
private array $pageData = []; // processed by display hooks
|
||||
|
||||
// template data that needs further processing .. ! WARNING ! they will not get aut fetched from $context as they are already defined here
|
||||
protected array $guideRating = [];
|
||||
private string $gStaticUrl;
|
||||
private string $gHost;
|
||||
private string $gServerTime;
|
||||
private ?string $analyticsTag = null;
|
||||
private bool $consentFooter = false;
|
||||
private string $dbProfiles = '';
|
||||
|
||||
private readonly string $user; // becomes User object
|
||||
|
||||
/*******************/
|
||||
/* basic execution */
|
||||
/* */
|
||||
/* 1) Init */
|
||||
/*******************/
|
||||
|
||||
public function __construct(private string $template, private ?\Aowow\TemplateResponse $context = null)
|
||||
{
|
||||
$this->locale = Lang::getLocale();
|
||||
$this->gStaticUrl = Cfg::get('STATIC_URL');
|
||||
$this->gHost = Cfg::get('HOST_URL');
|
||||
$this->analyticsTag = Cfg::get('GTAG_MEASUREMENT_ID');
|
||||
$this->gServerTime = sprintf("new Date('%s')", date(Util::$dateFormatInternal));
|
||||
$this->user = User::class;
|
||||
}
|
||||
|
||||
public function addDataLoader(string ...$dataFile) : void
|
||||
{
|
||||
foreach ($dataFile as $df)
|
||||
$this->dataLoader[] = $df;
|
||||
}
|
||||
|
||||
public function addScript(int $type, string $str, int $flags = 0x0) : bool
|
||||
{
|
||||
$tpl = match ($type)
|
||||
{
|
||||
SC_CSS_FILE => '<link rel="stylesheet" type="text/css" href="%1$s%2$s" />',
|
||||
SC_CSS_STRING => '<style type="text/css">%1$s</style>',
|
||||
SC_JS_FILE => '<script type="text/javascript" src="%1$s%2$s"></script>',
|
||||
SC_JS_STRING => '<script type="text/javascript">%1$s</script>',
|
||||
default => ''
|
||||
};
|
||||
|
||||
if (!$tpl || !$str)
|
||||
|
||||
if (!$str)
|
||||
{
|
||||
trigger_error('PageTemplate::addScript - content empty', E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$tpl)
|
||||
{
|
||||
trigger_error('PageTemplate::addScript - unknown script type #'.$type, E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
// insert locale string
|
||||
if ($flags & SC_FLAG_LOCALIZED)
|
||||
$str = sprintf($str, Lang::getLocale()->json());
|
||||
|
||||
$this->scripts[] = [$type, $str, $flags, $tpl];
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (optional) set pre-render hooks */
|
||||
|
||||
public function registerDisplayHook(string $var, callable $fn) : void
|
||||
{
|
||||
$this->displayHooks[$var][] = $fn;
|
||||
}
|
||||
|
||||
private function getDisplayHooks(string $var) : array
|
||||
{
|
||||
return $this->displayHooks[$var] ?? [];
|
||||
}
|
||||
|
||||
/* 3) self test, ready to be cached now */
|
||||
|
||||
public function prepare() : bool
|
||||
{
|
||||
if (!self::test('template/pages/', $this->template))
|
||||
{
|
||||
trigger_error('Error: nonexistent template requested: template/pages/'.$this->template.'.tpl.php', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO - more checks and preparations
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 4) display */
|
||||
|
||||
public function render() : void
|
||||
{
|
||||
$this->update();
|
||||
|
||||
include('template/pages/'.$this->template.'.tpl.php');
|
||||
}
|
||||
|
||||
|
||||
/***********/
|
||||
/* loaders */
|
||||
/***********/
|
||||
|
||||
// "template_exists"
|
||||
public static function test(string $path, string $file) : bool
|
||||
{
|
||||
if (!preg_match('/^[\w\-_]+(\.tpl(\.php)?)?$/i', $file))
|
||||
return false;
|
||||
|
||||
if ($path && preg_match('/\\{2,}|\/{2,}|\.{2,}|~/i', $path))
|
||||
return false;
|
||||
|
||||
if (!is_file('template/'.$path.$file))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// load brick
|
||||
private function brick(string $file, array $localVars = []) : void
|
||||
{
|
||||
$file .= '.tpl.php';
|
||||
|
||||
if (!self::test('bricks/', $file))
|
||||
{
|
||||
trigger_error('Nonexistent template requested: template/bricks/'.$file, E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($localVars as $n => $v)
|
||||
$$n = $v;
|
||||
|
||||
include('template/bricks/'.$file);
|
||||
}
|
||||
|
||||
private function brickIf(mixed $boolish, string $file, array $localVars = []) : void
|
||||
{
|
||||
if ($boolish)
|
||||
$this->brick($file, $localVars);
|
||||
}
|
||||
|
||||
// load brick with more text then vars
|
||||
private function localizedBrick(string $file, array $localVars = []) : void
|
||||
{
|
||||
foreach ($localVars as $n => $v)
|
||||
$$n = $v;
|
||||
|
||||
$_file = $file.'_'.$this->locale->value.'.tpl.php';
|
||||
if (self::test('localized/', $_file))
|
||||
{
|
||||
include('template/localized/'.$_file);
|
||||
return;
|
||||
}
|
||||
|
||||
$_file = $file.'_'.$this->locale->getFallback()->value.'.tpl.php';
|
||||
if (self::test('localized/', $_file))
|
||||
{
|
||||
include('template/localized/'.$_file);
|
||||
return;
|
||||
}
|
||||
|
||||
trigger_error('Nonexistent template requested: template/localized/'.$_file, E_USER_ERROR);
|
||||
}
|
||||
|
||||
private function localizedBrickIf(mixed $boolish, string $file, array $localVars = []) : void
|
||||
{
|
||||
if ($boolish)
|
||||
$this->localizedBrick($file, $localVars);
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* Util wrapper */
|
||||
/****************/
|
||||
|
||||
private function cfg(string $name) : mixed
|
||||
{
|
||||
return Cfg::get($name);
|
||||
}
|
||||
|
||||
private function json(mixed $var, int $jsonFlags = 0x0) : string
|
||||
{
|
||||
if (is_string($var) && $this->$var)
|
||||
$var = $this->$var;
|
||||
|
||||
return preg_replace('/script\s*\>/i', 'scr"+"ipt>', Util::toJSON($var, $jsonFlags));
|
||||
}
|
||||
|
||||
private function escHTML(string $var) : string|array
|
||||
{
|
||||
return Util::htmlEscape($this->$var ?? $var);
|
||||
}
|
||||
|
||||
private function escJS(string $var) : string|array
|
||||
{
|
||||
return Util::jsEscape($this->$var ?? $var);
|
||||
}
|
||||
|
||||
private function ucFirst(string $var) : string
|
||||
{
|
||||
return Util::ucFirst($this->$var ?? $var);
|
||||
}
|
||||
|
||||
|
||||
/*****************/
|
||||
/* render helper */
|
||||
/*****************/
|
||||
|
||||
private function concat(string $arrVar, string $separator = '') : string
|
||||
{
|
||||
if (!is_array($this->$arrVar))
|
||||
return '';
|
||||
|
||||
return implode($separator, $this->$arrVar);
|
||||
}
|
||||
|
||||
private function renderArray(string|array $arrVar, int $lpad = 0) : string
|
||||
{
|
||||
$data = [];
|
||||
if (is_string($arrVar) && isset($this->$arrVar) && is_array($this->$arrVar))
|
||||
$data = $this->$arrVar;
|
||||
else if (is_array($arrVar))
|
||||
$data = $arrVar;
|
||||
|
||||
$buff = '';
|
||||
foreach ($data as $x)
|
||||
$buff .= str_repeat(' ', $lpad) . $x . "\n";
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// load jsGlobals
|
||||
private function renderGlobalVars(int $lpad = 0) : string
|
||||
{
|
||||
$buff = '';
|
||||
|
||||
if ($this->guideRating)
|
||||
$buff .= str_repeat(' ', $lpad).sprintf(self::GUIDE_RATING_TPL, ...$this->guideRating);
|
||||
|
||||
foreach ($this->jsGlobals as [$jsVar, $data, $extraData])
|
||||
{
|
||||
$buff .= str_repeat(' ', $lpad).'var _ = '.$jsVar.';';
|
||||
|
||||
foreach ($data as $key => $data)
|
||||
$buff .= ' _['.(is_numeric($key) ? $key : "'".$key."'")."]=".Util::toJSON($data).';';
|
||||
|
||||
$buff .= "\n";
|
||||
|
||||
if (isset($this->gPageInfo['type']) && isset($this->gPageInfo['typeId']) && isset($extraData[$this->gPageInfo['typeId']]))
|
||||
{
|
||||
$buff .= "\n";
|
||||
foreach ($extraData[$this->gPageInfo['typeId']] as $k => $v)
|
||||
if ($v)
|
||||
$buff .= str_repeat(' ', $lpad).'_['.$this->gPageInfo['typeId'].'].'.$k.' = '.Util::toJSON($v).";\n";
|
||||
$buff .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
private function renderSeriesItem(int $idx, array $list, int $lpad = 0) : string
|
||||
{
|
||||
$result = '<tr><th>'.($idx + 1).'</th><td><div>';
|
||||
|
||||
$end = array_key_last($list);
|
||||
foreach ($list as $k => $i) // itemItr
|
||||
{
|
||||
$wrap = match ($i['side'])
|
||||
{
|
||||
SIDE_ALLIANCE => '<span class="icon-alliance-padded">%s</span>',
|
||||
SIDE_HORDE => '<span class="icon-horde">%s</span>',
|
||||
default => '%s'
|
||||
};
|
||||
|
||||
if ($i['typeId'] == $this->typeId)
|
||||
$result .= sprintf($wrap, '<b>'.$i['name'].'</b>');
|
||||
else
|
||||
$result .= sprintf($wrap, '<a href="?'.$i['typeStr'].'='.$i['typeId'].'">'.$i['name'].'</a>');
|
||||
|
||||
if ($end != $k)
|
||||
$result .= '<br />';
|
||||
|
||||
}
|
||||
|
||||
return str_repeat(' ', $lpad) . $result . "</div></td></tr>\n";
|
||||
}
|
||||
|
||||
private function renderFilter(int $lpad = 0) : string
|
||||
{
|
||||
$result = [];
|
||||
|
||||
// it's worth noting, that this only works on non-cached page calls. Luckily Profiler pages are not cached.
|
||||
if ($this->context instanceof \Aowow\IProfilerList)
|
||||
{
|
||||
$result[] = "pr_setRegionRealm(\$WH.ge('fi').firstChild, '".$this->region."', '".$this->realm."');";
|
||||
|
||||
if ($this->filter->values['ra'])
|
||||
$result[] = "pr_onChangeRace();";
|
||||
}
|
||||
|
||||
if ($this->filter->fiInit) // str: filter template (and init html form)
|
||||
$result[] = "fi_init('".$this->filter->fiInit."');";
|
||||
else if ($this->filter->fiType) // str: filter template (set without init)
|
||||
$result[] = "var fi_type = '".$this->filter->fiType."'";
|
||||
|
||||
if ($this->filter->fiSetCriteria) // arr:criteria, arr:signs, arr:values
|
||||
$result[] = 'fi_setCriteria('.mb_substr(Util::toJSON(array_values($this->filter->fiSetCriteria)), 1, -1).");";
|
||||
|
||||
/*
|
||||
nt: don't try to match provided weights on predefined weight sets (preselects preset from opt list and ..?)
|
||||
ids: weights are encoded as ids, not by their js name and need conversion before use
|
||||
stealth: the ub-selector (items filter) will not visually change (so what..?)
|
||||
*/
|
||||
if ($this->filter->fiSetWeights) // arr:weights, bool:nt[0], bool:ids[1], bool:stealth[1]
|
||||
$result[] = 'fi_setWeights('.Util::toJSON(array_values($this->filter->fiSetWeights)).', 0, 1, 1);';
|
||||
|
||||
if ($this->filter->fiExtraCols) // arr:extraCols
|
||||
$result[] = 'fi_extraCols = '.Util::toJSON(array_values(array_unique($this->filter->fiExtraCols))).";";
|
||||
|
||||
return str_repeat(' ', $lpad)."<script type=\"text/javascript\">//<![CDATA[\n".
|
||||
$this->renderArray($result, $lpad + 4).
|
||||
str_repeat(' ', $lpad)."//]]></script>\n";
|
||||
}
|
||||
|
||||
private function makeOptionsList(array $data, mixed $selectedIdx = null, int $lpad = 0, ?callable $callback = null) : string
|
||||
{
|
||||
$callback ??= fn(&$v, &$k) => $v; // default callback: skip empty descriptors
|
||||
$options = '';
|
||||
|
||||
foreach ($data as $idx => $str)
|
||||
{
|
||||
$extraAttributes = [];
|
||||
if (!$callback($str, $idx, $extraAttributes))
|
||||
continue;
|
||||
|
||||
if ($idx === '' || !$str)
|
||||
continue;
|
||||
|
||||
$options .= str_repeat(' ', max(0, $lpad)).'<option';
|
||||
|
||||
foreach ($extraAttributes as $k => $v)
|
||||
$options .= ' '.$k.'="'.$v.'"';
|
||||
|
||||
if (is_array($selectedIdx) && in_array($idx, $selectedIdx))
|
||||
$options .= ' selected="selected"';
|
||||
else if (!is_null($selectedIdx) && $selectedIdx == $idx)
|
||||
$options .= ' selected="selected"';
|
||||
|
||||
$options .= ' value="'.$idx.'">'.$str.'</option>'.($lpad < 0 ? '' : "\n");
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
private function makeRadiosList(string $name, array $data, mixed $selectedIdx = null, int $lpad = 0, ?callable $callback = null) : string
|
||||
{
|
||||
$callback ??= fn(&$v, &$k) => $v; // default callback: skip empty descriptors
|
||||
$options = '';
|
||||
|
||||
foreach ($data as $idx => [$title, $id])
|
||||
{
|
||||
$extraAttributes = [];
|
||||
if (!$callback($title, $idx, $extraAttributes))
|
||||
continue;
|
||||
|
||||
if ($id === '' || !$title)
|
||||
continue;
|
||||
|
||||
$options .= str_repeat(' ', max(0, $lpad)).'<input type="radio" name="'.$name.'" value="'.$idx.'" id="'.$name.'-'.$id.'"';
|
||||
|
||||
if (!is_null($selectedIdx) && $selectedIdx == $idx)
|
||||
$options .= ' checked="checked"';
|
||||
|
||||
$options .= '/><label for="'.$name.'-'.$id.'"';
|
||||
|
||||
foreach ($extraAttributes as $k => $v)
|
||||
$options .= ' '.$k.'="'.$v.'"';
|
||||
|
||||
$options .= '>'.$title.'</label>'.($lpad < 0 ? '' : "\n");
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
// unordered stuff
|
||||
|
||||
private function prepareScripts() : void
|
||||
{
|
||||
$this->js = $this->css = [];
|
||||
|
||||
foreach ($this->scripts as [$type, $str, $flags, $tpl])
|
||||
{
|
||||
$app = [];
|
||||
|
||||
if (($flags & SC_FLAG_APPEND_LOCALE) && $this->locale != \Aowow\Locale::EN)
|
||||
$app[] = 'lang='.$this->locale->domain();
|
||||
|
||||
// append anti-cache timestamp
|
||||
if (!($flags & SC_FLAG_NO_TIMESTAMP))
|
||||
if ($type == SC_JS_FILE || $type == SC_CSS_FILE)
|
||||
$app[] = filemtime('static/'.$str) ?: 0;
|
||||
|
||||
if ($app)
|
||||
$appendix = '?'.implode('&', $app);
|
||||
|
||||
if ($type == SC_JS_FILE || $type == SC_CSS_FILE)
|
||||
$str = Cfg::get('STATIC_URL').'/'.$str;
|
||||
|
||||
if ($flags & SC_FLAG_PREFIX)
|
||||
{
|
||||
if ($type == SC_JS_FILE || $type == SC_JS_STRING)
|
||||
array_unshift($this->js, sprintf($tpl, $str, $appendix ?? ''));
|
||||
else
|
||||
array_unshift($this->css, sprintf($tpl, $str, $appendix ?? ''));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($type == SC_JS_FILE || $type == SC_JS_STRING)
|
||||
array_push($this->js, sprintf($tpl, $str, $appendix ?? ''));
|
||||
else
|
||||
array_push($this->css, sprintf($tpl, $str, $appendix ?? ''));
|
||||
}
|
||||
}
|
||||
|
||||
if ($data = array_unique($this->dataLoader))
|
||||
{
|
||||
$args = array(
|
||||
'data' => implode('.', $data),
|
||||
'locale' => $this->locale->value,
|
||||
't' => $_SESSION['dataKey']
|
||||
);
|
||||
|
||||
array_push($this->js, '<script type="text/javascript" src="'.Cfg::get('HOST_URL').'/?'.http_build_query($args).'"></script>');
|
||||
}
|
||||
}
|
||||
|
||||
// refresh vars that shouldn't be cached
|
||||
private function update() : void
|
||||
{
|
||||
// analytics + consent
|
||||
if (!isset($_COOKIE['consent']))
|
||||
{
|
||||
$this->addScript(SC_CSS_FILE, 'css/consent.css');
|
||||
$this->addScript(SC_JS_FILE, 'js/consent.js');
|
||||
|
||||
$this->consentFooter = true;
|
||||
$this->analyticsTag = null;
|
||||
}
|
||||
else if ($this->analyticsTag && !$_COOKIE['consent'])
|
||||
$this->analyticsTag = null;
|
||||
|
||||
// js + css
|
||||
$this->prepareScripts();
|
||||
|
||||
// db profiling
|
||||
if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
$this->dbProfiles = \Aowow\DB::getProfiles();
|
||||
}
|
||||
|
||||
public function setListviewError() : void
|
||||
{
|
||||
if (!$this->lvTabs)
|
||||
return;
|
||||
|
||||
foreach ($this->lvTabs->iterate() as $lv)
|
||||
if ($lv instanceof \Aowow\Listview)
|
||||
$lv->setError();
|
||||
}
|
||||
|
||||
// pre-serialization: if a var is relevant it was stored in $rawData
|
||||
public function __sleep() : array
|
||||
{
|
||||
$this->context = null; // unlink from TemplateResponse
|
||||
$this->pageData = []; // clear modified data
|
||||
|
||||
$vars = [];
|
||||
foreach ($this as $k => $_)
|
||||
$vars[] = $k;
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
public function __wakeup() : void
|
||||
{
|
||||
$this->gStaticUrl = Cfg::get('STATIC_URL');
|
||||
$this->gHost = Cfg::get('HOST_URL');
|
||||
$this->analyticsTag = Cfg::get('GTAG_MEASUREMENT_ID');
|
||||
$this->gServerTime = sprintf("new Date('%s')", date(Util::$dateFormatInternal));
|
||||
}
|
||||
|
||||
public function __set(string $var, mixed $value) : void
|
||||
{
|
||||
$this->pageData[$var] = $value;
|
||||
}
|
||||
|
||||
public function __get(string $var) : mixed
|
||||
{
|
||||
// modified data exists
|
||||
if (isset($this->pageData[$var]))
|
||||
return $this->pageData[$var];
|
||||
|
||||
if (!isset($this->rawData[$var]))
|
||||
{
|
||||
if (!$this->context)
|
||||
return null;
|
||||
|
||||
if (!property_exists($this->context, $var))
|
||||
return null;
|
||||
|
||||
$this->rawData[$var] = $this->context->$var;
|
||||
}
|
||||
|
||||
if ($hooks = $this->getDisplayHooks($var))
|
||||
{
|
||||
if (is_object($this->rawData[$var])) // is frontend component
|
||||
$this->pageData[$var] = clone $this->rawData[$var];
|
||||
else
|
||||
$this->pageData[$var] = $this->rawData[$var];
|
||||
|
||||
foreach ($hooks as $fn)
|
||||
$fn($this, $this->pageData[$var]);
|
||||
}
|
||||
|
||||
return $this->pageData[$var] ?? $this->rawData[$var];
|
||||
}
|
||||
}
|
||||
657
includes/components/response/baseresponse.class.php
Normal file
657
includes/components/response/baseresponse.class.php
Normal file
@@ -0,0 +1,657 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
trait TrRecoveryHelper
|
||||
{
|
||||
const MODE_INFO = 0;
|
||||
const MODE_FORM_PASS = 1;
|
||||
const MODE_FORM_EMAIL = 2;
|
||||
|
||||
private function startRecovery(int $newStatus, string $mailTemplate, string $email) : string
|
||||
{
|
||||
if (!$newStatus <= ACC_STATUS_NEW && $newStatus > ACC_STATUS_CHANGE_PASS)
|
||||
return Lang::main('intError');
|
||||
|
||||
// check if already processing
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT `statusTimer` - UNIX_TIMESTAMP() FROM ?_account WHERE `email` = ? AND `status` > ?d AND `statusTimer` > UNIX_TIMESTAMP()', $email, ACC_STATUS_NEW))
|
||||
return sprintf(Lang::account('isRecovering'), Util::formatTime($_ * 1000));
|
||||
|
||||
// create new token and write to db
|
||||
$token = Util::createHash();
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET `token` = ?, `status` = ?d, `statusTimer` = UNIX_TIMESTAMP() + ?d WHERE `email` = ?', $token, $newStatus, Cfg::get('ACC_RECOVERY_DECAY'), $email))
|
||||
return Lang::main('intError');
|
||||
|
||||
// send recovery mail
|
||||
if (!Util::sendMail($email, $mailTemplate, [$token], Cfg::get('ACC_RECOVERY_DECAY')))
|
||||
return sprintf(Lang::main('intError2'), 'send mail');
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
trait TrGetNext
|
||||
{
|
||||
private function getNext(bool $forHeader = false) : string
|
||||
{
|
||||
$next = '';
|
||||
if (!empty($this->_get['next']))
|
||||
$next = $this->_get['next'];
|
||||
else if (isset($_SERVER['HTTP_REFERER']) && strstr($_SERVER['HTTP_REFERER'], '?'))
|
||||
$next = explode('?', $_SERVER['HTTP_REFERER'])[1];
|
||||
else if ($forHeader)
|
||||
return '.';
|
||||
|
||||
return ($forHeader ? '?' : '').$next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Interface ICache
|
||||
{
|
||||
public function saveCache(string|Template\PageTemplate $toCache) : void;
|
||||
public function loadCache(bool|string|Template\PageTemplate &$fromCache) : bool;
|
||||
public function setOnCacheLoaded(callable $callback, mixed $params = null) : void;
|
||||
public function getCacheKeyComponents() : array;
|
||||
public function applyOnCacheLoaded(mixed &$data) : mixed;
|
||||
}
|
||||
|
||||
trait TrCache
|
||||
{
|
||||
private const STORE_METHOD_OBJECT = 0;
|
||||
private const STORE_METHOD_STRING = 1;
|
||||
|
||||
private int $_cacheType = CACHE_TYPE_NONE;
|
||||
private int $skipCache = 0x0;
|
||||
private ?int $decay = null;
|
||||
private string $cacheDir = 'cache/template/';
|
||||
private bool $cacheInited = false;
|
||||
private ?\Memcached $memcached = null;
|
||||
private array $onCacheLoaded = [null, null]; // post-load updater
|
||||
|
||||
public static array $cacheStats = []; // load info for page footer
|
||||
|
||||
// visible properties or given strings are cached
|
||||
public function saveCache(string|object $toCache) : void
|
||||
{
|
||||
$this->initCache();
|
||||
|
||||
if ($this->_cacheType == CACHE_TYPE_NONE)
|
||||
return;
|
||||
|
||||
if (!Cfg::get('CACHE_MODE') /* || Cfg::get('DEBUG') */)
|
||||
return;
|
||||
|
||||
if (!$this->decay)
|
||||
return;
|
||||
|
||||
$cKey = $this->formatCacheKey();
|
||||
$method = is_object($toCache) ? self::STORE_METHOD_OBJECT : self::STORE_METHOD_STRING;
|
||||
|
||||
if ($method == self::STORE_METHOD_OBJECT)
|
||||
$toCache = serialize($toCache);
|
||||
else
|
||||
$toCache = (string)$toCache;
|
||||
|
||||
if (is_callable($this->onCacheLoaded[0]))
|
||||
$postCache = serialize($this->onCacheLoaded);
|
||||
|
||||
if (Cfg::get('CACHE_MODE') & CACHE_MODE_MEMCACHED)
|
||||
{
|
||||
// on &refresh also clear related
|
||||
if ($this->skipCache & CACHE_MODE_MEMCACHED)
|
||||
$this->deleteCache(CACHE_MODE_MEMCACHED);
|
||||
|
||||
$data = array(
|
||||
'timestamp' => time(),
|
||||
'lifetime' => $this->decay,
|
||||
'revision' => AOWOW_REVISION,
|
||||
'method' => $method,
|
||||
'postCache' => $postCache ?? null,
|
||||
'data' => $toCache
|
||||
);
|
||||
|
||||
$this->memcached()?->set($cKey[2], $data);
|
||||
}
|
||||
|
||||
if (Cfg::get('CACHE_MODE') & CACHE_MODE_FILECACHE)
|
||||
{
|
||||
$data = time()." ".$this->decay." ".AOWOW_REVISION." ".$method."\n";
|
||||
$data .= ($postCache ?? '')."\n";
|
||||
$data .= gzcompress($toCache, 9);
|
||||
|
||||
// on &refresh also clear related
|
||||
if ($this->skipCache & CACHE_MODE_FILECACHE)
|
||||
$this->deleteCache(CACHE_MODE_FILECACHE);
|
||||
|
||||
if (Util::writeDir($this->cacheDir . implode(DIRECTORY_SEPARATOR, array_slice($cKey, 0, 2))))
|
||||
file_put_contents($this->cacheDir . implode(DIRECTORY_SEPARATOR, $cKey), $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function loadCache(mixed &$fromCache) : bool
|
||||
{
|
||||
$this->initCache();
|
||||
|
||||
if ($this->_cacheType == CACHE_TYPE_NONE)
|
||||
return false;
|
||||
|
||||
if (!Cfg::get('CACHE_MODE') /* || Cfg::get('DEBUG') */)
|
||||
return false;
|
||||
|
||||
$cKey = $this->formatCacheKey();
|
||||
$rev = $method = $data = $postCache = null;
|
||||
|
||||
if ((Cfg::get('CACHE_MODE') & CACHE_MODE_MEMCACHED) && !($this->skipCache & CACHE_MODE_MEMCACHED))
|
||||
{
|
||||
if ($cache = $this->memcached()?->get($cKey[2]))
|
||||
{
|
||||
$method = $cache['method'];
|
||||
$data = $cache['data'];
|
||||
$postCache = $cache['postCache'];
|
||||
|
||||
if (($cache['timestamp'] + $cache['lifetime']) > time() && $cache['revision'] == AOWOW_REVISION)
|
||||
self::$cacheStats = [CACHE_MODE_MEMCACHED, $cache['timestamp'], $cache['lifetime']];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$data && (Cfg::get('CACHE_MODE') & CACHE_MODE_FILECACHE) && !($this->skipCache & CACHE_MODE_FILECACHE))
|
||||
{
|
||||
$file = $this->cacheDir . implode(DIRECTORY_SEPARATOR, $cKey);
|
||||
if (!file_exists($file))
|
||||
return false;
|
||||
|
||||
$content = file_get_contents($file);
|
||||
if (!$content)
|
||||
return false;
|
||||
|
||||
[$head, $postCache, $data] = explode("\n", $content, 3);
|
||||
if (substr_count($head, ' ') != 3)
|
||||
return false;
|
||||
|
||||
[$time, $lifetime, $rev, $method] = explode(' ', $head);
|
||||
|
||||
if (($time + $lifetime) < time() || $rev != AOWOW_REVISION)
|
||||
return false;
|
||||
|
||||
self::$cacheStats = [CACHE_MODE_FILECACHE, $time, $lifetime];
|
||||
$data = gzuncompress($data);
|
||||
}
|
||||
|
||||
if (!$data)
|
||||
return false;
|
||||
|
||||
if ($postCache)
|
||||
$this->onCacheLoaded = unserialize($postCache);
|
||||
|
||||
$fromCache = false;
|
||||
if ($method == self::STORE_METHOD_OBJECT)
|
||||
$fromCache = unserialize($data);
|
||||
else if ($method == self::STORE_METHOD_STRING)
|
||||
$fromCache = $data;
|
||||
|
||||
return $fromCache !== false;
|
||||
}
|
||||
|
||||
public function deleteCache(int $modeMask = 0x3) : void
|
||||
{
|
||||
$this->initCache();
|
||||
|
||||
// type+typeId+catg; 3+6+10
|
||||
$cKey = $this->formatCacheKey();
|
||||
$cKey[2] = substr($cKey[2], 0, 19);
|
||||
|
||||
if ($modeMask & CACHE_MODE_MEMCACHED)
|
||||
foreach ($this->memcached()?->getAllKeys() ?? [] as $k)
|
||||
if (strpos($k, $cKey[2]) === 0)
|
||||
$this->memcached()?->delete($k);
|
||||
|
||||
if ($modeMask & CACHE_MODE_FILECACHE)
|
||||
foreach (glob(implode(DIRECTORY_SEPARATOR, $cKey).'*') as $file)
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
private function memcached() : ?\Memcached
|
||||
{
|
||||
if (!$this->memcached && (Cfg::get('CACHE_MODE') & CACHE_MODE_MEMCACHED))
|
||||
{
|
||||
$this->memcached = new \Memcached();
|
||||
$this->memcached->addServer('localhost', 11211);
|
||||
}
|
||||
|
||||
return $this->memcached;
|
||||
}
|
||||
|
||||
private function initCache() : void
|
||||
{
|
||||
// php's missing trait property conflict resolution is going to be the end of me
|
||||
// also allow reevaluation even if inited. It may have changed in generate(), because of an error.
|
||||
if (isset($this->cacheType))
|
||||
$this->_cacheType = $this->cacheType;
|
||||
|
||||
if ($this->cacheInited)
|
||||
return;
|
||||
|
||||
// force refresh
|
||||
if (isset($_GET['refresh']) && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_DEV))
|
||||
{
|
||||
if ($_GET['refresh'] == 'filecache')
|
||||
$this->skipCache = CACHE_MODE_FILECACHE;
|
||||
else if ($_GET['refresh'] == 'memcached')
|
||||
$this->skipCache = CACHE_MODE_MEMCACHED;
|
||||
else if ($_GET['refresh'] == '')
|
||||
$this->skipCache = CACHE_MODE_FILECACHE | CACHE_MODE_MEMCACHED;
|
||||
}
|
||||
|
||||
$this->decay ??= Cfg::get('CACHE_DECAY');
|
||||
|
||||
$cacheDir = Cfg::get('CACHE_DIR');
|
||||
if ($cacheDir && Util::writeDir($cacheDir))
|
||||
$this->cacheDir = mb_substr($cacheDir, -1) != '/' ? $cacheDir.'/' : $cacheDir;
|
||||
|
||||
$this->cacheInited = true;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/466521
|
||||
private function formatCacheKey() : array
|
||||
{
|
||||
[$dbType, $dbTypeId, $category, $staffMask, $miscInfo] = $this->getCacheKeyComponents();
|
||||
|
||||
$fileKey = '';
|
||||
// DBType: 3
|
||||
$fileKey .= str_pad(dechex($dbType & 0xFFF), 3, 0, STR_PAD_LEFT);
|
||||
// DBTypeId: 6
|
||||
$fileKey .= str_pad(dechex($dbTypeId & 0xFFFFFF), 6, 0, STR_PAD_LEFT);
|
||||
// category: (2+4+4)
|
||||
$fileKey .= str_pad(dechex($category & 0xFFFFFFFFFF), 2+4+4, 0, STR_PAD_LEFT);
|
||||
// cacheType: 1
|
||||
$fileKey .= str_pad(dechex($this->_cacheType & 0xF), 1, 0, STR_PAD_LEFT);
|
||||
// localeId: 2,
|
||||
$fileKey .= str_pad(dechex(Lang::getLocale()->value & 0xFF), 2, 0, STR_PAD_LEFT);
|
||||
// staff mask: 4
|
||||
$fileKey .= str_pad(dechex($staffMask & 0xFFFFFFFF), 4, 0, STR_PAD_LEFT);
|
||||
// optioal: miscInfo
|
||||
if ($miscInfo)
|
||||
$fileKey .= '-'.$miscInfo;
|
||||
|
||||
// topDir, 2ndDir, file
|
||||
return array(
|
||||
str_pad(dechex($dbType & 0xFF), 2, 0, STR_PAD_LEFT),
|
||||
str_pad(dechex(($dbTypeId > 0 ? $dbTypeId : $category) & 0xFF), 2, 0, STR_PAD_LEFT),
|
||||
$fileKey
|
||||
);
|
||||
}
|
||||
|
||||
public function setOnCacheLoaded(callable $callback, mixed $params = null) : void
|
||||
{
|
||||
$this->onCacheLoaded = [$callback, $params];
|
||||
}
|
||||
|
||||
public function applyOnCacheLoaded(mixed &$data) : mixed
|
||||
{
|
||||
if (is_callable($this->onCacheLoaded[0]))
|
||||
return $this->onCacheLoaded[0]($data, $this->onCacheLoaded[1]);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function setCacheDecay(int $seconds) : void
|
||||
{
|
||||
if ($seconds < 0)
|
||||
return;
|
||||
|
||||
$this->decay = $seconds;
|
||||
}
|
||||
|
||||
abstract public function getCacheKeyComponents() : array;
|
||||
}
|
||||
|
||||
trait TrSearch
|
||||
{
|
||||
private int $maxResults = 500;
|
||||
private string $query = ''; // sanitized search string
|
||||
private int $searchMask = 0; // what to search for
|
||||
private Search $searchObj;
|
||||
|
||||
public function getCacheKeyComponents() : array
|
||||
{
|
||||
return array(
|
||||
-1, // DBType
|
||||
-1, // DBTypeId
|
||||
$this->searchMask, // category
|
||||
User::$groups, // staff mask
|
||||
md5($this->query) // misc (here search query)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Interface IProfilerList
|
||||
{
|
||||
public function getRegions() : void;
|
||||
}
|
||||
|
||||
trait TrProfiler
|
||||
{
|
||||
protected int $realmId = 0;
|
||||
protected string $battlegroup = ''; // not implemented, since no pserver supports it
|
||||
|
||||
public string $region = '';
|
||||
public string $realm = '';
|
||||
|
||||
private function getSubjectFromUrl(string $pageParam) : void
|
||||
{
|
||||
if (!$pageParam)
|
||||
return;
|
||||
|
||||
// cat[0] is always region
|
||||
// cat[1] is realm or bGroup (must be realm if cat[2] is set)
|
||||
// cat[2] is arena-team, guild or character
|
||||
$cat = explode('.', mb_strtolower($pageParam), 3);
|
||||
|
||||
$cat = array_map('urldecode', $cat);
|
||||
|
||||
if (array_search($cat[0], Util::$regions) === false)
|
||||
return;
|
||||
|
||||
$this->region = $cat[0];
|
||||
|
||||
// if ($cat[1] == Profiler::urlize(Cfg::get('BATTLEGROUP')))
|
||||
// $this->battlegroup = Cfg::get('BATTLEGROUP');
|
||||
if (isset($cat[1]))
|
||||
{
|
||||
foreach (Profiler::getRealms() as $rId => $r)
|
||||
{
|
||||
if (Profiler::urlize($r['name'], true) == $cat[1])
|
||||
{
|
||||
$this->realm = $r['name'];
|
||||
$this->realmId = $rId;
|
||||
if (isset($cat[2]) && mb_strlen($cat[2]) >= 2)
|
||||
$this->subjectName = mb_strtolower($cat[2]); // cannot reconstruct original name from urlized form; match against special name field
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function followBreadcrumbPath() : void
|
||||
{
|
||||
if ($this->region)
|
||||
{
|
||||
$this->breadcrumb[] = $this->region;
|
||||
|
||||
if ($this->realm)
|
||||
$this->breadcrumb[] = Profiler::urlize($this->realm, true);
|
||||
// else
|
||||
// $this->breadcrumb[] = Profiler::urlize(Cfg::get('BATTLEGROUP'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait TrProfilerDetail
|
||||
{
|
||||
use TrProfiler { TrProfiler::getSubjectFromUrl as _getSubjectFromUrl; }
|
||||
|
||||
protected string $subjectName = '';
|
||||
|
||||
public int $typeId = 0;
|
||||
public ?array $doResync = null;
|
||||
|
||||
private function getSubjectFromUrl(string $pageParam) : void
|
||||
{
|
||||
if (!$pageParam)
|
||||
return;
|
||||
|
||||
if (Util::checkNumeric($pageParam, NUM_CAST_INT))
|
||||
$this->typeId = $pageParam;
|
||||
else
|
||||
$this->_getSubjectFromUrl($pageParam);
|
||||
}
|
||||
|
||||
private function handleIncompleteData(int $type, int $guid) : void
|
||||
{
|
||||
// queue full fetch
|
||||
if ($newId = Profiler::scheduleResync($type, $this->realmId, $guid))
|
||||
{
|
||||
$this->template = 'text-page-generic';
|
||||
$this->doResync = [Type::getFileString($type), $newId];
|
||||
$this->inputbox = ['inputbox-status', ['head' => Lang::profiler('firstUseTitle', [Util::ucFirst($this->subjectName), $this->realm])]];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// todo: base info should have been created in __construct .. why are we here..?
|
||||
$this->forward('?'.Type::getFileString($type).'s='.$this->region.'.'.Profiler::urlize($this->realm, true).'&filter=na='.Util::ucFirst($this->subjectName).';ex=on');
|
||||
}
|
||||
}
|
||||
|
||||
trait TrProfilerList
|
||||
{
|
||||
use TrProfiler;
|
||||
|
||||
public array $regions = [];
|
||||
|
||||
public function getRegions() : void
|
||||
{
|
||||
$usedRegions = array_column(Profiler::getRealms(), 'region');
|
||||
foreach (Util::$regions as $idx => $id)
|
||||
if (in_array($id, $usedRegions))
|
||||
$this->regions[$id] = Lang::profiler('regions', $id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class BaseResponse
|
||||
{
|
||||
protected const PATTERN_TEXT_LINE = '/[\p{Cc}\p{Cf}\p{Co}\p{Cs}\p{Cn}]/ui';
|
||||
protected const PATTERN_TEXT_BLOB = '/[\x00-\x09\x0B-\x1F\p{Cf}\p{Co}\p{Cs}\p{Cn}]/ui';
|
||||
|
||||
protected static array $sql = []; // debug: sql stats container
|
||||
|
||||
protected array $expectedPOST = []; // fill with variables you that are going to be used; eg:
|
||||
protected array $expectedGET = []; // 'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdList']
|
||||
protected array $expectedCOOKIE = [];
|
||||
|
||||
protected array $_post = []; // the filtered variable result
|
||||
protected array $_get = [];
|
||||
protected array $_cookie = [];
|
||||
|
||||
protected int $requiredUserGroup = U_GROUP_NONE; // by default accessible to everone
|
||||
protected bool $requiresLogin = false; // normal users and guests are both U_GROUP_NONE, soooo.....
|
||||
protected mixed $result = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->initRequestData();
|
||||
|
||||
if (!User::isInGroup($this->requiredUserGroup))
|
||||
$this->onUserGroupMismatch();
|
||||
|
||||
if ($this->requiresLogin && !User::isLoggedIn())
|
||||
$this->onUserGroupMismatch();
|
||||
}
|
||||
|
||||
public function process() : void
|
||||
{
|
||||
$fromCache = false;
|
||||
|
||||
if ($this instanceof ICache)
|
||||
$fromCache = $this->loadCache($this->result);
|
||||
|
||||
if (!$this->result)
|
||||
$this->generate();
|
||||
|
||||
$this->display();
|
||||
|
||||
if ($this instanceof ICache && !$fromCache)
|
||||
$this->saveCache($this->result);
|
||||
}
|
||||
|
||||
private function initRequestData() : void
|
||||
{
|
||||
// php bug? If INPUT_X is empty, filter_input_array returns null/fails
|
||||
// only really relevant for INPUT_POST
|
||||
// manuall set everything null in this case
|
||||
|
||||
if ($this->expectedPOST)
|
||||
{
|
||||
if ($_POST)
|
||||
$this->_post = filter_input_array(INPUT_POST, $this->expectedPOST);
|
||||
else
|
||||
$this->_post = array_fill_keys(array_keys($this->expectedPOST), null);
|
||||
}
|
||||
|
||||
if ($this->expectedGET)
|
||||
{
|
||||
if ($_GET)
|
||||
$this->_get = filter_input_array(INPUT_GET, $this->expectedGET);
|
||||
else
|
||||
$this->_get = array_fill_keys(array_keys($this->expectedGET), null);
|
||||
}
|
||||
|
||||
if ($this->expectedCOOKIE)
|
||||
{
|
||||
if ($_COOKIE)
|
||||
$this->_cookie = filter_input_array(INPUT_COOKIE, $this->expectedCOOKIE);
|
||||
else
|
||||
$this->_cookie = array_fill_keys(array_keys($this->expectedCOOKIE), null);
|
||||
}
|
||||
}
|
||||
|
||||
protected function forward(string $url = '') : never
|
||||
{
|
||||
$this->sendNoCacheHeader();
|
||||
header('Location: '.($url ?: '.'), true, 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function forwardToSignIn(string $next = '') : never
|
||||
{
|
||||
$this->forward('?account=signin'.($next ? '&next='.$next : ''));
|
||||
}
|
||||
|
||||
protected function sumSQLStats() : void
|
||||
{
|
||||
Util::arraySumByKey(self::$sql, DB::Aowow()->getStatistics(), DB::World()->getStatistics());
|
||||
foreach (Profiler::getRealms() as $rId => $_)
|
||||
Util::arraySumByKey(self::$sql, DB::Characters($rId)->getStatistics());
|
||||
}
|
||||
|
||||
protected function sendNoCacheHeader()
|
||||
{
|
||||
header('Expires: Sat, 01 Jan 2000 01:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
}
|
||||
|
||||
|
||||
/****************************/
|
||||
/* required Parameter tests */
|
||||
/****************************/
|
||||
|
||||
protected function assertPOST(string ...$keys) : bool
|
||||
{
|
||||
foreach ($keys as $k) // not sent by browser || empty text field sent || validation failed
|
||||
if (!isset($this->_post[$k]) || $this->_post[$k] === null || $this->_post[$k] === '' || $this->_post[$k] === false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function assertGET(string ...$keys) : bool
|
||||
{
|
||||
foreach ($keys as $k)
|
||||
if (!isset($this->_get[$k]) || $this->_get[$k] === null || $this->_get[$k] === '' || $this->_get[$k] === false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function assertCOOKIE(string ...$keys) : bool
|
||||
{
|
||||
foreach ($keys as $k)
|
||||
if (!isset($this->_cookie[$k]) || $this->_cookie[$k] === null || $this->_cookie[$k] === '' || $this->_cookie[$k] === false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*******************************/
|
||||
/* Parameter validation checks */
|
||||
/*******************************/
|
||||
|
||||
protected static function checkRememberMe(string $val) : bool
|
||||
{
|
||||
return $val === 'yes';
|
||||
}
|
||||
|
||||
protected static function checkCheckbox(string $val) : bool
|
||||
{
|
||||
return $val === 'on';
|
||||
}
|
||||
|
||||
protected static function checkEmptySet(string $val) : bool
|
||||
{
|
||||
return $val === ''; // parameter is set and expected to be empty
|
||||
}
|
||||
|
||||
protected static function checkIdList(string $val) : array
|
||||
{
|
||||
if (preg_match('/^-?\d+(,-?\d+)*$/', $val))
|
||||
return array_map('intVal', explode(',', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected static function checkIntArray(string $val) : array
|
||||
{
|
||||
if (preg_match('/^-?\d+(:-?\d+)*$/', $val))
|
||||
return array_map('intVal', explode(':', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected static function checkIdListUnsigned(string $val) : array
|
||||
{
|
||||
if (preg_match('/^\d+(,\d+)*$/', $val))
|
||||
return array_map('intVal', explode(',', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected static function checkTextLine(string $val) : string
|
||||
{
|
||||
// trim non-printable chars
|
||||
return preg_replace(self::PATTERN_TEXT_LINE, '', trim(urldecode($val)));
|
||||
}
|
||||
|
||||
protected static function checkTextBlob(string $val) : string
|
||||
{
|
||||
// trim non-printable chars + excessive whitespaces (pattern includes \r)
|
||||
$str = preg_replace(self::PATTERN_TEXT_BLOB, '', trim($val));
|
||||
return preg_replace('/ +/', ' ', trim($str));
|
||||
}
|
||||
|
||||
|
||||
/********************/
|
||||
/* child implements */
|
||||
/********************/
|
||||
|
||||
// calc response
|
||||
abstract protected function generate() : void;
|
||||
|
||||
// send response
|
||||
abstract protected function display() : void;
|
||||
|
||||
// handling differs by medium
|
||||
abstract protected function onUserGroupMismatch() : never;
|
||||
}
|
||||
|
||||
?>
|
||||
687
includes/components/response/templateresponse.class.php
Normal file
687
includes/components/response/templateresponse.class.php
Normal file
@@ -0,0 +1,687 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
trait TrDetailPage
|
||||
{
|
||||
// template vars
|
||||
public ?InfoboxMarkup $infobox = null;
|
||||
public ?InfoboxMarkup $contributions = null;
|
||||
public ?array $series = null;
|
||||
public ?string $transfer = null; // faction transfer equivalent data
|
||||
public ?Markup $smartAI = null;
|
||||
public ?array $map = null;
|
||||
public array $headIcons = [];
|
||||
|
||||
public function getCacheKeyComponents() : array
|
||||
{
|
||||
return array(
|
||||
$this->type, // DBType
|
||||
$this->typeId, // DBTypeId
|
||||
-1, // category
|
||||
User::$groups, // staff mask
|
||||
'' // misc (here unused)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait TrListPage
|
||||
{
|
||||
public ?string $subCat = null;
|
||||
public ?Filter $filter = null;
|
||||
|
||||
public function getCacheKeyComponents() : array
|
||||
{
|
||||
// max. 3 catgs
|
||||
// catg max 65535
|
||||
if ($this->category)
|
||||
{
|
||||
$catg = 0x0;
|
||||
for ($i = 0; $i < 3; $i++)
|
||||
{
|
||||
$catg <<= 4;
|
||||
$catg |= ($this->category[$i] ?? 0) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
if ($get = $this->filter?->buildGETParam())
|
||||
$misc = md5($get);
|
||||
|
||||
return array(
|
||||
$this->type, // DBType
|
||||
-1, // DBTypeId
|
||||
$catg ?? -1, // category
|
||||
User::$groups, // staff mask
|
||||
$misc ?? '' // misc (here filter)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait TrGuideEditor
|
||||
{
|
||||
public int $typeId = 0;
|
||||
|
||||
public int $editCategory = 0;
|
||||
public int $editClassId = 0;
|
||||
public int $editSpecId = 0;
|
||||
public int $editRev = 0;
|
||||
public int $editStatus = GUIDE_STATUS_DRAFT;
|
||||
public string $editStatusColor = GuideMgr::STATUS_COLORS[GUIDE_STATUS_DRAFT];
|
||||
public string $editTitle = '';
|
||||
public string $editName = '';
|
||||
public string $editDescription = '';
|
||||
public string $editText = '';
|
||||
public Locale $editLocale = Locale::EN;
|
||||
}
|
||||
|
||||
class TemplateResponse extends BaseResponse
|
||||
{
|
||||
final protected const /* int */ TAB_DATABASE = 0;
|
||||
final protected const /* int */ TAB_TOOLS = 1;
|
||||
final protected const /* int */ TAB_MORE = 2;
|
||||
final protected const /* int */ TAB_COMMUNITY = 3;
|
||||
final protected const /* int */ TAB_STAFF = 4;
|
||||
final protected const /* int */ TAB_GUIDES = 6;
|
||||
|
||||
private array $jsgBuffer = []; // throw any db type references in here to be processed later
|
||||
private array $header = [];
|
||||
private string $fullParams = ''; // effectively articleUrl
|
||||
|
||||
protected string $template = '';
|
||||
protected array $breadcrumb = [];
|
||||
protected ?int $activeTab = null; // [Database, Tools, More, Community, Staff, null, Guides] ?? none
|
||||
protected string $pageName = '';
|
||||
protected array $category = [];
|
||||
protected array $validCats = [];
|
||||
protected ?string $articleUrl = null;
|
||||
protected bool $filterError = false; // retroactively apply error notice to fixed filter result
|
||||
|
||||
protected array $dataLoader = []; // ?data=x.y.z as javascript
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/jquery-3.7.0.min.js', SC_FLAG_NO_TIMESTAMP ],
|
||||
[SC_JS_FILE, 'js/basic.js' ],
|
||||
[SC_JS_FILE, 'widgets/power.js', SC_FLAG_NO_TIMESTAMP | SC_FLAG_APPEND_LOCALE],
|
||||
[SC_JS_FILE, 'js/locale_%s.js', SC_FLAG_LOCALIZED ],
|
||||
[SC_JS_FILE, 'js/global.js' ],
|
||||
[SC_JS_FILE, 'js/locale.js' ],
|
||||
[SC_JS_FILE, 'js/Markup.js' ],
|
||||
[SC_CSS_FILE, 'css/basic.css' ],
|
||||
[SC_CSS_FILE, 'css/global.css' ],
|
||||
[SC_CSS_FILE, 'css/aowow.css' ],
|
||||
[SC_CSS_FILE, 'css/locale_%s.css', SC_FLAG_LOCALIZED ]
|
||||
);
|
||||
|
||||
// debug: stats
|
||||
protected static float $time = 0.0;
|
||||
// protected static array $sql = [];
|
||||
// protected static array $cacheStats = [];
|
||||
public array $pageStats = []; // static properties carry the values, this is just for the PageTemplate to reference
|
||||
|
||||
// send to template
|
||||
public array $title = []; // head title components
|
||||
public string $h1 = ''; // body title
|
||||
public string $h1Link = ''; //
|
||||
public ?string $headerLogo = null; // url to non-standard logo for events etc.
|
||||
public string $search = ''; // prefilled search bar
|
||||
public string $wowheadLink = 'https://wowhead.com/';
|
||||
public int $contribute = CONTRIBUTE_NONE;
|
||||
public ?array $inputbox = null;
|
||||
public ?string $rss = null; // link rel=alternate for rss auto-discovery
|
||||
public ?string $tabsTitle = null;
|
||||
public ?Markup $extraText = null;
|
||||
public ?string $extraHTML = null;
|
||||
public array $redButtons = []; // see template/redButtons.tpl.php
|
||||
|
||||
// send to template, but it is js stuff
|
||||
public array $gPageInfo = [];
|
||||
public bool $gDataKey = false; // send g_DataKey to template or don't (stored in $_SESSION)
|
||||
public ?Markup $article = null;
|
||||
public ?Tabs $lvTabs = null;
|
||||
public array $pageTemplate = []; // js PageTemplate object
|
||||
public array $jsGlobals = []; // ready to be used in template
|
||||
|
||||
public function __construct(string $pageParam = '')
|
||||
{
|
||||
$this->title[] = Cfg::get('NAME');
|
||||
self::$time = microtime(true);
|
||||
|
||||
parent::__construct();
|
||||
|
||||
$this->fullParams = $this->pageName;
|
||||
if ($pageParam)
|
||||
$this->fullParams .= '='.$pageParam;
|
||||
|
||||
// prep js+css includes
|
||||
$parentVars = get_class_vars(__CLASS__);
|
||||
if ($parentVars['scripts'] != $this->scripts) // additions set in child class
|
||||
$this->scripts = array_merge($parentVars['scripts'], $this->scripts);
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF | U_GROUP_SCREENSHOT | U_GROUP_VIDEO))
|
||||
array_push($this->scripts, [SC_CSS_FILE, 'css/staff.css'], [SC_JS_FILE, 'js/staff.js']);
|
||||
|
||||
// get alt header logo
|
||||
if ($ahl = DB::Aowow()->selectCell('SELECT `altHeaderLogo` FROM ?_home_featuredbox WHERE ?d BETWEEN `startDate` AND `endDate` ORDER BY `id` DESC', time()))
|
||||
$this->headerLogo = Util::defStatic($ahl);
|
||||
|
||||
if ($this->pageName)
|
||||
{
|
||||
$this->wowheadLink = sprintf(WOWHEAD_LINK, Lang::getLocale()->domain(), $this->pageName, $pageParam ? '=' . $pageParam : '');
|
||||
$this->pageTemplate['pageName'] = $this->pageName;
|
||||
}
|
||||
|
||||
if (!is_null($this->activeTab))
|
||||
$this->pageTemplate['activeTab'] = $this->activeTab;
|
||||
|
||||
if (!$this->isValidPage())
|
||||
$this->onInvalidCategory();
|
||||
|
||||
if (Cfg::get('MAINTENANCE') && !User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$this->generateMaintenance();
|
||||
else if (Cfg::get('MAINTENANCE') && User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
Util::addNote('Maintenance mode enabled!');
|
||||
}
|
||||
|
||||
// by default goto login page
|
||||
protected function onUserGroupMismatch() : never
|
||||
{
|
||||
if (User::isLoggedIn())
|
||||
$this->generateError();
|
||||
|
||||
$this->forwardToSignIn($_SERVER['QUERY_STRING'] ?? '');
|
||||
}
|
||||
|
||||
// by default show error page
|
||||
protected function onInvalidCategory() : never
|
||||
{
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
// just pass through
|
||||
protected function addScript(array ...$scriptDefs) : void
|
||||
{
|
||||
if (!$this->result)
|
||||
$this->scripts = array_merge($this->scripts, $scriptDefs);
|
||||
else
|
||||
foreach ($scriptDefs as $s)
|
||||
$this->result->addScript(...$s);
|
||||
}
|
||||
|
||||
protected function addDataLoader(string ...$dataFiles) : void
|
||||
{
|
||||
if (!$this->result)
|
||||
$this->dataLoader = array_merge($this->dataLoader, $dataFiles);
|
||||
else
|
||||
$this->result->addDataLoader($dataFiles);
|
||||
}
|
||||
|
||||
public static function pageStatsHook(Template\PageTemplate &$pt, array &$stats) : void
|
||||
{
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
{
|
||||
$stats['time'] = Util::formatTime((microtime(true) - self::$time) * 1000, true);
|
||||
$stats['sql'] = ['count' => parent::$sql['count'], 'time' => Util::formatTime(parent::$sql['time'] * 1000, true)];
|
||||
$stats['cache'] = !empty(static::$cacheStats) ? [static::$cacheStats[0], Util::formatTimeDiff(static::$cacheStats[1])] : null;
|
||||
}
|
||||
else
|
||||
$stats = [];
|
||||
}
|
||||
|
||||
protected function getCategoryFromUrl(string $pageParam) : void
|
||||
{
|
||||
$arr = explode('.', $pageParam);
|
||||
foreach ($arr as $v)
|
||||
{
|
||||
if (!is_numeric($v))
|
||||
break;
|
||||
|
||||
$this->category[] = (int)$v;
|
||||
}
|
||||
}
|
||||
|
||||
// functionally this should be in PageTemplate but inaccessible there
|
||||
protected function fmtStaffTip(?string $text, string $tip) : string
|
||||
{
|
||||
if (!$text || !User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
return $text ?? '';
|
||||
else
|
||||
return sprintf(Util::$dfnString, $tip, $text);
|
||||
}
|
||||
|
||||
|
||||
/**********************/
|
||||
/* Prepare js-Globals */
|
||||
/**********************/
|
||||
|
||||
// add typeIds <int|array[int]> that should be displayed as jsGlobal on the page
|
||||
public function extendGlobalIds(int $type, int ...$ids) : void
|
||||
{
|
||||
if (!$type || !$ids)
|
||||
return;
|
||||
|
||||
if (!isset($this->jsgBuffer[$type]))
|
||||
$this->jsgBuffer[$type] = [];
|
||||
|
||||
foreach ($ids as $id)
|
||||
$this->jsgBuffer[$type][] = $id;
|
||||
}
|
||||
|
||||
// add jsGlobals or typeIds (can be mixed in one array: TYPE => [mixeddata]) to display on the page
|
||||
public function extendGlobalData(array $data, ?array $extra = null) : void
|
||||
{
|
||||
foreach ($data as $type => $globals)
|
||||
{
|
||||
if (!is_array($globals) || !$globals)
|
||||
continue;
|
||||
|
||||
$this->initJSGlobal($type);
|
||||
|
||||
// can be id => data
|
||||
// or idx => id
|
||||
// and may be mixed
|
||||
foreach ($globals as $k => $v)
|
||||
{
|
||||
if (is_array($v))
|
||||
{
|
||||
// localize name fields .. except for icons .. icons are special
|
||||
if ($type != Type::ICON)
|
||||
{
|
||||
foreach (['name', 'namefemale'] as $n)
|
||||
{
|
||||
if (!isset($v[$n]))
|
||||
continue;
|
||||
|
||||
$v[$n . '_'.Lang::getLocale()->json()] = $v[$n];
|
||||
unset($v[$n]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->jsGlobals[$type][1][$k] = $v;
|
||||
}
|
||||
else if (is_numeric($v))
|
||||
$this->extendGlobalIds($type, $v);
|
||||
}
|
||||
}
|
||||
|
||||
if ($extra)
|
||||
{
|
||||
$namedExtra = [];
|
||||
foreach ($extra as $typeId => $data)
|
||||
foreach ($data as $k => $v)
|
||||
$namedExtra[$typeId][$k.'_'.Lang::getLocale()->json()] = $v;
|
||||
|
||||
$this->jsGlobals[$type][2] = $namedExtra;
|
||||
}
|
||||
}
|
||||
|
||||
// init store for type
|
||||
private function initJSGlobal(int $type) : void
|
||||
{
|
||||
$jsg = &$this->jsGlobals; // shortcut
|
||||
|
||||
if (isset($jsg[$type]))
|
||||
return;
|
||||
|
||||
if ($tpl = Type::getJSGlobalTemplate($type))
|
||||
$jsg[$type] = $tpl;
|
||||
}
|
||||
|
||||
// lookup jsGlobals from collected typeIds
|
||||
private function applyGlobals() : void
|
||||
{
|
||||
foreach ($this->jsgBuffer as $type => $ids)
|
||||
{
|
||||
foreach ($ids as $k => $id) // filter already generated data, maybe we can save a lookup or two
|
||||
if (isset($this->jsGlobals[$type][1][$id]))
|
||||
unset($ids[$k]);
|
||||
|
||||
if (!$ids)
|
||||
continue;
|
||||
|
||||
$this->initJSGlobal($type);
|
||||
|
||||
$obj = Type::newList($type, [Cfg::get('SQL_LIMIT_NONE'), ['id', array_unique($ids, SORT_NUMERIC)]]);
|
||||
if (!$obj)
|
||||
continue;
|
||||
|
||||
$this->extendGlobalData($obj->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
// delete processed ids
|
||||
$this->jsgBuffer[$type] = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************/
|
||||
/* Generic Page Content */
|
||||
/************************/
|
||||
|
||||
// get announcements and notes for user
|
||||
private function addAnnouncements(bool $onlyGenerics = false) : void
|
||||
{
|
||||
$announcements = [];
|
||||
|
||||
// display occured notices
|
||||
$notes = $_SESSION['notes'] ?? [];
|
||||
unset($_SESSION['notes']);
|
||||
|
||||
$notes[] = [...Util::getNotes(), 'One or more issues occured during page generation'];
|
||||
|
||||
foreach ($notes as $i => [$messages, $logLevel, $head])
|
||||
{
|
||||
if (!$messages)
|
||||
continue;
|
||||
|
||||
array_unshift($messages, $head);
|
||||
|
||||
$colors = array( // [border, text]
|
||||
LOG_LEVEL_ERROR => ['C50F1F', 'E51223'],
|
||||
LOG_LEVEL_WARN => ['C19C00', 'E5B700'],
|
||||
LOG_LEVEL_INFO => ['3A96DD', '42ADFF']
|
||||
);
|
||||
|
||||
$text = new LocString(['name_loc' . Lang::getLocale()->value => '[span]'.implode("[br]", $messages).'[/span]'], callback: Util::defStatic(...));
|
||||
$style = 'color: #'.($colors[$logLevel][1] ?? 'fff').'; font-weight: bold; font-size: 14px; padding-left: 40px; background-image: url('.Cfg::get('STATIC_URL').'/images/announcements/warn-small.png); background-size: 15px 15px; background-position: 12px center; border: dashed 2px #'.($colors[$logLevel][0] ?? 'fff').';';
|
||||
|
||||
$announcements[] = new Announcement(-$i, 'internal error', $text, style: $style);
|
||||
}
|
||||
|
||||
// fetch announcements
|
||||
$fromDB = DB::Aowow()->select(
|
||||
'SELECT `id`, `mode`, `status`, `name`, `style`, `text_loc0`, `text_loc2`, `text_loc3`, `text_loc4`, `text_loc6`, `text_loc8`
|
||||
FROM ?_announcements
|
||||
WHERE (`status` = ?d { OR `status` = ?d } ) AND
|
||||
(`page` = "*" { OR `page` = ? } ) AND
|
||||
(`groupMask` = 0 OR `groupMask` & ?d)',
|
||||
Announcement::STATUS_ENABLED, User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU) ? Announcement::STATUS_DISABLED : DBSIMPLE_SKIP,
|
||||
$onlyGenerics || !$this->pageName ? DBSIMPLE_SKIP : $this->pageName,
|
||||
User::$groups
|
||||
);
|
||||
|
||||
foreach ($fromDB as $a)
|
||||
if (($ann = new Announcement($a['id'], $a['name'], new LocString($a, 'text', Util::defStatic(...)), $a['mode'], $a['status'], Util::defStatic($a['style'])))->status != Announcement::STATUS_DELETED)
|
||||
$announcements[] = $ann;
|
||||
|
||||
$this->result->announcements = $announcements;
|
||||
}
|
||||
|
||||
// get article & static infobox (run before processing jsGlobals)
|
||||
private function addArticle() : void
|
||||
{
|
||||
if ($this->article)
|
||||
return;
|
||||
|
||||
$article = [];
|
||||
if (isset($this->guideRevision))
|
||||
$article = DB::Aowow()->selectRow('SELECT `article`, `locale`, `editAccess` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d AND `rev` = ?d',
|
||||
Type::GUIDE, $this->typeId, $this->guideRevision);
|
||||
if (!$article && $this->gPageInfo['articleUrl'])
|
||||
$article = DB::Aowow()->selectRow('SELECT `article`, `locale`, `editAccess` FROM ?_articles WHERE `url` = ? AND `locale` IN (?a) ORDER BY `locale` DESC, `rev` DESC LIMIT 1',
|
||||
$this->gPageInfo['articleUrl'], [Lang::getLocale()->value, Locale::EN->value]);
|
||||
if (!$article && !empty($this->type) && isset($this->typeId))
|
||||
$article = DB::Aowow()->selectRow('SELECT `article`, `locale`, `editAccess` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d AND `locale` IN (?a) ORDER BY `locale` DESC, `rev` DESC LIMIT 1',
|
||||
$this->type, $this->typeId, [Lang::getLocale()->value, Locale::EN->value]);
|
||||
|
||||
if (!$article)
|
||||
return;
|
||||
|
||||
$text = Util::defStatic($article['article']);
|
||||
$opts = [];
|
||||
|
||||
// convert U_GROUP_* to MARKUP.CLASS_* (as seen in js-object Markup)
|
||||
if ($article['editAccess'] & (U_GROUP_ADMIN | U_GROUP_VIP | U_GROUP_DEV))
|
||||
$opts['allow'] = Markup::CLASS_ADMIN;
|
||||
else if ($article['editAccess'] & U_GROUP_STAFF)
|
||||
$opts['allow'] = Markup::CLASS_STAFF;
|
||||
else if ($article['editAccess'] & U_GROUP_PREMIUM)
|
||||
$opts['allow'] = Markup::CLASS_PREMIUM;
|
||||
else if ($article['editAccess'] & U_GROUP_PENDING)
|
||||
$opts['allow'] = Markup::CLASS_PENDING;
|
||||
else
|
||||
$opts['allow'] = Markup::CLASS_USER;
|
||||
|
||||
if (!empty($this->type) && isset($this->typeId))
|
||||
$opts['dbpage'] = 1;
|
||||
|
||||
if ($article['locale'] != Lang::getLocale()->value)
|
||||
$opts['prepend'] = '<div class="notice-box"><span class="icon-bubble">'.Lang::main('langOnly', [Lang::lang($article['locale'])]).'</span></div>';
|
||||
|
||||
$this->article = new Markup($text, $opts);
|
||||
|
||||
if ($jsg = $this->article->getJsGlobals())
|
||||
$this->extendGlobalData($jsg);
|
||||
|
||||
$this->gPageInfo['editAccess'] = $article['editAccess'];
|
||||
|
||||
if (method_exists($this, 'postArticle')) // e.g. update variables in article
|
||||
$this->postArticle($this->article['text']);
|
||||
}
|
||||
|
||||
private function addCommunityContent() : void
|
||||
{
|
||||
$community = array(
|
||||
'coError' => $_SESSION['error']['co'] ?? null,
|
||||
'ssError' => $_SESSION['error']['ss'] ?? null,
|
||||
'viError' => $_SESSION['error']['vi'] ?? null
|
||||
);
|
||||
|
||||
if ($this->contribute & CONTRIBUTE_CO)
|
||||
$community['co'] = Util::toJSON(CommunityContent::getComments($this->type, $this->typeId));
|
||||
|
||||
if ($this->contribute & CONTRIBUTE_SS)
|
||||
$community['ss'] = Util::toJSON(CommunityContent::getScreenshots($this->type, $this->typeId));
|
||||
|
||||
if ($this->contribute & CONTRIBUTE_VI)
|
||||
$community['vi'] = Util::toJSON(CommunityContent::getVideos($this->type, $this->typeId));
|
||||
|
||||
unset($_SESSION['error']);
|
||||
|
||||
// as comments are not cached, those globals cant be either
|
||||
$this->extendGlobalData(CommunityContent::getJSGlobals());
|
||||
|
||||
$this->result->community = $community;
|
||||
$this->applyGlobals();
|
||||
}
|
||||
|
||||
|
||||
/**************/
|
||||
/* Generators */
|
||||
/**************/
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->result = new Template\PageTemplate($this->template, $this);
|
||||
|
||||
foreach ($this->scripts as $s)
|
||||
$this->result->addScript(...$s);
|
||||
|
||||
$this->result->addDataLoader(...$this->dataLoader);
|
||||
|
||||
// static::class so pageStatsHook defined here, can access cacheStats defined in the implementation
|
||||
$this->result->registerDisplayHook('pageStats', [static::class, 'pageStatsHook']);
|
||||
|
||||
// only adds edit links to the staff menu: precursor to guides?
|
||||
if (!($this instanceof GuideBaseResponse))
|
||||
$this->gPageInfo += array(
|
||||
'articleUrl' => $this->articleUrl ?? $this->fullParams, // is actually be the url-param
|
||||
'editAccess' => (U_GROUP_ADMIN | U_GROUP_EDITOR | U_GROUP_BUREAU)
|
||||
);
|
||||
|
||||
if ($this->breadcrumb)
|
||||
$this->pageTemplate['breadcrumb'] = $this->breadcrumb;
|
||||
|
||||
if (isset($this->filter))
|
||||
$this->pageTemplate['filter'] = $this->filter->query ? 1 : 0;
|
||||
|
||||
$this->addArticle();
|
||||
|
||||
$this->applyGlobals();
|
||||
}
|
||||
|
||||
// we admit this page exists and an error occured on it
|
||||
public function generateError(?string $altPageName = null) : never
|
||||
{
|
||||
$this->result = new Template\PageTemplate('text-page-generic', $this);
|
||||
|
||||
// only use own script defs
|
||||
foreach (get_class_vars(self::class)['scripts'] as $s)
|
||||
$this->result->addScript(...$s);
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF | U_GROUP_SCREENSHOT | U_GROUP_VIDEO))
|
||||
{
|
||||
$this->result->addScript(SC_CSS_FILE, 'css/staff.css');
|
||||
$this->result->addScript(SC_JS_FILE, 'js/staff.js');
|
||||
}
|
||||
|
||||
$this->result->registerDisplayHook('pageStats', [self::class, 'pageStatsHook']);
|
||||
|
||||
$this->title[] = Lang::main('errPageTitle');
|
||||
$this->h1 = Lang::main('errPageTitle');
|
||||
$this->articleUrl = 'page-not-found';
|
||||
$this->gPageInfo += array(
|
||||
'articleUrl' => 'page-not-found',
|
||||
'editAccess' => (U_GROUP_ADMIN | U_GROUP_EDITOR | U_GROUP_BUREAU)
|
||||
);
|
||||
|
||||
$this->pageTemplate['pageName'] ??= $altPageName ?? 'page-not-found';
|
||||
|
||||
$this->addArticle();
|
||||
|
||||
$this->sumSQLStats();
|
||||
|
||||
$this->header[] = ['HTTP/1.0 404 Not Found', true, 404];
|
||||
|
||||
$this->display(true);
|
||||
exit;
|
||||
}
|
||||
|
||||
// we do not have this page
|
||||
public function generateNotFound(string $title = '', string $msg = '') : never
|
||||
{
|
||||
$this->result = new Template\PageTemplate('text-page-generic', $this);
|
||||
|
||||
// only use own script defs
|
||||
foreach (get_class_vars(self::class)['scripts'] as $s)
|
||||
$this->result->addScript(...$s);
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF | U_GROUP_SCREENSHOT | U_GROUP_VIDEO))
|
||||
{
|
||||
$this->result->addScript(SC_CSS_FILE, 'css/staff.css');
|
||||
$this->result->addScript(SC_JS_FILE, 'js/staff.js');
|
||||
}
|
||||
|
||||
$this->result->registerDisplayHook('pageStats', [self::class, 'pageStatsHook']);
|
||||
|
||||
array_unshift($this->title, Lang::main('nfPageTitle'));
|
||||
|
||||
$this->inputbox = ['inputbox-status', array(
|
||||
'head' => isset($this->typeId) ? Util::ucWords($title).' #'.$this->typeId : $title,
|
||||
'error' => !$msg && isset($this->typeId) ? Lang::main('pageNotFound', [$title]) : $msg
|
||||
)];
|
||||
|
||||
$this->contribute = CONTRIBUTE_NONE;
|
||||
|
||||
if (!empty($this->breadcrumb))
|
||||
$this->pageTemplate['breadcrumb'] = $this->breadcrumb;
|
||||
|
||||
$this->sumSQLStats();
|
||||
|
||||
$this->header[] = ['HTTP/1.0 404 Not Found', true, 404];
|
||||
|
||||
$this->display(true);
|
||||
exit;
|
||||
}
|
||||
|
||||
// display brb gnomes
|
||||
public function generateMaintenance() : never
|
||||
{
|
||||
$this->result = new Template\PageTemplate('maintenance', $this);
|
||||
|
||||
$this->header[] = ['HTTP/1.0 503 Service Temporarily Unavailable', true, 503];
|
||||
$this->header[] = ['Retry-After: '.(3 * HOUR)];
|
||||
|
||||
$this->display(true);
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function display(bool $withError = false) : void
|
||||
{
|
||||
$this->title = Util::htmlEscape($this->title);
|
||||
$this->search = Util::htmlEscape($this->search);
|
||||
// can't escape >h1 here, because CharTitles legitimately add HTML
|
||||
|
||||
$this->addAnnouncements($withError);
|
||||
if (!$withError)
|
||||
$this->addCommunityContent();
|
||||
|
||||
// force jsGlobals from Announcements/CommunityContent into PageTemplate
|
||||
// as this may be loaded from cache, it will be unlinked from its response
|
||||
if ($ptJSG = $this->result->jsGlobals)
|
||||
{
|
||||
Util::mergeJsGlobals($ptJSG, $this->jsGlobals);
|
||||
$this->result->jsGlobals = $ptJSG;
|
||||
}
|
||||
else if ($this->jsGlobals)
|
||||
$this->result->jsGlobals = $this->jsGlobals;
|
||||
|
||||
if ($this instanceof ICache)
|
||||
$this->applyOnCacheLoaded($this->result);
|
||||
|
||||
if ($this->result && $this->filterError)
|
||||
$this->result->setListviewError();
|
||||
|
||||
$this->sumSQLStats();
|
||||
|
||||
// Heisenbug: IE11 and FF32 will sometimes (under unknown circumstances) cache 302 redirects and stop
|
||||
// re-requesting them from the server but load them from local cache, thus breaking menu features.
|
||||
$this->sendNoCacheHeader();
|
||||
foreach ($this->header as $h)
|
||||
header(...$h);
|
||||
|
||||
$this->result?->render();
|
||||
}
|
||||
|
||||
|
||||
/**********/
|
||||
/* Checks */
|
||||
/**********/
|
||||
|
||||
// has a valid combination of categories
|
||||
private function isValidPage() : bool
|
||||
{
|
||||
if (!$this->category || !$this->validCats)
|
||||
return true;
|
||||
|
||||
$c = $this->category; // shorthand
|
||||
|
||||
switch (count($c))
|
||||
{
|
||||
case 0: // no params works always
|
||||
return true;
|
||||
case 1: // null is valid || value in a 1-dim-array || (key for a n-dim-array && ( has more subcats || no further subCats ))
|
||||
$filtered = array_filter($this->validCats, fn ($x) => is_int($x));
|
||||
return $c[0] === null || in_array($c[0], $filtered) || (!empty($this->validCats[$c[0]]) && (is_array($this->validCats[$c[0]]) || $this->validCats[$c[0]] === true));
|
||||
case 2: // first param has to be a key. otherwise invalid
|
||||
if (!isset($this->validCats[$c[0]]))
|
||||
return false;
|
||||
|
||||
// check if the sub-array is n-imensional
|
||||
if (is_array($this->validCats[$c[0]]) && count($this->validCats[$c[0]]) == count($this->validCats[$c[0]], COUNT_RECURSIVE))
|
||||
return in_array($c[1], $this->validCats[$c[0]]); // second param is value in second level array
|
||||
else
|
||||
return isset($this->validCats[$c[0]][$c[1]]); // check if params is key of another array
|
||||
case 3: // 3 params MUST point to a specific value
|
||||
return isset($this->validCats[$c[0]][$c[1]]) && in_array($c[2], $this->validCats[$c[0]][$c[1]]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
163
includes/components/response/textresponse.class.php
Normal file
163
includes/components/response/textresponse.class.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
trait TrTooltip
|
||||
{
|
||||
private array $enhancedTT = [];
|
||||
|
||||
public function getCacheKeyComponents() : array
|
||||
{
|
||||
$key = array(
|
||||
$this->type, // DBType
|
||||
$this->typeId, // DBTypeId
|
||||
-1, // category
|
||||
User::$groups, // staff mask
|
||||
'' // misc (here tooltip)
|
||||
);
|
||||
|
||||
if ($this->enhancedTT)
|
||||
$key[4] = md5(serialize($this->enhancedTT));
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait TrRss
|
||||
{
|
||||
private array $feedData = [];
|
||||
|
||||
protected function generateRSS(string $title, string $link) : string
|
||||
{
|
||||
$root = new SimpleXML('<rss />');
|
||||
$root->addAttribute('version', '2.0');
|
||||
|
||||
$channel = $root->addChild('channel');
|
||||
|
||||
$channel->addChild('title', Cfg::get('NAME_SHORT').' - '.$title);
|
||||
$channel->addChild('link', Cfg::get('HOST_URL').'/?'.$link);
|
||||
$channel->addChild('description', Cfg::get('NAME'));
|
||||
$channel->addChild('language', implode('-', str_split(Lang::getLocale()->json(), 2)));
|
||||
$channel->addChild('ttl', Cfg::get('TTL_RSS'));
|
||||
$channel->addChild('lastBuildDate', date(DATE_RSS));
|
||||
|
||||
foreach ($this->feedData as $row)
|
||||
{
|
||||
$item = $channel->addChild('item');
|
||||
|
||||
foreach ($row as $key => [$isCData, $attrib, $text])
|
||||
{
|
||||
if ($isCData && $text)
|
||||
$child = $item->addChild($key)->addCData($text);
|
||||
else
|
||||
$child = $item->addChild($key, $text);
|
||||
|
||||
foreach ($attrib as $k => $v)
|
||||
$child->addAttribute($k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
return $root->asXML();
|
||||
}
|
||||
}
|
||||
|
||||
trait TrCommunityHelper
|
||||
{
|
||||
private function handleCaption(?string $caption) : string
|
||||
{
|
||||
if (!$caption)
|
||||
return '';
|
||||
|
||||
// trim excessive whitespaces
|
||||
$caption = trim(preg_replace('/\s{2,}/', ' ', $caption));
|
||||
|
||||
// shorten to fit db
|
||||
$caption = substr($caption, 0, 200);
|
||||
|
||||
// jsEscape just in case
|
||||
return Util::jsEscape($caption);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TextResponse extends BaseResponse
|
||||
{
|
||||
protected string $contentType = MIME_TYPE_JAVASCRIPT;
|
||||
protected ?string $redirectTo = null;
|
||||
protected array $params = [];
|
||||
|
||||
/// generation stats
|
||||
protected static float $time = 0.0;
|
||||
|
||||
public function __construct(string $pageParam = '')
|
||||
{
|
||||
self::$time = microtime(true);
|
||||
$this->params = explode('.', $pageParam);
|
||||
// todo - validate params?
|
||||
|
||||
parent::__construct();
|
||||
|
||||
if (Cfg::get('MAINTENANCE') && !User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
// by default ajax has nothing to say
|
||||
protected function onUserGroupMismatch() : never
|
||||
{
|
||||
trigger_error('TextResponse::onUserGroupMismatch - loggedIn: '.($this->requiresLogin ? 'yes' : 'no').'; expected: '.Util::asHex($this->requiredUserGroup).'; is: '.Util::asHex(User::$groups), E_USER_WARNING);
|
||||
|
||||
$this->generate403();
|
||||
}
|
||||
|
||||
public function generate404(?string $out = null) : never
|
||||
{
|
||||
header('HTTP/1.0 404 Not Found', true, 404);
|
||||
header($this->contentType);
|
||||
exit($out);
|
||||
}
|
||||
|
||||
public function generate403(?string $out = null) : never
|
||||
{
|
||||
header('HTTP/1.0 403 Forbidden', true, 403);
|
||||
header($this->contentType);
|
||||
exit($out);
|
||||
}
|
||||
|
||||
protected function display() : void
|
||||
{
|
||||
if ($this->redirectTo)
|
||||
$this->forward($this->redirectTo);
|
||||
|
||||
$out = ($this instanceof ICache) ? $this->applyOnCacheLoaded($this->result) : $this->result;
|
||||
|
||||
$this->sendNoCacheHeader();
|
||||
header($this->contentType);
|
||||
|
||||
// NOTE - this may fuck up some javascripts that say they expect ajax, but use the whole string anyway
|
||||
// so it's limited to tooltips
|
||||
if (Cfg::get('DEBUG') && User::isInGroup(U_GROUP_STAFF) && $this->result instanceof Tooltip)
|
||||
{
|
||||
$this->sumSQLStats();
|
||||
|
||||
echo "/*\n";
|
||||
echo " * generated in ".Util::formatTime((microtime(true) - self::$time) * 1000)."\n";
|
||||
echo " * " . parent::$sql['count'] . " SQL queries in " . Util::formatTime(parent::$sql['time'] * 1000) . "\n";
|
||||
if ($this instanceof ICache && static::$cacheStats)
|
||||
{
|
||||
[$mode, $set, $lifetime] = static::$cacheStats;
|
||||
echo " * stored in " . ($mode == CACHE_MODE_MEMCACHED ? 'Memcached' : 'filecache') . ":\n";
|
||||
echo " * + ".date('c', $set) . ' - ' . Util::formatTimeDiff($set) . "\n";
|
||||
echo " * - ".date('c', $set + $lifetime) . ' - in '.Util::formatTime(($set + $lifetime - time()) * 1000) . "\n";
|
||||
}
|
||||
echo " */\n\n";
|
||||
}
|
||||
|
||||
echo $out;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -56,6 +56,8 @@ class UserList extends DBTypeList
|
||||
|
||||
public function getListviewData() : array { return []; }
|
||||
public function renderTooltip() : ?string { return null; }
|
||||
|
||||
public static function getName($id) : ?LocString { return null; }
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -17,7 +17,7 @@ define('TDB_WORLD_EXPECTED_VER', 24041);
|
||||
|
||||
// as of 01.01.2024 https://www.wowhead.com/wotlk/de/spell=40120/{seo}
|
||||
// https://www.wowhead.com/wotlk/es/search=vuelo
|
||||
define('WOWHEAD_LINK', 'https://www.wowhead.com/wotlk/%s/%s=%s');
|
||||
define('WOWHEAD_LINK', 'https://www.wowhead.com/wotlk/%s/%s%s');
|
||||
|
||||
define('LOG_LEVEL_ERROR', 1);
|
||||
define('LOG_LEVEL_WARN', 2);
|
||||
@@ -25,7 +25,8 @@ define('LOG_LEVEL_INFO', 3);
|
||||
|
||||
define('MIME_TYPE_TEXT', 'Content-Type: text/plain; charset=utf-8');
|
||||
define('MIME_TYPE_XML', 'Content-Type: text/xml; charset=utf-8');
|
||||
define('MIME_TYPE_JSON', 'Content-Type: application/x-javascript; charset=utf-8');
|
||||
define('MIME_TYPE_JAVASCRIPT', 'Content-Type: application/x-javascript; charset=utf-8');
|
||||
define('MIME_TYPE_JSON', 'Content-Type: application/json; charset=utf-8');
|
||||
define('MIME_TYPE_OPENSEARCH', 'Content-Type: application/x-suggestions+json; charset=utf-8');
|
||||
define('MIME_TYPE_RSS', 'Content-Type: application/rss+xml; charset=utf-8');
|
||||
define('MIME_TYPE_JPEG', 'Content-Type: image/jpeg');
|
||||
|
||||
@@ -68,6 +68,8 @@ spl_autoload_register(function (string $class) : void
|
||||
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';
|
||||
else if (file_exists('includes/components/response/'.strtolower($class).'.class.php'))
|
||||
require_once 'includes/components/response/'.strtolower($class).'.class.php';
|
||||
});
|
||||
|
||||
// TC systems in components
|
||||
@@ -121,41 +123,6 @@ spl_autoload_register(function (string $class) : void
|
||||
throw new \Exception('could not register type class: '.$cl);
|
||||
});
|
||||
|
||||
// endpoint loader
|
||||
spl_autoload_register(function (string $class) : void
|
||||
{
|
||||
if ($i = strrpos($class, '\\'))
|
||||
$class = substr($class, $i + 1);
|
||||
|
||||
if (preg_match('/[^\w]/i', $class))
|
||||
return;
|
||||
|
||||
$class = strtolower($class);
|
||||
|
||||
if (stripos($class, 'ajax') === 0) // handles ajax and jsonp requests
|
||||
{
|
||||
if (file_exists('includes/ajaxHandler/'.strtr($class, ['ajax' => '']).'.class.php'))
|
||||
{
|
||||
require_once 'includes/ajaxHandler/ajaxHandler.class.php';
|
||||
require_once 'includes/ajaxHandler/'.strtr($class, ['ajax' => '']).'.class.php';
|
||||
}
|
||||
else
|
||||
throw new \Exception('could not register ajaxHandler class: '.$class);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (stripos($class, 'page')) // handles templated pages
|
||||
{
|
||||
if (file_exists('pages/'.strtr($class, ['page' => '']).'.php'))
|
||||
{
|
||||
require_once 'pages/genericPage.class.php';
|
||||
require_once 'pages/'.strtr($class, ['page' => '']).'.php';
|
||||
}
|
||||
else if ($class == 'genericpage') // may be called directly in fatal error case
|
||||
require_once 'pages/genericPage.class.php';
|
||||
}
|
||||
});
|
||||
|
||||
set_error_handler(function(int $errNo, string $errStr, string $errFile, int $errLine) : bool
|
||||
{
|
||||
// either from test function or handled separately
|
||||
@@ -208,13 +175,17 @@ set_exception_handler(function (\Throwable $e) : void
|
||||
else
|
||||
{
|
||||
Util::addNote('Exception - '.$e->getMessage().' @ '.$e->getFile(). ':'.$e->getLine()."\n".$e->getTraceAsString(), U_GROUP_EMPLOYEE, LOG_LEVEL_ERROR);
|
||||
(new GenericPage())->error();
|
||||
(new TemplateResponse())->generateError();
|
||||
}
|
||||
});
|
||||
|
||||
// handle fatal errors
|
||||
register_shutdown_function(function() : void
|
||||
{
|
||||
// defer undisplayed error/exception notes
|
||||
if (!CLI && ($n = Util::getNotes()))
|
||||
$_SESSION['notes'][] = [$n[0], $n[1], 'Defered issues from previous request'];
|
||||
|
||||
if ($e = error_get_last())
|
||||
{
|
||||
if (DB::isConnected(DB_AOWOW))
|
||||
@@ -263,7 +234,7 @@ if (!CLI)
|
||||
{
|
||||
// not displaying the brb gnomes as static_host is missing, but eh...
|
||||
if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD) || !Cfg::get('HOST_URL') || !Cfg::get('STATIC_URL'))
|
||||
(new GenericPage())->maintenance();
|
||||
(new TemplateResponse())->generateMaintenance();
|
||||
|
||||
// Setup Session
|
||||
$cacheDir = Cfg::get('SESSION_CACHE_DIR');
|
||||
@@ -275,7 +246,7 @@ if (!CLI)
|
||||
if (!session_start())
|
||||
{
|
||||
trigger_error('failed to start session', E_USER_ERROR);
|
||||
(new GenericPage())->error();
|
||||
(new TemplateResponse())->generateError();
|
||||
}
|
||||
|
||||
if (User::init())
|
||||
@@ -300,12 +271,6 @@ if (!CLI)
|
||||
if (DB::isConnected(DB_CHARACTERS . $idx))
|
||||
DB::Characters($idx)->setLogger(DB::profiler(...));
|
||||
}
|
||||
|
||||
// parse page-parameters .. sanitize before use!
|
||||
$str = explode('&', $_SERVER['QUERY_STRING'] ?? '', 2)[0];
|
||||
$_ = explode('=', $str, 2);
|
||||
$pageCall = mb_strtolower($_[0]);
|
||||
$pageParam = $_[1] ?? '';
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -18,104 +18,6 @@ class SimpleXML extends \SimpleXMLElement
|
||||
}
|
||||
}
|
||||
|
||||
trait TrRequestData
|
||||
{
|
||||
// const in trait supported in php8.2+
|
||||
public const PATTERN_TEXT_LINE = '/[\p{Cc}\p{Cf}\p{Co}\p{Cs}\p{Cn}]/ui';
|
||||
public const PATTERN_TEXT_BLOB = '/[\x00-\x09\x0B-\x1F\p{Cf}\p{Co}\p{Cs}\p{Cn}]/ui';
|
||||
|
||||
protected $_get = []; // fill with variables you that are going to be used; eg:
|
||||
protected $_post = []; // 'id' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkIdList']
|
||||
protected $_cookie = [];
|
||||
|
||||
private $filtered = false;
|
||||
|
||||
private function initRequestData() : void
|
||||
{
|
||||
if ($this->filtered)
|
||||
return;
|
||||
|
||||
// php bug? If INPUT_X is empty, filter_input_array returns null/fails
|
||||
// only really relevant for INPUT_POST
|
||||
// manuall set everything null in this case
|
||||
|
||||
if ($this->_post)
|
||||
{
|
||||
if ($_POST)
|
||||
$this->_post = filter_input_array(INPUT_POST, $this->_post);
|
||||
else
|
||||
$this->_post = array_fill_keys(array_keys($this->_post), null);
|
||||
}
|
||||
|
||||
if ($this->_get)
|
||||
{
|
||||
if ($_GET)
|
||||
$this->_get = filter_input_array(INPUT_GET, $this->_get);
|
||||
else
|
||||
$this->_get = array_fill_keys(array_keys($this->_get), null);
|
||||
}
|
||||
|
||||
if ($this->_cookie)
|
||||
{
|
||||
if ($_COOKIE)
|
||||
$this->_cookie = filter_input_array(INPUT_COOKIE, $this->_cookie);
|
||||
else
|
||||
$this->_cookie = array_fill_keys(array_keys($this->_cookie), null);
|
||||
}
|
||||
|
||||
$this->filtered = true;
|
||||
}
|
||||
|
||||
private static function checkEmptySet(string $val) : bool
|
||||
{
|
||||
return $val === ''; // parameter is expected to be empty
|
||||
}
|
||||
|
||||
private static function checkInt(string $val) : int
|
||||
{
|
||||
if (preg_match('/^-?\d+$/', $val))
|
||||
return intVal($val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static function checkIdList(string $val) : array
|
||||
{
|
||||
if (preg_match('/^-?\d+(,-?\d+)*$/', $val))
|
||||
return array_map('intVal', explode(',', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private static function checkIntArray(string $val) : array
|
||||
{
|
||||
if (preg_match('/^-?\d+(:-?\d+)*$/', $val))
|
||||
return array_map('intVal', explode(':', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private static function checkIdListUnsigned(string $val) : array
|
||||
{
|
||||
if (preg_match('/^\d+(,\d+)*$/', $val))
|
||||
return array_map('intVal', explode(',', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private static function checkTextLine(string $val) : string
|
||||
{
|
||||
// trim non-printable chars
|
||||
return preg_replace(self::PATTERN_TEXT_LINE, '', $val);
|
||||
}
|
||||
|
||||
private static function checkTextBlob(string $val) : string
|
||||
{
|
||||
// trim non-printable chars
|
||||
return preg_replace(self::PATTERN_TEXT_BLOB, '', $val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class Util
|
||||
{
|
||||
@@ -175,9 +77,7 @@ abstract class Util
|
||||
|
||||
public static $guideratingString = " $(document).ready(function() {\n $('#guiderating').append(GetStars(%.10F, %s, %u, %u));\n });";
|
||||
|
||||
public static $expansionString = array( // 3 & 4 unused .. obviously
|
||||
null, 'bc', 'wotlk', 'cata', 'mop'
|
||||
);
|
||||
public static $expansionString = [null, 'bc', 'wotlk'];
|
||||
|
||||
public static $tcEncoding = '0zMcmVokRsaqbdrfwihuGINALpTjnyxtgevElBCDFHJKOPQSUWXYZ123456789';
|
||||
private static $notes = [];
|
||||
@@ -191,7 +91,7 @@ abstract class Util
|
||||
{
|
||||
$notes = [];
|
||||
$severity = LOG_LEVEL_INFO;
|
||||
foreach (self::$notes as [$note, $uGroup, $level])
|
||||
foreach (self::$notes as $k => [$note, $uGroup, $level])
|
||||
{
|
||||
if ($uGroup && !User::isInGroup($uGroup))
|
||||
continue;
|
||||
@@ -200,6 +100,7 @@ abstract class Util
|
||||
$severity = $level;
|
||||
|
||||
$notes[] = $note;
|
||||
unset(self::$notes[$k]);
|
||||
}
|
||||
|
||||
return [$notes, $severity];
|
||||
@@ -309,14 +210,14 @@ abstract class Util
|
||||
if ($ms)
|
||||
return $ms."\u{00A0}".Lang::timeUnits('ab', 7);
|
||||
|
||||
return '0 '.Lang::timeUnits('ab', 6);
|
||||
return "0\u{00A0}".Lang::timeUnits('ab', 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
$_ = $d + $h / 24;
|
||||
if ($_ > 1 && !($_ % 365)) // whole years
|
||||
return round(($d + $h / 24) / 364, 2)."\u{00A0}".Lang::timeUnits($d / 364 == 1 && !$h ? 'sg' : 'pl', 0);
|
||||
if ($_ > 1 && !($_ % 30)) // whole month
|
||||
return round(($d + $h / 24) / 365, 2)."\u{00A0}".Lang::timeUnits($d / 365 == 1 && !$h ? 'sg' : 'pl', 0);
|
||||
if ($_ > 1 && !($_ % 30)) // whole months
|
||||
return round(($d + $h / 24) / 30, 2)."\u{00A0}".Lang::timeUnits($d / 30 == 1 && !$h ? 'sg' : 'pl', 1);
|
||||
if ($_ > 1 && !($_ % 7)) // whole weeks
|
||||
return round(($d + $h / 24) / 7, 2)."\u{00A0}".Lang::timeUnits($d / 7 == 1 && !$h ? 'sg' : 'pl', 2);
|
||||
@@ -329,15 +230,15 @@ abstract class Util
|
||||
if ($s)
|
||||
return round($s + $ms / 1000, 2)."\u{00A0}".Lang::timeUnits($s == 1 && !$ms ? 'sg' : 'pl', 6);
|
||||
if ($ms)
|
||||
return $ms." ".Lang::timeUnits($ms == 1 ? 'sg' : 'pl', 7);
|
||||
return $ms."\u{00A0}".Lang::timeUnits($ms == 1 ? 'sg' : 'pl', 7);
|
||||
|
||||
return '0 '.Lang::timeUnits('pl', 6);
|
||||
return "0\u{00A0}".Lang::timeUnits('pl', 6);
|
||||
}
|
||||
}
|
||||
|
||||
public static function formatTimeDiff(int $sec) : string
|
||||
{
|
||||
$delta = time() - $sec;
|
||||
$delta = abs(time() - $sec);
|
||||
|
||||
[, $s, $m, $h, $d] = self::parseTime($delta * 1000);
|
||||
|
||||
@@ -476,21 +377,23 @@ abstract class Util
|
||||
));
|
||||
}
|
||||
|
||||
public static function defStatic($data)
|
||||
public static function defStatic(array|string $data) : array|string
|
||||
{
|
||||
if (is_array($data))
|
||||
{
|
||||
foreach ($data as &$v)
|
||||
if ($v)
|
||||
$v = self::defStatic($v);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return strtr($data, array(
|
||||
'<script' => '<scr"+"ipt',
|
||||
'script>' => 'scr"+"ipt>',
|
||||
'HOST_URL' => Cfg::get('HOST_URL'),
|
||||
'STATIC_URL' => Cfg::get('STATIC_URL')
|
||||
'STATIC_URL' => Cfg::get('STATIC_URL'),
|
||||
'NAME' => Cfg::get('NAME'),
|
||||
'NAME_SHORT' => Cfg::get('NAME_SHORT'),
|
||||
'CONTACT_EMAIL' => Cfg::get('CONTACT_EMAIL')
|
||||
));
|
||||
}
|
||||
|
||||
@@ -558,7 +461,7 @@ abstract class Util
|
||||
$first = mb_substr($str, 0, 1);
|
||||
$rest = mb_substr($str, 1);
|
||||
|
||||
return mb_strtoupper($first).mb_strtolower($rest);
|
||||
return mb_strtoupper($first).$rest;
|
||||
}
|
||||
|
||||
public static function ucWords(string $str) : string
|
||||
@@ -864,15 +767,6 @@ abstract class Util
|
||||
return DB::Aowow()->query('INSERT IGNORE INTO ?_account_reputation (?#) VALUES (?a)', array_keys($x), array_values($x));
|
||||
}
|
||||
|
||||
public static function sendNoCacheHeader()
|
||||
{
|
||||
header('Expires: Sat, 01 Jan 2000 01:00:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
}
|
||||
|
||||
public static function toJSON($data, $forceFlags = 0)
|
||||
{
|
||||
$flags = $forceFlags ?: (JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE);
|
||||
@@ -884,7 +778,7 @@ abstract class Util
|
||||
|
||||
// handle strings prefixed with $ as js-variables
|
||||
// literal: match everything (lazy) between first pair of unescaped double quotes. First character must be $.
|
||||
$json = preg_replace_callback('/(?<!\\\\)"\$(.+?)(?<!\\\\)"/i', function($m) { return str_replace('\"', '"', $m[1]); }, $json);
|
||||
$json = preg_replace_callback('/(?<!\\\\)"\$(.+?)(?<!\\\\)"/i', fn($m) => str_replace('\"', '"', $m[1]), $json);
|
||||
|
||||
return $json;
|
||||
}
|
||||
@@ -1330,9 +1224,9 @@ abstract class Util
|
||||
'Reply-To: ' . Cfg::get('CONTACT_EMAIL') . "\n" .
|
||||
'X-Mailer: PHP/' . phpversion();
|
||||
|
||||
if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO)
|
||||
{
|
||||
$_SESSION['debug-mail'] = $email . "\n\n" . $subject . "\n\n" . $body;
|
||||
Util::addNote("Redirected from Util::sendMail:\n\nTo: " . $email . "\n\nSubject: " . $subject . "\n\n" . $body, U_GROUP_DEV | U_GROUP_ADMIN, LOG_LEVEL_INFO);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
215
index.php
215
index.php
@@ -8,160 +8,75 @@ if (CLI)
|
||||
die("this script must not be run from CLI.\nto setup aowow use 'php aowow'\n");
|
||||
|
||||
|
||||
$altClass = '';
|
||||
switch ($pageCall)
|
||||
$pageCall = 'home'; // default to Homepage unless specified otherwise
|
||||
$pageParam = '';
|
||||
parse_str(parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY), $query);
|
||||
foreach ($query as $page => $param)
|
||||
{
|
||||
/* called by user */
|
||||
case '': // no parameter given -> MainPage
|
||||
$altClass = 'home';
|
||||
case 'home':
|
||||
case 'admin':
|
||||
case 'account': // account management [nyi]
|
||||
case 'achievement':
|
||||
case 'achievements':
|
||||
case 'areatrigger':
|
||||
case 'areatriggers':
|
||||
case 'arena-team':
|
||||
case 'arena-teams':
|
||||
case 'class':
|
||||
case 'classes':
|
||||
case 'currency':
|
||||
case 'currencies':
|
||||
case 'compare': // tool: item comparison
|
||||
case 'emote':
|
||||
case 'emotes':
|
||||
case 'enchantment':
|
||||
case 'enchantments':
|
||||
case 'event':
|
||||
case 'events':
|
||||
case 'faction':
|
||||
case 'factions':
|
||||
case 'guide':
|
||||
case 'guides':
|
||||
case 'guild':
|
||||
case 'guilds':
|
||||
case 'icon':
|
||||
case 'icons':
|
||||
case 'item':
|
||||
case 'items':
|
||||
case 'itemset':
|
||||
case 'itemsets':
|
||||
case 'maps': // tool: map listing
|
||||
case 'mail':
|
||||
case 'mails':
|
||||
case 'my-guides':
|
||||
if ($pageCall == 'my-guides')
|
||||
$altClass = 'guides';
|
||||
case 'npc':
|
||||
case 'npcs':
|
||||
case 'object':
|
||||
case 'objects':
|
||||
case 'pet':
|
||||
case 'pets':
|
||||
case 'petcalc': // tool: pet talent calculator
|
||||
if ($pageCall == 'petcalc')
|
||||
$altClass = 'talent';
|
||||
case 'profile': // character profiler [nyi]
|
||||
case 'profiles': // character profile listing [nyi]
|
||||
case 'profiler': // character profiler main page
|
||||
case 'quest':
|
||||
case 'quests':
|
||||
case 'race':
|
||||
case 'races':
|
||||
case 'screenshot': // prepare uploaded screenshots
|
||||
case 'search': // tool: searches
|
||||
case 'skill':
|
||||
case 'skills':
|
||||
case 'sound':
|
||||
case 'sounds':
|
||||
case 'spell':
|
||||
case 'spells':
|
||||
case 'talent': // tool: talent calculator
|
||||
case 'title':
|
||||
case 'titles':
|
||||
case 'user':
|
||||
case 'video':
|
||||
case 'zone':
|
||||
case 'zones':
|
||||
/* called by script */
|
||||
case 'data': // tool: dataset-loader
|
||||
case 'cookie': // lossless cookies and user settings
|
||||
case 'contactus':
|
||||
case 'comment':
|
||||
case 'edit': // guide editor: targeted by QQ fileuploader, detail-page article editor
|
||||
case 'get-description': // guide editor: shorten fulltext into description
|
||||
case 'filter': // pre-evaluate filter POST-data; sanitize and forward as GET-data
|
||||
case 'go-to-reply': // find page the reply is on and forward
|
||||
if ($pageCall == 'go-to-reply')
|
||||
$altClass = 'go-to-comment';
|
||||
case 'go-to-comment': // find page the comment is on and forward
|
||||
case 'locale': // subdomain-workaround, change the language
|
||||
$cleanName = str_replace(['-', '_'], '', ucFirst($altClass ?: $pageCall));
|
||||
try // can it be handled as ajax?
|
||||
{
|
||||
$out = '';
|
||||
$class = __NAMESPACE__.'\\'.'Ajax'.$cleanName;
|
||||
$ajax = new $class(explode('.', $pageParam));
|
||||
$page = preg_replace('/[^\w\-]/i', '', $page);
|
||||
|
||||
if ($ajax->handle($out))
|
||||
{
|
||||
Util::sendNoCacheHeader();
|
||||
$pageCall = Util::lower($page);
|
||||
$pageParam = $param ?? '';
|
||||
break; // only use first k/v-pair to determine page
|
||||
}
|
||||
|
||||
if ($ajax->doRedirect)
|
||||
header('Location: '.$out, true, 302);
|
||||
[$classMod, $file] = match (true)
|
||||
{
|
||||
// is search ajax
|
||||
isset($_GET['json']) => ['Json', $pageCall . '_json' ],
|
||||
isset($_GET['opensearch']) => ['Open', $pageCall . '_open' ],
|
||||
// is powered tooltip
|
||||
isset($_GET['power']) => ['Power', $pageCall . '_power' ],
|
||||
// is item data xml dump
|
||||
isset($_GET['xml']) => ['Xml', $pageCall . '_xml' ],
|
||||
// is community content feed
|
||||
isset($_GET['rss']) => ['Rss', $pageCall . '_rss' ],
|
||||
// is sounds playlist
|
||||
isset($_GET['playlist']) => ['Playlist', $pageCall . '_playlist'],
|
||||
// pageParam can be sub page
|
||||
(bool)preg_match('/^[a-z\-]+$/i', $pageParam) => [Util::ucFirst(strtr($pageParam, ['-' => ''])), Util::lower($pageParam)],
|
||||
// no pageParam or PageParam is param for BasePage
|
||||
default => ['Base', $pageCall ]
|
||||
};
|
||||
|
||||
// admin=X pages are mixed html and ajax on the same endpoint .. meh
|
||||
if ($pageCall == 'admin' && isset($_GET['action']) && preg_match('/^[a-z]+$/', $_GET['action']))
|
||||
{
|
||||
$classMod .= 'Action' . Util::ucFirst($_GET['action']);
|
||||
$file .= '_' . Util::lower($_GET['action']);
|
||||
}
|
||||
|
||||
try {
|
||||
$responder = new \StdClass;
|
||||
|
||||
// 1. try specialized response
|
||||
if (file_exists('endpoints/'.$pageCall.'/'.$file.'.php'))
|
||||
{
|
||||
require_once 'endpoints/'.$pageCall.'/'.$file.'.php';
|
||||
|
||||
$class = __NAMESPACE__.'\\' . Util::ucFirst(strtr($pageCall, ['-' => ''])).$classMod.'Response';
|
||||
$responder = new $class($pageParam);
|
||||
}
|
||||
// 2. try generalized response
|
||||
else if (file_exists('endpoints/'.$pageCall.'/'.$pageCall.'.php'))
|
||||
{
|
||||
require_once 'endpoints/'.$pageCall.'/'.$pageCall.'.php';
|
||||
|
||||
$class = __NAMESPACE__.'\\' . Util::ucFirst(strtr($pageCall, ['-' => ''])).'BaseResponse';
|
||||
$responder = new $class($pageParam);
|
||||
}
|
||||
// 3. throw .. your hands in the air and give up
|
||||
if (!is_callable([$responder, 'process']))
|
||||
throw new \Exception('request handler '.$pageCall.'::'.$classMod.'('.$pageParam.') not found');
|
||||
|
||||
$responder->process();
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
if (isset($_GET['json']) || isset($_GET['opensearch']) || isset($_GET['power']) || isset($_GET['xml']) || isset($_GET['rss']))
|
||||
(new TextResponse($pageParam))->generate404();
|
||||
else
|
||||
{
|
||||
header($ajax->getContentType());
|
||||
die($out);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new \Exception('not handled as ajax');
|
||||
}
|
||||
catch (\Exception $e) // no, apparently not..
|
||||
{
|
||||
$class = __NAMESPACE__.'\\'.$cleanName.'Page';
|
||||
$classInstance = new $class($pageCall, $pageParam);
|
||||
|
||||
if (is_callable([$classInstance, 'display']))
|
||||
$classInstance->display();
|
||||
else if (isset($_GET['power']))
|
||||
die('$WowheadPower.register(0, '.Lang::getLocale()->value.', {})');
|
||||
else // in conjunction with a proper rewriteRule in .htaccess...
|
||||
(new GenericPage($pageCall))->error();
|
||||
}
|
||||
|
||||
break;
|
||||
/* other pages */
|
||||
case 'whats-new':
|
||||
case 'searchplugins':
|
||||
case 'searchbox':
|
||||
case 'tooltips':
|
||||
case 'help':
|
||||
case 'faq':
|
||||
case 'aboutus':
|
||||
case 'reputation':
|
||||
case 'privilege':
|
||||
case 'privileges':
|
||||
case 'top-users':
|
||||
(new MorePage($pageCall, $pageParam))->display();
|
||||
break;
|
||||
case 'latest-additions':
|
||||
case 'latest-comments':
|
||||
case 'latest-screenshots':
|
||||
case 'latest-videos':
|
||||
case 'unrated-comments':
|
||||
case 'missing-screenshots':
|
||||
case 'most-comments':
|
||||
case 'random':
|
||||
(new UtilityPage($pageCall, $pageParam))->display();
|
||||
break;
|
||||
default: // unk parameter given -> ErrorPage
|
||||
if (isset($_GET['power']))
|
||||
die('$WowheadPower.register(0, '.Lang::getLocale()->value.', {})');
|
||||
else // in conjunction with a proper rewriteRule in .htaccess...
|
||||
(new GenericPage($pageCall))->error();
|
||||
break;
|
||||
(new TemplateResponse($pageParam))->generateError($pageCall);
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
6
setup/updates/1758578400_01.sql
Normal file
6
setup/updates/1758578400_01.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
DELETE FROM `aowow_config` WHERE `key` IN ('rep_req_ext_links', 'gtag_measurement_id');
|
||||
INSERT INTO `aowow_config` (`key`, `value`, `default`, `cat`, `flags`, `comment`) VALUES
|
||||
('rep_req_ext_links', 150, 150, 5, 129, 'required reputation to link to external sites'),
|
||||
('gtag_measurement_id', '', NULL, 6, 136, 'Enter your Google Tag measurement ID here to track site stats');
|
||||
|
||||
UPDATE `aowow_config` SET `key` = 'ua_measurement_key', `comment` = '[DEPRECATED ?] Enter your Google Universal Analytics key here to track site stats' WHERE `key` = 'analytics_user';
|
||||
180
static/css/consent.css
Normal file
180
static/css/consent.css
Normal file
@@ -0,0 +1,180 @@
|
||||
#consent-overlay .dark-filter.fade-in {
|
||||
animation-name: fade-in;
|
||||
animation-duration: 400ms;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
#consent-overlay .dark-filter.hide {
|
||||
display: none !important
|
||||
}
|
||||
|
||||
#consent-overlay .dark-filter {
|
||||
z-index: 2147483645;
|
||||
background: rgba(0,0,0,.5);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% { opacity: 0 }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
|
||||
#consent-overlay #banner {
|
||||
position: fixed;
|
||||
z-index: 2147483645;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background-color: #181818;
|
||||
max-height: 90%;
|
||||
min-height: 125px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
#consent-overlay #policy {
|
||||
margin: 1.25em 0 .625em 2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #policy-title {
|
||||
font-size: revert;
|
||||
line-height: 1.3;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 10px;
|
||||
color: #fff;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #policy-text {
|
||||
clear: both;
|
||||
text-align: left;
|
||||
line-height: 1.5;
|
||||
width: 50%;
|
||||
border-right: 1px solid #d8d8d8;
|
||||
padding-right: 1rem;
|
||||
padding-bottom: 1em
|
||||
}
|
||||
|
||||
#consent-overlay #banner #policy-text * {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #policy-text a {
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #policy-title,
|
||||
#consent-overlay #banner #policy-text {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#consent-overlay #banner .columns {
|
||||
width: 100%;
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
display: initial;
|
||||
margin-left: 4%;
|
||||
width: 82.6666666667%;
|
||||
}
|
||||
|
||||
#consent-overlay #banner .columns:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #accept-btn,
|
||||
#consent-overlay #banner #reject-all {
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
#consent-overlay .ggl-container {
|
||||
width: 45%;
|
||||
padding-left: 1rem;
|
||||
display: inline-block;
|
||||
float: none;
|
||||
}
|
||||
|
||||
#consent-overlay .ggl-container div,
|
||||
#consent-overlay #policy-text {
|
||||
border-color: #303030 !important;
|
||||
}
|
||||
|
||||
#consent-overlay .ggl-title {
|
||||
line-height: 1.7;
|
||||
color: #fff;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 0;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
#consent-overlay .ggl-text {
|
||||
margin-bottom: 10px;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #button-container {
|
||||
left: auto;
|
||||
right: 4%;
|
||||
margin-left: 0;
|
||||
min-height: 1px;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
width: 13.3333333333%;
|
||||
}
|
||||
|
||||
#consent-overlay .columns {
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #button-group {
|
||||
display: inline-block;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#consent-overlay #banner #button-group button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#consent-overlay #accept-btn,
|
||||
#consent-overlay #reject-all {
|
||||
margin-top: 1em;
|
||||
margin-right: 1em;
|
||||
outline-offset: 1px;
|
||||
min-width: 125px;
|
||||
height: auto;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
word-wrap: break-word;
|
||||
padding: 12px 10px;
|
||||
line-height: 1.2;
|
||||
width: 100%;
|
||||
background-color: #a71a19;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
text-decoration: none !important;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
transition: 75ms;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
#consent-overlay #accept-btn:hover,
|
||||
#consent-overlay #reject-all:hover {
|
||||
box-shadow: none;
|
||||
background-color: #da2020 !important;
|
||||
border-color: #da2020 !important;
|
||||
}
|
||||
10
static/js/consent.js
Normal file
10
static/js/consent.js
Normal file
@@ -0,0 +1,10 @@
|
||||
$(document).ready(function() {
|
||||
$WH.qs('#consent-overlay #accept-btn').onclick = function () {
|
||||
$WH.sc('consent', 1000, 1);
|
||||
$WH.ge('consent-overlay').style.display = 'none';
|
||||
};
|
||||
$WH.qs('#consent-overlay #reject-all').onclick = function () {
|
||||
$WH.sc('consent', 1000, 0);
|
||||
$WH.ge('consent-overlay').style.display = 'none';
|
||||
};
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php namespace Aowow; ?>
|
||||
|
||||
<?php
|
||||
if (!empty($this->contribute)):
|
||||
if ($this->contribute):
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
<div class="text">
|
||||
@@ -11,7 +11,7 @@ if (!empty($this->contribute)):
|
||||
<div class="text" style="margin-right: 310px">
|
||||
<div class="tabbed-contents" style="clear: none">
|
||||
<?php
|
||||
$this->localizedBrick('contrib');
|
||||
$this->localizedBrick('contrib', ['coError' => $this->community['coError'], 'ssError' => $this->community['ssError'], 'viError' => $this->community['viError']]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php namespace Aowow; ?>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
<?php if (isset($this->region) && isset($this->realm)): ?>
|
||||
pr_setRegionRealm($WH.ge('fi').firstChild, '<?=$this->region; ?>', '<?=$this->realm; ?>');
|
||||
<?php if ($this->filterObj->values['ra']): ?>
|
||||
pr_onChangeRace();
|
||||
<?php
|
||||
endif;
|
||||
endif;
|
||||
|
||||
if ($this->filterObj->fiInit): // str: filter template (and init html form)
|
||||
echo " fi_init('".$this->filterObj->fiInit."');\n";
|
||||
elseif ($this->filterObj->fiType): // str: filter template (set without init)
|
||||
echo " var fi_type = '".$this->filterObj->fiType."'\n";
|
||||
endif;
|
||||
|
||||
if ($this->filterObj->fiSetCriteria):
|
||||
echo ' fi_setCriteria('.mb_substr(Util::toJSON(array_values($this->filterObj->fiSetCriteria)), 1, -1).");\n";
|
||||
endif;
|
||||
if ($this->filterObj->fiSetWeights):
|
||||
/*
|
||||
nt: don't try to match provided weights on predefined weight sets (preselects preset from opt list and ..?)
|
||||
ids: weights are encoded as ids, not by their js name and need conversion before use
|
||||
stealth: the ub-selector (items filter) will not visually change (so what..?)
|
||||
*/
|
||||
echo ' fi_setWeights('.Util::toJSON($this->filterObj->fiSetWeights).", 0, 1, 1);\n";
|
||||
endif;
|
||||
if ($this->filterObj->fiExtraCols):
|
||||
echo ' fi_extraCols = '.Util::toJSON(array_values(array_unique($this->filterObj->fiExtraCols))).";\n";
|
||||
endif;
|
||||
?>
|
||||
//]]></script>
|
||||
@@ -1,23 +1,27 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
use \Aowow\Lang;
|
||||
?>
|
||||
|
||||
<div class="footer">
|
||||
<?php
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE) && ($this->time || isset($this->mysql) || $this->isCached)):
|
||||
if ($this->pageStats):
|
||||
echo " <table style=\"margin:auto;\">\n";
|
||||
|
||||
if (isset($this->mysql)):
|
||||
echo ' <tr><td style="text-align:left;">'.Lang::main('numSQL') .'</td><td>'.$this->mysql['count']."</td></tr>\n";
|
||||
echo ' <tr><td style="text-align:left;">'.Lang::main('timeSQL').'</td><td>'.Util::formatTime($this->mysql['time'] * 1000, true)."</td></tr>\n";
|
||||
if ($x = $this->pageStats['sql']):
|
||||
echo ' <tr><td style="text-align:left;">'.Lang::main('numSQL') .'</td><td>'.$x['count']."</td></tr>\n";
|
||||
echo ' <tr><td style="text-align:left;">'.Lang::main('timeSQL').'</td><td>'.$x['time']."</td></tr>\n";
|
||||
endif;
|
||||
|
||||
if ($this->time):
|
||||
echo ' <tr><td style="text-align:left;">Page generated in</td><td>'.Util::formatTime($this->time * 1000, true)."</td></tr>\n";
|
||||
if ($x = $this->pageStats['time']):
|
||||
echo ' <tr><td style="text-align:left;">Page generated in</td><td>'.$x."</td></tr>\n";
|
||||
endif;
|
||||
|
||||
if ($this->cacheLoaded && $this->cacheLoaded[0] == CACHE_MODE_FILECACHE):
|
||||
echo " <tr><td style=\"text-align:left;\">reloaded from filecache</td><td>created".Lang::main('colon').date(Lang::main('dateFmtLong'), $this->cacheLoaded[1])."</td></tr>\n";
|
||||
elseif ($this->cacheLoaded && $this->cacheLoaded[0] == CACHE_MODE_MEMCACHED):
|
||||
echo " <tr><td style=\"text-align:left;\">reloaded from memcached</td><td>created".Lang::main('colon').date(Lang::main('dateFmtLong'), $this->cacheLoaded[1])."</td></tr>\n";
|
||||
if ($this->pageStats['cache'] && $this->pageStats['cache'][0] == CACHE_MODE_FILECACHE):
|
||||
echo " <tr><td style=\"text-align:left;\">Stored in filecache</td><td>".$this->pageStats['cache'][1]."</td></tr>\n";
|
||||
elseif ($this->pageStats['cache'] && $this->pageStats['cache'][0] == CACHE_MODE_MEMCACHED):
|
||||
echo " <tr><td style=\"text-align:left;\">Stored in Memcached</td><td>".$this->pageStats['cache'][1]."</td></tr>\n";
|
||||
endif;
|
||||
|
||||
echo " </table>\n";
|
||||
@@ -33,15 +37,13 @@ endif;
|
||||
<div id="noscript-text"><?=Lang::main('noJScript'); ?></div>
|
||||
</noscript>
|
||||
|
||||
<script type="text/javascript">DomContentLoaded.now()</script>
|
||||
<?php
|
||||
if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN)):
|
||||
?>
|
||||
<?=$this->localizedBrickIf($this->consentFooter, 'consent'); ?>
|
||||
|
||||
<?php if ($this->dbProfiles): ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.open("/", "SqlLog", "width=1800,height=200,top=100,left=100,status=no,location=no,toolbar=no,menubar=no").document.write('<?=DB::getProfiles();?>');
|
||||
window.open("/", "SqlLog", "width=1800,height=200,top=100,left=100,status=no,location=no,toolbar=no,menubar=no")?.document?.write('<?=$this->dbProfiles;?>');
|
||||
</script>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,61 +1,49 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
<title><?=Util::htmlEscape(implode(' - ', $this->title)); ?></title>
|
||||
use \Aowow\Lang;
|
||||
?>
|
||||
|
||||
<title><?=$this->concat('title', ' - '); ?></title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="SHORTCUT ICON" href="<?=Cfg::get('STATIC_URL'); ?>/images/logos/favicon.ico" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="<?=Cfg::get('STATIC_URL'); ?>/download/searchplugins/aowow.xml" title="Aowow" />
|
||||
<?php if (isset($this->rss)): ?>
|
||||
<link rel="alternate" type="application/rss+xml" title="<?=Util::htmlEscape(implode(' - ', $this->title)); ?>" href="<?=$this->rss; ?>"/>
|
||||
<?php endif;
|
||||
foreach ($this->css as [$type, $css]):
|
||||
if ($type == SC_CSS_FILE):
|
||||
echo ' <link rel="stylesheet" type="text/css" href="'.$css."\" />\n";
|
||||
elseif ($type == SC_CSS_STRING):
|
||||
echo ' <style type="text/css">'.$css."</style>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<link rel="SHORTCUT ICON" href="<?=$this->gStaticUrl; ?>/images/logos/favicon.ico" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="<?=$this->gStaticUrl; ?>/download/searchplugins/aowow.xml" title="<?=Lang::main('search');?>" />
|
||||
<?=$this->renderArray('css', 4); ?>
|
||||
<script type="text/javascript">
|
||||
var g_serverTime = new Date('<?=date(Util::$dateFormatInternal); ?>');
|
||||
var g_staticUrl = "<?=Cfg::get('STATIC_URL'); ?>";
|
||||
var g_host = "<?=Cfg::get('HOST_URL'); ?>";
|
||||
var g_serverTime = <?=$this->gServerTime; ?>;
|
||||
var g_staticUrl = "<?=$this->gStaticUrl; ?>";
|
||||
var g_host = "<?=$this->gHost; ?>";
|
||||
<?php
|
||||
if ($this->gDataKey):
|
||||
echo " var g_dataKey = '".$_SESSION['dataKey']."'\n";
|
||||
endif;
|
||||
?>
|
||||
</script>
|
||||
<?php
|
||||
foreach ($this->js as [$type, $js]):
|
||||
if ($type == SC_JS_FILE):
|
||||
echo ' <script type="text/javascript" src="'.$js."\"></script>\n";
|
||||
elseif ($type == SC_JS_STRING):
|
||||
echo ' <script type="text/javascript">'.$js."</script>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<?=$this->renderArray('js', 4); ?>
|
||||
<script type="text/javascript">
|
||||
var g_user = <?=Util::toJSON($this->gUser, JSON_UNESCAPED_UNICODE); ?>;
|
||||
var g_user = <?=$this->json($this->user::getUserGlobal()); ?>;
|
||||
<?php
|
||||
if ($this->gFavorites):
|
||||
echo " g_favorites = ".Util::toJSON($this->gFavorites).";\n";
|
||||
if ($fav = $this->user::getFavorites()):
|
||||
echo " g_favorites = ".$this->json($fav).";\n";
|
||||
endif;
|
||||
?>
|
||||
</script>
|
||||
|
||||
<?php
|
||||
if (Cfg::get('ANALYTICS_USER')):
|
||||
?>
|
||||
<?php if ($this->analyticsTag): ?>
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=<?=$this->analyticsTag; ?>"></script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', '<?=Cfg::get('ANALYTICS_USER'); ?>', 'auto');
|
||||
ga('send', 'pageview');
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', '<?=$this->analyticsTag; ?>');
|
||||
</script>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
if ($this->rss):
|
||||
?>
|
||||
<link rel="alternate" type="application/rss+xml" title="<?=$this->concat('title', ' - '); ?>" href="<?=$this->rss; ?>"/>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<?php
|
||||
if (!empty($this->headIcons)):
|
||||
if ($this->headIcons):
|
||||
foreach ($this->headIcons as $k => $v):
|
||||
echo '<div id="h1-icon-'.$k."\" class=\"h1-icon\"></div>\n";
|
||||
endforeach;
|
||||
@@ -9,7 +11,7 @@ if (!empty($this->headIcons)):
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
<?php
|
||||
foreach ($this->headIcons as $k => $v):
|
||||
echo "\$WH.ge('h1-icon-".$k."').appendChild(Icon.create('".Util::jsEscape($v)."', 1));\n";
|
||||
echo "\$WH.ge('h1-icon-".$k."').appendChild(Icon.create('".$this->escJS($v)."', 1));\n";
|
||||
endforeach;
|
||||
?>
|
||||
//]]></script>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<?php namespace Aowow; ?>
|
||||
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<?php $this->brick('head'); ?>
|
||||
</head>
|
||||
|
||||
<body<?=(User::isPremium() ? ' class="premium-logo"' : null); ?>>
|
||||
<body<?=($this->user::isPremium() ? ' class="premium-logo"' : ''); ?>>
|
||||
<div id="layers"></div>
|
||||
<?php if ($this->headerLogo): ?>
|
||||
<style type="text/css">
|
||||
@@ -21,18 +22,18 @@
|
||||
<div class="header" id="header">
|
||||
<div id="header-logo">
|
||||
<a class="header-logo" href="."></a>
|
||||
<h1><?=Util::htmlEscape($this->name); ?></h1>
|
||||
<h1><?=$this->concat('title', ' - '); ?></h1>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wrapper" class="wrapper">
|
||||
<div class="toplinks linklist"><?php $this->brick('headerMenu'); ?></div>
|
||||
<div class="toptabs" id="toptabs"></div>
|
||||
<div class="topbar" id="topbar">
|
||||
<div class="topbar-search"><form action="."><a href="javascript:;"></a><input name="search" size="35" id="livesearch-generic" value="<?=Util::htmlEscape($this->search ?? ''); ?>" /></form></div>
|
||||
<div class="topbar-search"><form action="."><a href="javascript:;"></a><input name="search" size="35" id="livesearch-generic" value="<?=$this->search; ?>" /></form></div>
|
||||
<div class="topbar-browse" id="topbar-browse"></div>
|
||||
<div class="topbar-buttons" id="topbar-buttons"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
<?=$this->writeGlobalVars(); ?>
|
||||
<?=$this->renderGlobalVars(12); ?>
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
use \Aowow\Lang;
|
||||
?>
|
||||
|
||||
<?php
|
||||
if (User::isLoggedIn()):
|
||||
if ($this->user::isLoggedIn()):
|
||||
echo '<span id="toplinks-favorites"><a class="hassubmenu"></a>|</span>';
|
||||
echo '<a id="toplinks-user">'.User::$username.'</a>';
|
||||
echo '<span id="toplinks-rep" title="'.Lang::main('reputationTip').'">(<a href="?reputation">'.User::getReputation().'</a>)</span>';
|
||||
echo '<a id="toplinks-user">'.$this->user::$username.'</a>';
|
||||
echo '<span id="toplinks-rep" title="'.Lang::main('reputationTip').'">(<a href="?reputation">'.$this->user::getReputation().'</a>)</span>';
|
||||
else:
|
||||
echo '<a href="?account=signin">'.Lang::main('signIn').'</a>';
|
||||
endif;
|
||||
|
||||
16
template/bricks/inputbox-status.tpl.php
Normal file
16
template/bricks/inputbox-status.tpl.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
use \Aowow\Lang;
|
||||
?>
|
||||
<div class="pad3"></div>
|
||||
|
||||
<div class="inputbox">
|
||||
<h1><?=$head ?? ''; ?></h1>
|
||||
<div id="inputbox-error"><?=$error ?? ''; ?></div>
|
||||
<?php if ($message ?? ''): ?>
|
||||
<div style="text-align: center; font-size: 110%"><?=$message; ?></div>
|
||||
<?php else: ?>
|
||||
<div class="clear"></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -1,40 +1,40 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
<?php
|
||||
if ($this->contribute & CONTRIBUTE_CO):
|
||||
echo " var lv_comments = ".Util::toJSON($this->community['co']).";\n";
|
||||
echo " var lv_comments = ".$this->community['co'].";\n";
|
||||
endif;
|
||||
if ($this->contribute & CONTRIBUTE_SS):
|
||||
|
||||
echo " var lv_screenshots = ".Util::toJSON($this->community['ss']).";\n";
|
||||
echo " var lv_screenshots = ".$this->community['ss'].";\n";
|
||||
endif;
|
||||
if ($this->contribute & CONTRIBUTE_VI):
|
||||
echo " var lv_videos = ".Util::toJSON($this->community['vi']).";\n";
|
||||
echo " var lv_videos = ".$this->community['vi'].";\n";
|
||||
endif;
|
||||
|
||||
if (!empty($this->gPageInfo)):
|
||||
echo " var g_pageInfo = ".Util::toJSON($this->gPageInfo).";\n";
|
||||
if ($this->gPageInfo):
|
||||
echo " var g_pageInfo = ".$this->json('gPageInfo').";\n";
|
||||
|
||||
// only used by item.php
|
||||
if (User::isLoggedIn() && isset($this->redButtons[BUTTON_EQUIP])):
|
||||
echo " DomContentLoaded.addEvent(function() { pr_addEquipButton('equip-pinned-button', ".$this->typeId."); });\n";
|
||||
// set by ItemBaseEndpoint
|
||||
if ($this->user::isLoggedIn() && !empty($this->redButtons[BUTTON_EQUIP])):
|
||||
echo " \$(document).ready(function() { pr_addEquipButton('equip-pinned-button', ".$this->typeId."); });\n";
|
||||
endif;
|
||||
endif;
|
||||
|
||||
if (!empty($this->pageTemplate)):
|
||||
if (Lang::getLocale()->value && $this->pageTemplate['pageName'] != 'home'):
|
||||
echo " Locale.set(".Lang::getLocale()->value.");\n";
|
||||
if ($this->pageTemplate):
|
||||
if ($this->locale->value && $this->pageTemplate['pageName'] != 'home'):
|
||||
echo " Locale.set(".$this->locale->value.");\n";
|
||||
endif;
|
||||
echo " PageTemplate.set(".$this->json('pageTemplate').");\n";
|
||||
endif;
|
||||
|
||||
echo " PageTemplate.set(".Util::toJSON($this->pageTemplate).");\n";
|
||||
echo " PageTemplate.init();\n";
|
||||
endif;
|
||||
|
||||
if (isset($fiQuery) && count($fiMenuItem) > 1 && array_slice($fiMenuItem, 0, 2) == [1, 5]):
|
||||
echo " \$(document).ready(function(){ Menu.modifyUrl(Menu.findItem(mn_path, ".Util::toJSON($fiMenuItem)."), { filter: '".$this->jsEscape($fiQuery)."'}, { onAppendCollision: fi_mergeFilterParams }) });\n";
|
||||
echo " \$(document).ready(function(){ Menu.modifyUrl(Menu.findItem(mn_path, ".$this->json($fiMenuItem)."), { filter: '".$this->escJS($fiQuery)."'}, { onAppendCollision: fi_mergeFilterParams }) });\n";
|
||||
elseif (isset($fiQuery)):
|
||||
echo " Menu.modifyUrl(Menu.findItem(mn_database, ".Util::toJSON($fiMenuItem)."), { filter: '+=".Util::jsEscape($fiQuery)."' }, { onAppendCollision: fi_mergeFilterParams, onAppendEmpty: fi_setFilterParams, menuUrl: Menu.getItemUrl(Menu.findItem(mn_database, ".Util::toJSON($fiMenuItem).")) });\n";
|
||||
echo " Menu.modifyUrl(Menu.findItem(mn_database, ".$this->json($fiMenuItem)."), { filter: '+=".$this->escJS($fiQuery)."' }, { onAppendCollision: fi_mergeFilterParams, onAppendEmpty: fi_setFilterParams, menuUrl: Menu.getItemUrl(Menu.findItem(mn_database, ".$this->json($fiMenuItem).")) });\n";
|
||||
endif;
|
||||
?>
|
||||
//]]></script>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
use \Aowow\Lang;
|
||||
?>
|
||||
|
||||
<?php
|
||||
// link to wowhead
|
||||
@@ -18,7 +22,7 @@ endif;
|
||||
// ingame-links/markdown/ect
|
||||
if (isset($this->redButtons[BUTTON_LINKS])):
|
||||
if ($b = $this->redButtons[BUTTON_LINKS]):
|
||||
echo '<a href="javascript:;" id="open-links-button" class="button-red" onclick="this.blur(); Links.show('.strtr(Util::toJSON($b, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE | JSON_HEX_APOS), ['"' => "'"]).');"><em><b><i>'.Lang::main('links').'</i></b><span>'.Lang::main('links').'</span></em></a>';
|
||||
echo '<a href="javascript:;" id="open-links-button" class="button-red" onclick="this.blur(); Links.show('.strtr($this->json($b, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE | JSON_HEX_APOS), ['"' => "'"]).');"><em><b><i>'.Lang::main('links').'</i></b><span>'.Lang::main('links').'</span></em></a>';
|
||||
else:
|
||||
echo '<a href="javascript:;" id="open-links-button" class="button-red button-red-disabled"><em><b><i>'.Lang::main('links').'</i></b><span>'.Lang::main('links').'</span></em></a>';
|
||||
endif;
|
||||
@@ -27,7 +31,7 @@ endif;
|
||||
// view in 3D
|
||||
if (isset($this->redButtons[BUTTON_VIEW3D])):
|
||||
if ($b = $this->redButtons[BUTTON_VIEW3D]): // json_encode puts property names in brackets wich is not cool with inline javascript
|
||||
echo '<a href="javascript:;" id="view3D-button" class="button-red" onclick="this.blur(); ModelViewer.show('.strtr(Util::toJSON($b, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE | JSON_HEX_APOS), ['"' => "'"]).')"><em><b><i>'.Lang::main('view3D').'</i></b><span>'.Lang::main('view3D').'</span></em></a>';
|
||||
echo '<a href="javascript:;" id="view3D-button" class="button-red" onclick="this.blur(); ModelViewer.show('.strtr($this->json($b, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE | JSON_HEX_APOS), ['"' => "'"]).')"><em><b><i>'.Lang::main('view3D').'</i></b><span>'.Lang::main('view3D').'</span></em></a>';
|
||||
else:
|
||||
echo '<a href="javascript:;" id="view3D-button" class="button-red button-red-disabled"><em><b><i>'.Lang::main('view3D').'</i></b><span>'.Lang::main('view3D').'</span></em></a>';
|
||||
endif;
|
||||
@@ -36,7 +40,7 @@ endif;
|
||||
// item comparison tool
|
||||
if (isset($this->redButtons[BUTTON_COMPARE])):
|
||||
if ($b = $this->redButtons[BUTTON_COMPARE]):
|
||||
echo '<a href="javascript:;" class="button-red" onclick="this.blur(); su_addToSaved(\''.(isset($b['eqList']) ? $b['eqList'] : $this->typeId).'\', '.(isset($b['qty']) ? $b['qty'] : 1).')"><em><b><i>'.Lang::main('compare').'</i></b><span>'.Lang::main('compare').'</span></em></a>';
|
||||
echo '<a href="javascript:;" class="button-red" onclick="this.blur(); su_addToSaved(\''.($b['eqList'] ?? $this->typeId).'\', '.($b['qty'] ?? 1).')"><em><b><i>'.Lang::main('compare').'</i></b><span>'.Lang::main('compare').'</span></em></a>';
|
||||
else:
|
||||
echo '<a href="javascript:;" class="button-red button-red-disabled"><em><b><i>'.Lang::main('compare').'</i></b><span>'.Lang::main('compare').'</span></em></a>';
|
||||
endif;
|
||||
|
||||
25
template/localized/consent_0.tpl.php
Normal file
25
template/localized/consent_0.tpl.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="consent-overlay">
|
||||
<div class="dark-filter fade-in"></div>
|
||||
<div id="banner" tabindex="0">
|
||||
<div id="group-container" class="columns">
|
||||
<div id="policy">
|
||||
<h2 id="policy-title">Privacy Notice</h2>
|
||||
<div id="policy-text">
|
||||
This website uses Cookies and Local Storage to manage your session and remember your user settings. We also use Google Analytics to collect anonymous usage statistics and improve our services. You may choose to opt out of Google Analytics tracking, but session management and user settings storage are required for the website to operate. For more details, please review our Privacy Policy.
|
||||
</div>
|
||||
<div class="ggl-container">
|
||||
<h3 class="ggl-title">Google Tag Manager:</h3>
|
||||
<div class="ggl-text">
|
||||
Google Tag Manager is used to collect anonymous usage data to improve website performance and user experience. No personally identifiable information is stored or shared.<br /><br /><a href="https://policies.google.com/technologies/partner-sites" target="_blank">Google Privacy Policy and Terms of Use</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="button-container" class="columns">
|
||||
<div id="button-group">
|
||||
<button id="accept-btn">Accept</button>
|
||||
<button id="reject-all">Reject</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
25
template/localized/consent_2.tpl.php
Normal file
25
template/localized/consent_2.tpl.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="consent-overlay">
|
||||
<div class="dark-filter fade-in"></div>
|
||||
<div id="banner" tabindex="0">
|
||||
<div id="group-container" class="columns">
|
||||
<div id="policy">
|
||||
<h2 id="policy-title">Avis de confidentialité</h2>
|
||||
<div id="policy-text">
|
||||
Ce site utilise des cookies et le stockage local pour gérer votre session et mémoriser vos paramètres utilisateur. Nous utilisons également Google Analytics pour collecter des statistiques d'utilisation anonymes et améliorer nos services. Vous pouvez choisir de refuser le suivi Google Analytics, mais la gestion de session et le stockage des paramètres utilisateur sont nécessaires au fonctionnement du site. Pour plus de détails, veuillez consulter notre politique de confidentialité.
|
||||
</div>
|
||||
<div class="ggl-container">
|
||||
<h3 class="ggl-title">Google Tag Manager :</h3>
|
||||
<div class="ggl-text">
|
||||
Google Tag Manager est utilisé pour collecter des données d'utilisation anonymes afin d'améliorer les performances et l'expérience utilisateur du site. Aucune information personnellement identifiable n'est stockée ou partagée.<br /><br /><a href="https://policies.google.com/technologies/partner-sites" target="_blank">Politique de confidentialité et conditions d'utilisation de Google</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="button-container" class="columns">
|
||||
<div id="button-group">
|
||||
<button id="accept-btn">Accepter</button>
|
||||
<button id="reject-all">Tout refuser</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
25
template/localized/consent_3.tpl.php
Normal file
25
template/localized/consent_3.tpl.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="consent-overlay">
|
||||
<div class="dark-filter fade-in"></div>
|
||||
<div id="banner" tabindex="0">
|
||||
<div id="group-container" class="columns">
|
||||
<div id="policy">
|
||||
<h2 id="policy-title">Datenschutzhinweis</h2>
|
||||
<div id="policy-text">
|
||||
Diese Website verwendet Cookies und lokalen Speicher, um Ihre Sitzung zu verwalten und Ihre Benutzereinstellungen zu speichern. Wir verwenden außerdem Google Analytics, um anonyme Nutzungsstatistiken zu sammeln und unsere Dienste zu verbessern. Sie können sich gegen das Tracking durch Google Analytics entscheiden, aber Sitzungsverwaltung und Speicherung der Benutzereinstellungen sind für den Betrieb der Website erforderlich. Weitere Informationen finden Sie in unserer Datenschutzerklärung.
|
||||
</div>
|
||||
<div class="ggl-container">
|
||||
<h3 class="ggl-title">Google Tag Manager:</h3>
|
||||
<div class="ggl-text">
|
||||
Der Google Tag Manager ermöglicht es uns anonyme Nutzungsdaten zu sammeln, um die Leistung und Benutzererfahrung der Website zu verbessern. Es werden keine personenbezogenen Daten gespeichert oder weitergegeben.<br /><br /><a href="https://policies.google.com/technologies/partner-sites" target="_blank">Datenschutzerklärung & Nutzungsbedingungen von Google</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="button-container" class="columns">
|
||||
<div id="button-group">
|
||||
<button id="accept-btn">Akzeptieren</button>
|
||||
<button id="reject-all">Ablehnen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
25
template/localized/consent_4.tpl.php
Normal file
25
template/localized/consent_4.tpl.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="consent-overlay">
|
||||
<div class="dark-filter fade-in"></div>
|
||||
<div id="banner" tabindex="0">
|
||||
<div id="group-container" class="columns">
|
||||
<div id="policy">
|
||||
<h2 id="policy-title">隐私声明</h2>
|
||||
<div id="policy-text">
|
||||
本网站使用Cookies和本地存储来管理您的会话并记住您的用户设置。我们还使用Google Analytics收集匿名使用统计数据,以改善我们的服务。您可以选择拒绝Google Analytics的跟踪,但会话管理和用户设置存储是网站运行所必需的。更多详情请查阅我们的隐私政策。
|
||||
</div>
|
||||
<div class="ggl-container">
|
||||
<h3 class="ggl-title">Google Tag Manager:</h3>
|
||||
<div class="ggl-text">
|
||||
Google Tag Manager用于收集匿名使用数据,以提升网站性能和用户体验。不存储或共享任何可识别个人身份的信息。<br /><br /><a href="https://policies.google.com/technologies/partner-sites" target="_blank">Google隐私政策和使用条款</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="button-container" class="columns">
|
||||
<div id="button-group">
|
||||
<button id="accept-btn">接受</button>
|
||||
<button id="reject-all">全部拒绝</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
25
template/localized/consent_6.tpl.php
Normal file
25
template/localized/consent_6.tpl.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="consent-overlay">
|
||||
<div class="dark-filter fade-in"></div>
|
||||
<div id="banner" tabindex="0">
|
||||
<div id="group-container" class="columns">
|
||||
<div id="policy">
|
||||
<h2 id="policy-title">Aviso de privacidad</h2>
|
||||
<div id="policy-text">
|
||||
Este sitio web utiliza Cookies y almacenamiento local para gestionar su sesión y recordar sus configuraciones de usuario. También utilizamos Google Analytics para recopilar estadísticas de uso anónimas y mejorar nuestros servicios. Puede optar por rechazar el seguimiento de Google Analytics, pero la gestión de la sesión y el almacenamiento de configuraciones de usuario son necesarios para el funcionamiento del sitio web. Para más detalles, consulte nuestra Política de Privacidad.
|
||||
</div>
|
||||
<div class="ggl-container">
|
||||
<h3 class="ggl-title">Google Tag Manager:</h3>
|
||||
<div class="ggl-text">
|
||||
Google Tag Manager se utiliza para recopilar datos de uso anónimos y mejorar el rendimiento y la experiencia del usuario del sitio web. No se almacena ni comparte información personal identificable.<br /><br /><a href="https://policies.google.com/technologies/partner-sites" target="_blank">Política de privacidad y términos de uso de Google</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="button-container" class="columns">
|
||||
<div id="button-group">
|
||||
<button id="accept-btn">Aceptar</button>
|
||||
<button id="reject-all">Rechazar todo</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
25
template/localized/consent_8.tpl.php
Normal file
25
template/localized/consent_8.tpl.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="consent-overlay">
|
||||
<div class="dark-filter fade-in"></div>
|
||||
<div id="banner" tabindex="0">
|
||||
<div id="group-container" class="columns">
|
||||
<div id="policy">
|
||||
<h2 id="policy-title">Уведомление о конфиденциальности</h2>
|
||||
<div id="policy-text">
|
||||
Этот сайт использует Cookies и локальное хранилище для управления вашей сессией и запоминания пользовательских настроек. Мы также используем Google Analytics для сбора анонимной статистики использования и улучшения наших сервисов. Вы можете отказаться от отслеживания Google Analytics, но управление сессией и хранение пользовательских настроек необходимы для работы сайта. Подробнее смотрите нашу Политику конфиденциальности.
|
||||
</div>
|
||||
<div class="ggl-container">
|
||||
<h3 class="ggl-title">Google Tag Manager:</h3>
|
||||
<div class="ggl-text">
|
||||
Google Tag Manager используется для сбора анонимных данных об использовании сайта, чтобы повысить производительность и удобство использования. Личные данные не сохраняются и не передаются третьим лицам.<br /><br /><a href="https://policies.google.com/technologies/partner-sites" target="_blank">Политика конфиденциальности и условия использования Google</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="button-container" class="columns">
|
||||
<div id="button-group">
|
||||
<button id="accept-btn">Принять</button>
|
||||
<button id="reject-all">Отклонить все</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<div id="tab-add-your-comment" style="display: none">
|
||||
Please keep the following in mind when posting a comment:
|
||||
@@ -9,9 +11,9 @@
|
||||
<li><div>You might want to proof-read your comments before posting them.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->coError ? ' <div class="msg-failure">'.$this->coError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $coError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$coError."</div>\n" : '';
|
||||
|
||||
if (User::canComment()):
|
||||
if ($this->user::canComment()):
|
||||
?>
|
||||
<form name="addcomment" action="?comment=add&type=<?=$this->type.'&typeid='.$this->typeId; ?>" method="post" onsubmit="return co_validateForm(this)">
|
||||
<div id="funcbox-generic"></div>
|
||||
@@ -25,7 +27,7 @@
|
||||
<div class="comment-edit-body"><textarea class="comment-editbox" rows="10" cols="40" name="commentbody" disabled="disabled"></textarea></div>
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>You are not logged in. Please <a href="?account=signin">log in</a> or <a href="?account=signup">register an account</a> to add your comment.</small>
|
||||
<?php
|
||||
@@ -41,9 +43,9 @@
|
||||
<li><div>Be sure to read the <a href="?help=screenshots-tips-tricks" target="_blank">tips & tricks</a> if you haven't before.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->ssError ? ' <div class="msg-failure">'.$this->ssError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $ssError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$ssError."</div>\n" : '';
|
||||
|
||||
if (User::canUploadScreenshot()):
|
||||
if ($this->user::canUploadScreenshot()):
|
||||
?>
|
||||
<form action="?screenshot=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return ss_validateForm(this)">
|
||||
<input type="file" name="screenshotfile" style="width: 35%"/><br />
|
||||
@@ -58,7 +60,7 @@
|
||||
<input type="file" name="screenshotfile" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>You are not signed in. Please <a href="?account=signin">sign in</a> to submit a screenshot.</small>
|
||||
<?php
|
||||
@@ -69,7 +71,9 @@
|
||||
<div id="tab-suggest-a-video" style="display: none">
|
||||
Simply type the URL of the video in the form below.
|
||||
<?php
|
||||
if (User::canSuggestVideo()):
|
||||
echo $viError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$viError."</div>\n" : '';
|
||||
|
||||
if ($this->user::canSuggestVideo()):
|
||||
?>
|
||||
<div class="pad2"></div>
|
||||
<form action="?video=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return vi_validateForm(this)">
|
||||
@@ -85,7 +89,7 @@
|
||||
<input type="text" name="videourl" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>You are not signed in. Please <a href="?account=signin">sign in</a> to submit a video.</small>
|
||||
<?php
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<div id="tab-add-your-comment" style="display: none">
|
||||
Gardez à l'esprit les points suivant avant de poster un commentaire :
|
||||
@@ -9,9 +11,9 @@
|
||||
<li><div>Il serait avisé de corriger vos fautes avant de soumettre vos commentaires.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->coError ? ' <div class="msg-failure">'.$this->coError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $coError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$coError."</div>\n" : '';
|
||||
|
||||
if (User::canComment()):
|
||||
if ($this->user::canComment()):
|
||||
?>
|
||||
<form name="addcomment" action="?comment=add&type=<?=$this->type.'&typeid='.$this->typeId; ?>" method="post" onsubmit="return co_validateForm(this)">
|
||||
<div id="funcbox-generic"></div>
|
||||
@@ -25,7 +27,7 @@
|
||||
<div class="comment-edit-body"><textarea class="comment-editbox" rows="10" cols="40" name="commentbody" disabled="disabled"></textarea></div>
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Vous n'êtes pas connecté(e). Veuillez vous <a href="?account=signin">connecter</a> ou vous <a href="?account=signup">inscrire</a> pour ajouter votre commentaire.</small>
|
||||
<?php
|
||||
@@ -41,9 +43,9 @@
|
||||
<li><div>Assurez-vous de lire les <a href="?help=screenshots-tips-tricks" target="_blank">trucs et astuces</a> si ce n'est pas déjà fait.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->ssError ? ' <div class="msg-failure">'.$this->ssError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $ssError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$ssError."</div>\n" : '';
|
||||
|
||||
if (User::canUploadScreenshot()):
|
||||
if ($this->user::canUploadScreenshot()):
|
||||
?>
|
||||
<form action="?screenshot=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return ss_validateForm(this)">
|
||||
<input type="file" name="screenshotfile" style="width: 35%"/><br />
|
||||
@@ -58,7 +60,7 @@
|
||||
<input type="file" name="screenshotfile" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Vous n'êtes pas connecté(e). Veuillez vous <a href="?account=signin">connecter</a> pour envoyer une capture d'écran.</small>
|
||||
<?php
|
||||
@@ -69,7 +71,9 @@
|
||||
<div id="tab-suggest-a-video" style="display: none">
|
||||
Entrez simplement l'URL du vidéo dans le formulaire ci-dessous.
|
||||
<?php
|
||||
if (User::canSuggestVideo()):
|
||||
echo $viError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$viError."</div>\n" : '';
|
||||
|
||||
if ($this->user::canSuggestVideo()):
|
||||
?>
|
||||
<div class="pad2"></div>
|
||||
<form action="?video=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return vi_validateForm(this)">
|
||||
@@ -85,7 +89,7 @@
|
||||
<input type="text" name="videourl" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Vous n'êtes pas connecté(e). Veuillez vous <a href="?account=signin">connecter</a> pour envoyer une vidéo.</small>
|
||||
<?php
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<div id="tab-add-your-comment" style="display: none">
|
||||
Denkt bitte an Folgendes, wenn Ihr einen Kommentar schreibt:
|
||||
@@ -9,9 +11,9 @@
|
||||
<li><div>Stellt Eure Fragen bitte in unseren <a href="?forums">Foren</a>, wenn Ihr eine schnellere Antwort wünscht.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->coError ? ' <div class="msg-failure">'.$this->coError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $coError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$coError."</div>\n" : '';
|
||||
|
||||
if (User::canComment()):
|
||||
if ($this->user::canComment()):
|
||||
?>
|
||||
<form name="addcomment" action="?comment=add&type=<?=$this->type.'&typeid='.$this->typeId; ?>" method="post" onsubmit="return co_validateForm(this)">
|
||||
<div id="funcbox-generic"></div>
|
||||
@@ -25,7 +27,7 @@
|
||||
<div class="comment-edit-body"><textarea class="comment-editbox" rows="10" cols="40" name="commentbody" disabled="disabled"></textarea></div>
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Ihr seid nicht angemeldet. Bitte <a href="?account=signin">meldet Euch an</a>, oder <a href="?account=signup">registriert Euch</a>, um einen Kommentar einzusenden.</small>
|
||||
<?php
|
||||
@@ -41,9 +43,9 @@
|
||||
<li><div>Lest Euch unbedingt die <a href="?help=screenshots-tips-tricks" target="_blank">Tipps & Tricks</a> durch, wenn nicht bereits geschehen.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->ssError ? ' <div class="msg-failure">'.$this->ssError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $ssError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$ssError."</div>\n" : '';
|
||||
|
||||
if (User::canUploadScreenshot()):
|
||||
if ($this->user::canUploadScreenshot()):
|
||||
?>
|
||||
<form action="?screenshot=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return ss_validateForm(this)">
|
||||
<input type="file" name="screenshotfile" style="width: 35%"/><br />
|
||||
@@ -58,7 +60,7 @@
|
||||
<input type="file" name="screenshotfile" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Ihr seid nicht angemeldet. Bitte <a href="?account=signin">meldet Euch an</a>, um einen Screenshot einzusenden.</small>
|
||||
<?php
|
||||
@@ -69,7 +71,9 @@
|
||||
<div id="tab-suggest-a-video" style="display: none">
|
||||
Gebt einfach die URL des Videos im folgenden Formular ein.
|
||||
<?php
|
||||
if (User::canSuggestVideo()):
|
||||
echo $viError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$viError."</div>\n" : '';
|
||||
|
||||
if ($this->user::canSuggestVideo()):
|
||||
?>
|
||||
<div class="pad2"></div>
|
||||
<form action="?video=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return vi_validateForm(this)">
|
||||
@@ -85,7 +89,7 @@
|
||||
<input type="text" name="videourl" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Ihr seid nicht angemeldet. Bitte <a href="?account=signin">meldet Euch an</a>, um ein Video vorzuschlagen.</small>
|
||||
<?php
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<div id="tab-add-your-comment" style="display: none">
|
||||
发表评论时请记住以下几点:
|
||||
@@ -9,15 +11,15 @@
|
||||
<li><div>你在发表前最好先预览下你的评论。</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->coError ? ' <div class="msg-failure">'.$this->coError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $coError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$coError."</div>\n" : '';
|
||||
|
||||
if (User::canComment()):
|
||||
if ($this->user::canComment()):
|
||||
?>
|
||||
<form name="addcomment" action="?comment=add&type=<?=$this->type.'&typeid='.$this->typeId; ?>" method="post" onsubmit="return co_validateForm(this)">
|
||||
<div id="funcbox-generic"></div>
|
||||
<script type="text/javascript">Listview.funcBox.coEditAppend($('#funcbox-generic'), {body: ''}, 1)</script>
|
||||
<div class="pad"></div>
|
||||
<input type="submit" value="Submit"></input>
|
||||
<input type="submit" value="提交"></input>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
@@ -25,7 +27,7 @@
|
||||
<div class="comment-edit-body"><textarea class="comment-editbox" rows="10" cols="40" name="commentbody" disabled="disabled"></textarea></div>
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>你尚未登录,请先<a href="?account=signin">登录</a>或<a href="?account=signup">注册一个账号</a> 以发表你的评论。</small>
|
||||
<?php
|
||||
@@ -41,14 +43,14 @@
|
||||
<li><div>请阅读我们的<a href="?help=screenshots-tips-tricks" target="_blank">提示和技巧</a>假如你还没看过的话。</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->ssError ? ' <div class="msg-failure">'.$this->ssError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $ssError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$ssError."</div>\n" : '';
|
||||
|
||||
if (User::canUploadScreenshot()):
|
||||
if ($this->user::canUploadScreenshot()):
|
||||
?>
|
||||
<form action="?screenshot=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return ss_validateForm(this)">
|
||||
<input type="file" name="screenshotfile" style="width: 35%"/><br />
|
||||
<div class="pad2"></div>
|
||||
<input type="submit" value="Submit" />
|
||||
<input type="submit" value="提交" />
|
||||
<div class="pad3"></div>
|
||||
<small class="q0">注意:你的截图将在审查后才会出现在站点上。</small>
|
||||
<?php
|
||||
@@ -58,7 +60,7 @@
|
||||
<input type="file" name="screenshotfile" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>你尚未登录,请先<a href="?account=signin">登录</a>以提交截图。</small>
|
||||
<?php
|
||||
@@ -67,17 +69,19 @@
|
||||
</form>
|
||||
</div>
|
||||
<div id="tab-suggest-a-video" style="display: none">
|
||||
Simply type the URL of the video in the form below.
|
||||
将视频URL输入下列表格即可。
|
||||
<?php
|
||||
if (User::canSuggestVideo()):
|
||||
echo $viError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$viError."</div>\n" : '';
|
||||
|
||||
if ($this->user::canSuggestVideo()):
|
||||
?>
|
||||
<div class="pad2"></div>
|
||||
<form action="?video=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return vi_validateForm(this)">
|
||||
<input type="text" name="videourl" style="width: 35%" /> <small>Supported: YouTube only</small>
|
||||
<input type="text" name="videourl" style="width: 35%" /> <small>支持:仅限 YouTube</small>
|
||||
<div class="pad2"></div>
|
||||
<input type="submit" value="Submit" />
|
||||
<input type="submit" value="提交" />
|
||||
<div class="pad3"></div>
|
||||
<small class="q0">Note: Your video will need to be approved before appearing on the site.</small>
|
||||
<small class="q0">说明:您的视频需通过审核才能在站点上显示。</small>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
@@ -85,9 +89,9 @@
|
||||
<input type="text" name="videourl" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>You are not signed in. Please <a href="?account=signin">sign in</a> to submit a video.</small>
|
||||
<small>你尚未登录,请先<a href="?account=signin">登录</a>以提交视频。</small>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<div id="tab-add-your-comment" style="display: none">
|
||||
Ten en cuenta lo siguiente cuando escribas un comentario:
|
||||
@@ -9,9 +11,9 @@
|
||||
<li><div>Deberías corregir tus comentarios antes de enviarlos.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->coError ? ' <div class="msg-failure">'.$this->coError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $coError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$coError."</div>\n" : '';
|
||||
|
||||
if (User::canComment()):
|
||||
if ($this->user::canComment()):
|
||||
?>
|
||||
<form name="addcomment" action="?comment=add&type=<?=$this->type.'&typeid='.$this->typeId; ?>" method="post" onsubmit="return co_validateForm(this)">
|
||||
<div id="funcbox-generic"></div>
|
||||
@@ -25,7 +27,7 @@
|
||||
<div class="comment-edit-body"><textarea class="comment-editbox" rows="10" cols="40" name="commentbody" disabled="disabled"></textarea></div>
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>No has iniciado sesión. Por favor <a href="?account=signin">entra a tu cuenta</a> o <a href="?account=signup">registra una cuenta</a> para añadir tu comentario.</small>
|
||||
<?php
|
||||
@@ -41,9 +43,9 @@
|
||||
<li><div>Asegurate de leer las <a href="?help=screenshots-tips-tricks" target="_blank">sugerencias y trucos</a> si no lo has hecho antes.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->ssError ? ' <div class="msg-failure">'.$this->ssError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $ssError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$ssError."</div>\n" : '';
|
||||
|
||||
if (User::canUploadScreenshot()):
|
||||
if ($this->user::canUploadScreenshot()):
|
||||
?>
|
||||
<form action="?screenshot=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return ss_validateForm(this)">
|
||||
<input type="file" name="screenshotfile" style="width: 35%"/><br />
|
||||
@@ -58,7 +60,7 @@
|
||||
<input type="file" name="screenshotfile" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>No has iniciado sesión. <a href="?account=signin">Inicia sesión</a> para enviar una captura de pantalla.</small>
|
||||
<?php
|
||||
@@ -69,7 +71,9 @@
|
||||
<div id="tab-suggest-a-video" style="display: none">
|
||||
Símplemente, escribe la URL del vídeo en el formulario.
|
||||
<?php
|
||||
if (User::canSuggestVideo()):
|
||||
echo $viError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$viError."</div>\n" : '';
|
||||
|
||||
if ($this->user::canSuggestVideo()):
|
||||
?>
|
||||
<div class="pad2"></div>
|
||||
<form action="?video=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return vi_validateForm(this)">
|
||||
@@ -85,7 +89,7 @@
|
||||
<input type="text" name="videourl" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>No has iniciado sesión. <a href="?account=signin">Inicia sesión</a> para enviar un video.</small>
|
||||
<?php
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
?>
|
||||
|
||||
<div id="tab-add-your-comment" style="display: none">
|
||||
При написании комментария, просим вас не забывать про следующее:
|
||||
@@ -9,9 +11,9 @@
|
||||
<li><div>У вас может возникнуть желание проверить написание своего комментария перед тем, как поместить его на сайт.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->coError ? ' <div class="msg-failure">'.$this->coError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $coError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$coError."</div>\n" : '';
|
||||
|
||||
if (User::canComment()):
|
||||
if ($this->user::canComment()):
|
||||
?>
|
||||
<form name="addcomment" action="?comment=add&type=<?=$this->type.'&typeid='.$this->typeId; ?>" method="post" onsubmit="return co_validateForm(this)">
|
||||
<div id="funcbox-generic"></div>
|
||||
@@ -25,7 +27,7 @@
|
||||
<div class="comment-edit-body"><textarea class="comment-editbox" rows="10" cols="40" name="commentbody" disabled="disabled"></textarea></div>
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Вы не вошли на сайт. Пожалуйста <a href="?account=signin">войдите</a> или <a href="?account=signup">зарегистрируйтесь</a>, чтобы добавлять комментарии.</small>
|
||||
<?php
|
||||
@@ -41,9 +43,9 @@
|
||||
<li><div>Если вы ещё не читали, то настоятельно рекомендуем вам прочесть <a href="?help=screenshots-tips-tricks" target="_blank">советы и особенности</a> получения изображений при помощи снимков экрана.</div></li>
|
||||
</ul>
|
||||
<?php
|
||||
echo $this->ssError ? ' <div class="msg-failure">'.$this->ssError."</div>\n <div class=\"pad\"></div>\n" : '';
|
||||
echo $ssError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$ssError."</div>\n" : '';
|
||||
|
||||
if (User::canUploadScreenshot()):
|
||||
if ($this->user::canUploadScreenshot()):
|
||||
?>
|
||||
<form action="?screenshot=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return ss_validateForm(this)">
|
||||
<input type="file" name="screenshotfile" style="width: 35%"/><br />
|
||||
@@ -58,7 +60,7 @@
|
||||
<input type="file" name="screenshotfile" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Вы не вошли на сайт. Пожалуйста <a href="?account=signin">войдите</a>, чтобы отправить скриншот.</small>
|
||||
<?php
|
||||
@@ -69,7 +71,9 @@
|
||||
<div id="tab-suggest-a-video" style="display: none">
|
||||
Введите URL видео на YouTube в форму ниже.
|
||||
<?php
|
||||
if (User::canSuggestVideo()):
|
||||
echo $viError ? " <div class=\"pad\"></div>\n <div class=\"msg-failure\">".$viError."</div>\n" : '';
|
||||
|
||||
if ($this->user::canSuggestVideo()):
|
||||
?>
|
||||
<div class="pad2"></div>
|
||||
<form action="?video=add&<?=$this->type.'.'.$this->typeId; ?>" method="post" enctype="multipart/form-data" onsubmit="return vi_validateForm(this)">
|
||||
@@ -85,7 +89,7 @@
|
||||
<input type="text" name="videourl" disabled="disabled" /><br />
|
||||
<?php
|
||||
endif;
|
||||
if (!User::isLoggedIn()):
|
||||
if (!$this->user::isLoggedIn()):
|
||||
?>
|
||||
<small>Вы не вошли на сайт. Пожалуйста <a href="?account=signin">войдите</a>, чтобы отправить видео.</small>
|
||||
<?php
|
||||
|
||||
@@ -5,6 +5,6 @@ Hey!
|
||||
Thanks a lot for your interest in contributing to the site.
|
||||
|
||||
Just click this link to activate your account:
|
||||
HOST_URL?account=signup&token=%s
|
||||
HOST_URL?account=activate&key=%s
|
||||
|
||||
The NAME_SHORT team
|
||||
|
||||
@@ -5,6 +5,6 @@ Bonjour !
|
||||
Nous vous remercions chaleureusement pour l'intérêt que vous portez à contribuer à notre site.
|
||||
|
||||
Vous n'avez qu'à cliquer sur le lien ci-dessous pour activer votre compte.
|
||||
HOST_URL?account=signup&token=%s
|
||||
HOST_URL?account=activate&key=%s
|
||||
|
||||
L'équipe NAME_SHORT
|
||||
|
||||
@@ -5,6 +5,6 @@ Hey!
|
||||
Vielen Dank für Euer Interesse an der Mitwirkung bei unserer Webseite.
|
||||
|
||||
Klickt einfach auf den folgenden Link, um Euer Konto zu aktivieren:
|
||||
HOST_URL?account=signup&token=%s
|
||||
HOST_URL?account=activate&key=%s
|
||||
|
||||
Das Team von NAME_SHORT
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
非常感谢你有兴趣为本站做出贡献。
|
||||
|
||||
只需点击此链接激活你的账户:
|
||||
HOST_URL?account=signup&token=%s
|
||||
HOST_URL?account=activate&key=%s
|
||||
|
||||
NAME_SHORT 团队敬上
|
||||
|
||||
@@ -5,6 +5,6 @@ Creación de cuenta
|
||||
Muchas gracias por tu interés en contribuir al sitio.
|
||||
|
||||
Simplemente haz clic en este enlace para activar tu cuenta:
|
||||
HOST_URL?account=signup&token=%s
|
||||
HOST_URL?account=activate&key=%s
|
||||
|
||||
El equipo de NAME_SHORT
|
||||
|
||||
@@ -5,6 +5,6 @@ Account Creation
|
||||
Благодарим за ваш интерес по наполнению сайта.
|
||||
|
||||
Для активации вашей учетной записи просто кликните по этой ссылке:
|
||||
HOST_URL?account=signup&token=%s
|
||||
HOST_URL?account=activate&key=%s
|
||||
|
||||
Команда NAME_SHORT.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
User Recovery
|
||||
Follow this link to log in.
|
||||
|
||||
HOST_URL?account=signin&token=%s
|
||||
HOST_URL?account=signin&key=%s
|
||||
|
||||
If you did not request this mail simply ignore it.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Récupération d'utilisateur
|
||||
Suivez ce lien pour vous connecter.
|
||||
|
||||
HOST_URL?account=signin&token=%s
|
||||
HOST_URL?account=signin&key=%s
|
||||
|
||||
Si vous n'avez pas demandé cet e-mail, ignorez le.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Benutzernamenanfrage
|
||||
Folgt diesem Link um euch anzumelden.
|
||||
|
||||
HOST_URL?account=signin&token=%s
|
||||
HOST_URL?account=signin&key=%s
|
||||
|
||||
Falls Ihr diese Mail nicht angefordert habt kann sie einfach ignoriert werden.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
用户恢复
|
||||
请点击此链接登录。
|
||||
|
||||
HOST_URL?account=signin&token=%s
|
||||
HOST_URL?account=signin&key=%s
|
||||
|
||||
如果您没有请求此邮件,请忽略它。
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Recuperacion de Usuario
|
||||
Siga a este enlace para ingresar.
|
||||
|
||||
HOST_URL?account=signin&token=%s
|
||||
HOST_URL?account=signin&key=%s
|
||||
|
||||
Si usted no solicitó este correo, por favor ignorelo.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Восстановление пользователя
|
||||
Перейдите по этой ссылке, чтобы войти в систему.
|
||||
|
||||
HOST_URL?account=signin&token=%s
|
||||
HOST_URL?account=signin&key=%s
|
||||
|
||||
Если вы не запрашивали это письмо, просто проигнорируйте его.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Password Reset
|
||||
Follow this link to reset your password.
|
||||
|
||||
HOST_URL?account=forgotpassword&token=%s
|
||||
HOST_URL?account=forgotpassword&key=%s
|
||||
|
||||
If you did not request this mail simply ignore it.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Réinitialisation du mot de passe
|
||||
Suivez ce lien pour réinitialiser votre mot de passe.
|
||||
|
||||
HOST_URL?account=forgotpassword&token=%s
|
||||
HOST_URL?account=forgotpassword&key=%s
|
||||
|
||||
Si vous n'avez pas fait de demande de réinitialisation, ignorez cet e-mail.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Kennwortreset
|
||||
Folgt diesem Link um euer Kennwort zurückzusetzen.
|
||||
|
||||
HOST_URL?account=forgotpassword&token=%s
|
||||
HOST_URL?account=forgotpassword&key=%s
|
||||
|
||||
Falls Ihr diese Mail nicht angefordert habt kann sie einfach ignoriert werden.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
重置密码
|
||||
点击此链接以重置您的密码。
|
||||
|
||||
HOST_URL?account=forgotpassword&token=%s
|
||||
HOST_URL?account=forgotpassword&key=%s
|
||||
|
||||
如果您没有请求此邮件,请忽略它。
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Reinicio de Contraseña
|
||||
Siga este enlace para reiniciar su contraseña.
|
||||
|
||||
HOST_URL?account=forgotpassword&token=%s
|
||||
HOST_URL?account=forgotpassword&key=%s
|
||||
|
||||
Si usted no solicitó este correo, por favor ignorelo.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
Сброс пароля
|
||||
Перейдите по этой ссылке, чтобы сбросить свой пароль.
|
||||
|
||||
HOST_URL?account=forgotpassword&token=%s
|
||||
HOST_URL?account=forgotpassword&key=%s
|
||||
|
||||
Если вы не запрашивали это письмо, просто проигнорируйте его.
|
||||
|
||||
@@ -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,83 +22,39 @@
|
||||
$this->brick('headIcons');
|
||||
|
||||
$this->brick('redButtons');
|
||||
?>
|
||||
|
||||
<h1<?=(isset($this->expansion) ? ' class="h1-icon"><span class="icon-'.$this->expansion.'-right">'.$this->name.'</span>' : '>'.$this->name); ?></h1>
|
||||
|
||||
<?php
|
||||
$this->brick('article');
|
||||
|
||||
if (isset($this->extraText)):
|
||||
?>
|
||||
<div id="text-generic" class="left"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
Markup.printHtml("<?=$this->extraText; ?>", "text-generic", {
|
||||
allow: Markup.CLASS_ADMIN,
|
||||
dbpage: true
|
||||
});
|
||||
//]]></script>
|
||||
|
||||
<div class="pad2"></div>
|
||||
<?php
|
||||
if ($this->expansion && $this->h1):
|
||||
echo ' <h1 class="h1-icon"><span class="icon-'.$this->expansion.'-right">'.$this->h1."</span></h1>\n";
|
||||
elseif ($this->h1):
|
||||
echo ' <h1>'.$this->h1."</h1>\n";
|
||||
endif;
|
||||
|
||||
$this->brick('markup', ['markup' => $this->article]);
|
||||
|
||||
$this->brick('markup', ['markup' => $this->extraText]);
|
||||
|
||||
$this->brick('mapper');
|
||||
|
||||
if (!empty($this->transfer)):
|
||||
if ($this->transfer):
|
||||
echo " <div class=\"pad\"></div>\n ".$this->transfer."\n";
|
||||
endif;
|
||||
|
||||
if (isset($this->smartAI)):
|
||||
?>
|
||||
<div id="text-generic" class="left"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
Markup.printHtml("<?=$this->smartAI; ?>", "text-generic", {
|
||||
allow: Markup.CLASS_ADMIN,
|
||||
dbpage: true
|
||||
});
|
||||
//]]></script>
|
||||
$this->brick('markup', ['markup' => $this->smartAI]);
|
||||
|
||||
<div class="pad2"></div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
if (!empty($this->zoneMusic)):
|
||||
if ($this->zoneMusic):
|
||||
?>
|
||||
<div class="clear">
|
||||
<?php
|
||||
if (!empty($this->zoneMusic['music'])):
|
||||
foreach ($this->zoneMusic as [$h3, $data, $divId, $opts]):
|
||||
?>
|
||||
<div id="zonemusicdiv-zonemusic" style="float: left">
|
||||
<h3><?=Lang::sound('music'); ?></h3>
|
||||
<div id="zonemusicdiv-<?=$divId; ?>" style="float: left">
|
||||
<h3><?=$h3; ?></h3>
|
||||
</div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
(new AudioControls()).init(<?=Util::toJSON($this->zoneMusic['music']); ?>, $WH.ge('zonemusicdiv-zonemusic'), {loop: true});
|
||||
(new AudioControls()).init(<?=$this->json($data); ?>, $WH.ge('zonemusicdiv-<?=$divId; ?>'), <?=$this->json($opts); ?>);
|
||||
//]]></script>
|
||||
<?php
|
||||
endif;
|
||||
if (!empty($this->zoneMusic['intro'])):
|
||||
?>
|
||||
<div id="zonemusicdiv-zonemusicintro" style="float: left">
|
||||
<h3><?=Lang::sound('intro'); ?></h3>
|
||||
|
||||
</div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
(new AudioControls()).init(<?=Util::toJSON($this->zoneMusic['intro']); ?>, $WH.ge('zonemusicdiv-zonemusicintro'), {});
|
||||
//]]></script>
|
||||
<?php
|
||||
endif;
|
||||
if (!empty($this->zoneMusic['ambience'])):
|
||||
?>
|
||||
<div id="zonemusicdiv-soundambience" style="float: left">
|
||||
<h3><?=Lang::sound('ambience'); ?></h3>
|
||||
|
||||
</div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
(new AudioControls()).init(<?=Util::toJSON($this->zoneMusic['ambience']); ?>, $WH.ge('zonemusicdiv-soundambience'), {loop: true});
|
||||
//]]></script>
|
||||
<?php
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<br clear="all"/></div>
|
||||
<?php
|
||||
@@ -104,7 +63,7 @@ endif;
|
||||
<h2 class="clear"><?=Lang::main('related'); ?></h2>
|
||||
</div>
|
||||
<?php
|
||||
$this->brick('lvTabs', ['relTabs' => true]);
|
||||
$this->brick('lvTabs');
|
||||
|
||||
$this->brick('contribute');
|
||||
?>
|
||||
|
||||
@@ -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">
|
||||
@@ -10,60 +13,34 @@
|
||||
$this->brick('announcement');
|
||||
|
||||
$this->brick('pageTemplate');
|
||||
|
||||
if ($this->notFound):
|
||||
?>
|
||||
<div class="pad3"></div>
|
||||
|
||||
<div class="inputbox">
|
||||
<h1><?=$this->notFound['title'];?></h1>
|
||||
<div id="inputbox-error"><?=$this->notFound['msg'];?></div>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<div class="text">
|
||||
<?php
|
||||
$this->brick('redButtons');
|
||||
|
||||
if (!empty($this->h1Links)):
|
||||
echo ' <div class="h1-links">'.$this->h1Links.'</div>';
|
||||
if ($this->h1Link):
|
||||
echo ' <div class="h1-links"><small><a href="'.$this->h1Link.'" class="icon-rss">'.Lang::main('subscribe').'</a></small></div>';
|
||||
endif;
|
||||
|
||||
if (!empty($this->name)):
|
||||
echo ' <h1>'.$this->name.'</h1>';
|
||||
if ($this->h1):
|
||||
echo ' <h1>'.$this->h1.'</h1>';
|
||||
endif;
|
||||
|
||||
$this->brick('mapper');
|
||||
|
||||
$this->brick('article');
|
||||
$this->brick('markup', ['markup' => $this->article]);
|
||||
|
||||
if (isset($this->extraText)):
|
||||
?>
|
||||
<div id="text-generic" class="left"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
Markup.printHtml("<?=Util::jsEscape($this->extraText);?>", "text-generic", {
|
||||
allow: Markup.CLASS_ADMIN,
|
||||
dbpage: true
|
||||
});
|
||||
//]]></script>
|
||||
$this->brick('markup', ['markup' => $this->extraText]);
|
||||
|
||||
<div class="pad2"></div>
|
||||
<?php
|
||||
endif;
|
||||
echo $this->extraHTML ?? '';
|
||||
|
||||
if (isset($this->extraHTML)):
|
||||
echo $this->extraHTML;
|
||||
endif;
|
||||
|
||||
endif;
|
||||
|
||||
if (!empty($this->tabsTitle)):
|
||||
if ($this->tabsTitle):
|
||||
echo ' <h2 class="clear">'.$this->tabsTitle.'</h2>';
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
if (!empty($this->lvTabs)):
|
||||
if ($this->lvTabs):
|
||||
$this->brick('lvTabs');
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?php namespace Aowow; ?>
|
||||
|
||||
<?php namespace Aowow\Template; ?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -9,9 +8,9 @@
|
||||
|
||||
<style type="text/css">
|
||||
body { text-align: center; font-family: Arial; background-color: black; color: white }
|
||||
.maintenance { background: url(<?=Cfg::get('STATIC_URL'); ?>/images/logos/home.png) no-repeat center top; width: 900px; margin: 40px auto; text-align: center; padding-top: 70px; }
|
||||
.maintenance { background: url(<?=$this->gStaticUrl; ?>/images/logos/home.png) no-repeat center top; width: 900px; margin: 40px auto; text-align: center; padding-top: 70px; }
|
||||
.maintenance div { color: #00DD00; font-weight: bold; padding: 20px }
|
||||
.maintenance p { background: url(<?=Cfg::get('STATIC_URL'); ?>/images/maintenance/brbgnomes.jpg) no-repeat center bottom; padding-bottom: 300px }
|
||||
.maintenance p { background: url(<?=$this->gStaticUrl; ?>/images/maintenance/brbgnomes.jpg) no-repeat center bottom; padding-bottom: 300px }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,72 +1,43 @@
|
||||
<?php namespace Aowow; ?>
|
||||
|
||||
<?php $this->brick('header'); ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
$this->brick('header');
|
||||
?>
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
||||
<?php
|
||||
$this->brick('announcement');
|
||||
|
||||
$this->brick('pageTemplate');
|
||||
|
||||
if ($this->notFound):
|
||||
?>
|
||||
<?php
|
||||
if (!empty($this->doResync)):
|
||||
if ([$typeStr, $id] = $this->doResync):
|
||||
?>
|
||||
<div id="roster-status" class="profiler-message clear"></div>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
|
||||
<div class="pad3"></div>
|
||||
|
||||
<div class="inputbox">
|
||||
<h1><?=$this->notFound['title']; ?></h1>
|
||||
<div id="inputbox-error"><?=$this->notFound['msg']; ?></div> <!-- style="background: no-repeat 3px 3px" -->
|
||||
<?php
|
||||
if (!empty($this->doResync)):
|
||||
?>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
pr_updateStatus('<?=$this->doResync[0]; ?>', $WH.ge('roster-status'), <?=$this->doResync[1]; ?>, 1);
|
||||
pr_updateStatus('<?=$typeStr; ?>', $WH.ge('roster-status'), <?=$id; ?>, 1);
|
||||
pr_setRegionRealm($WH.gE($WH.ge('topbar'), 'form')[0], '<?=$this->region; ?>', '<?=$this->realm; ?>');
|
||||
//]]></script>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
if ($this->inputbox):
|
||||
$this->brick(...$this->inputbox); // $templateName, [$templateVars]
|
||||
else:
|
||||
?>
|
||||
<div class="text">
|
||||
<h1><?=$this->name; ?></h1>
|
||||
<?=($this->h1 ? ' <h1>'.$this->h1.'</h1>' : '');?>
|
||||
|
||||
<?php
|
||||
$this->brick('article');
|
||||
$this->brick('markup', ['markup' => $this->article]);
|
||||
|
||||
if (isset($this->extraText)):
|
||||
$this->brick('markup', ['markup' => $this->extraText]);
|
||||
|
||||
echo $this->extraHTML ?? '';
|
||||
?>
|
||||
<div id="text-generic" class="left"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
Markup.printHtml("<?=Util::jsEscape($this->extraText); ?>", "text-generic", {
|
||||
allow: Markup.CLASS_ADMIN,
|
||||
dbpage: true
|
||||
});
|
||||
//]]></script>
|
||||
|
||||
<div class="pad2"></div>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
if (isset($this->extraHTML)):
|
||||
echo $this->extraHTML;
|
||||
endif;
|
||||
|
||||
endif;
|
||||
?>
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
Reference in New Issue
Block a user