mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Template/Update (Part 40)
* convert 'guides' (listing, viewing, writing & management) * don't allow comments on WIP guides
This commit is contained in:
81
endpoints/admin/guide.php
Normal file
81
endpoints/admin/guide.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminGuideResponse extends TextResponse
|
||||
{
|
||||
private const /* int */ ERR_NONE = 0;
|
||||
private const /* int */ ERR_GUIDE = 1;
|
||||
private const /* int */ ERR_STATUS = 2;
|
||||
private const /* int */ ERR_WRITE_DB = 3;
|
||||
private const /* int */ ERR_MISCELLANEOUS = 999;
|
||||
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'status' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => GuideMgr::STATUS_APPROVED, 'max_range' => GuideMgr::STATUS_REJECTED]],
|
||||
'msg' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id', 'status'))
|
||||
{
|
||||
trigger_error('AdminGuideResponse - malformed request received', E_USER_ERROR);
|
||||
$this->result = self::ERR_MISCELLANEOUS;
|
||||
return;
|
||||
}
|
||||
|
||||
$guide = DB::Aowow()->selectRow('SELECT `userId`, `status` FROM ?_guides WHERE `id` = ?d', $this->_post['id']);
|
||||
if (!$guide)
|
||||
{
|
||||
trigger_error('AdminGuideResponse - guide #'.$this->_post['id'].' not found', E_USER_ERROR);
|
||||
$this->result = self::ERR_GUIDE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_post['status'] == $guide['status'])
|
||||
{
|
||||
trigger_error('AdminGuideResponse - guide #'.$this->_post['id'].' already has status #'.$this->_post['status'], E_USER_ERROR);
|
||||
$this->result = self::ERR_STATUS;
|
||||
return;
|
||||
}
|
||||
|
||||
// status can only be APPROVED or REJECTED due to input validation
|
||||
if (!$this->update($this->_post['id'], $this->_post['status'], $this->_post['msg']))
|
||||
{
|
||||
trigger_error('AdminGuideResponse - write to db failed for guide #'.$this->_post['id'], E_USER_ERROR);
|
||||
$this->result = self::ERR_WRITE_DB;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_post['status'] == GuideMgr::STATUS_APPROVED)
|
||||
Util::gainSiteReputation($guide['userId'], SITEREP_ACTION_ARTICLE, ['id' => $this->_post['id']]);
|
||||
|
||||
$this->result = self::ERR_NONE;
|
||||
}
|
||||
|
||||
private function update(int $id, int $status, ?string $msg = null) : bool
|
||||
{
|
||||
if ($status == GuideMgr::STATUS_APPROVED) // set display rev to latest
|
||||
$ok = DB::Aowow()->query('UPDATE ?_guides SET `status` = ?d, `rev` = (SELECT `rev` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d ORDER BY `rev` DESC LIMIT 1), `approveUserId` = ?d, `approveDate` = ?d WHERE `id` = ?d', $status, Type::GUIDE, $id, User::$id, time(), $id);
|
||||
else
|
||||
$ok = DB::Aowow()->query('UPDATE ?_guides SET `status` = ?d WHERE `id` = ?d', $status, $id);
|
||||
|
||||
if (!$ok)
|
||||
return false;
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `status`) VALUES (?d, ?d, ?d, ?d)', $id, time(), User::$id, $status);
|
||||
if ($msg)
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `msg`) VALUES (?d, ?d, ?d, ?)', $id, time(), User::$id, $msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
46
endpoints/admin/guides.php
Normal file
46
endpoints/admin/guides.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminGuidesResponse extends TemplateResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'guides';
|
||||
protected ?int $activeTab = parent::TAB_STAFF;
|
||||
protected array $breadcrumb = [4, 1, 25]; // Staff > Content > Guides Awaiting Approval
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = 'Pending Guides';
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
parent::generate();
|
||||
|
||||
$pending = new GuideList([['status', GuideMgr::STATUS_REVIEW]]);
|
||||
if ($pending->error)
|
||||
$data = [];
|
||||
else
|
||||
{
|
||||
$data = $pending->getListviewData();
|
||||
$latest = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, MAX(`rev`) FROM ?_articles WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `rev`', Type::GUIDE, $pending->getFoundIDs());
|
||||
foreach ($latest as $id => $rev)
|
||||
$data[$id]['rev'] = $rev;
|
||||
}
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => array_values($data),
|
||||
'hiddenCols' => ['patch', 'comments', 'views', 'rating'],
|
||||
'extraCols' => '$_'
|
||||
), GuideList::$brickFile, 'guideAdminCol'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
48
endpoints/edit/image.php
Normal file
48
endpoints/edit/image.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EditImageResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'qqfile' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'guide' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 1]]
|
||||
);
|
||||
|
||||
/*
|
||||
success: bool
|
||||
id: image enumerator
|
||||
type: 3 ? png : jpg
|
||||
name: old filename
|
||||
error: errString
|
||||
*/
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('qqfile', 'guide'))
|
||||
{
|
||||
$this->result = Util::toJSON(['success' => false, 'error' => Lang::main('genericError')]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!User::canWriteGuide())
|
||||
{
|
||||
$this->result = Util::toJSON(['success' => false, 'error' => Lang::main('genericError')]);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->result = GuideMgr::handleUpload();
|
||||
|
||||
if (isset($this->result['success']))
|
||||
$this->result += ['name' => $this->_get['qqfile']];
|
||||
|
||||
$this->result = Util::toJSON($this->result);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
35
endpoints/get-description/get-description.php
Normal file
35
endpoints/get-description/get-description.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GetdescriptionBaseResponse extends TextResponse
|
||||
{
|
||||
protected string $contentType = MIME_TYPE_TEXT;
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'description' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']]
|
||||
);
|
||||
|
||||
public function __construct(string $param)
|
||||
{
|
||||
if ($param) // should be empty
|
||||
$this->generate404();
|
||||
|
||||
parent::__construct($param);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!User::canWriteGuide())
|
||||
return;
|
||||
|
||||
$this->result = GuideMgr::createDescription($this->_post['description']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
104
endpoints/guide/changelog.php
Normal file
104
endpoints/guide/changelog.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuideChangelogResponse extends TemplateResponse
|
||||
{
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'guide=changelog';
|
||||
protected ?int $activeTab = parent::TAB_GUIDES;
|
||||
protected array $breadcrumb = [6];
|
||||
|
||||
// why is this here: is there a mediawiki like diff function for staff?
|
||||
protected array $scripts = [[SC_CSS_STRING, 'li input[type="radio"] { margin:0px 5px 0px 0px; }']];
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
// main container should be tagged: <div class="text guide-changelog">
|
||||
|
||||
if (!$this->assertGET('id'))
|
||||
$this->generateNotFound(Lang::game('guide'), Lang::guide('notFound'));
|
||||
|
||||
$guide = new GuideList(array(['id', $this->_get['id']]));
|
||||
if ($guide->error)
|
||||
$this->generateNotFound(Lang::game('guide'), Lang::guide('notFound'));
|
||||
|
||||
if (!$guide->canBeViewed() && !$guide->userCanView())
|
||||
$this->forward('?guides='.$guide->getField('category'));
|
||||
|
||||
$this->h1 = lang::guide('clTitle', [$this->_get['id'], $guide->getField('title')]);
|
||||
if (!$this->h1)
|
||||
$this->h1 = $guide->getField('name');
|
||||
|
||||
$this->gPageInfo += ['name' => $guide->getField('name')];
|
||||
|
||||
|
||||
$this->breadcrumb[] = $guide->getField('category');
|
||||
|
||||
|
||||
parent::generate();
|
||||
|
||||
/* - NYI (see "&& false")
|
||||
$this->addScript([SC_JS_STRING,
|
||||
|
||||
<<<JS
|
||||
$(document).ready(function() {
|
||||
var radios = $("input[type=radio]");
|
||||
function limit(col, val) {
|
||||
radios.each(function(i, e) {
|
||||
if (col == e.name)
|
||||
return;
|
||||
|
||||
if (col == "b")
|
||||
e.disabled = (val <= parseInt(e.value));
|
||||
else if (col == "a")
|
||||
e.disabled = (val >= parseInt(e.value));
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
radios.each(function (i, e) {
|
||||
e.onchange = limit.bind(this, e.name, parseInt(e.value));
|
||||
|
||||
if (i < 2 && e.name == "b") // first pair
|
||||
$(e).trigger("click");
|
||||
else if (e.value == 0 && e.name == "a") // last pair
|
||||
$(e).trigger("click");
|
||||
});
|
||||
});
|
||||
JS
|
||||
]);
|
||||
*/
|
||||
|
||||
$buff = '<ul>';
|
||||
$inp = fn($rev) => User::isInGroup(U_GROUP_STAFF) && false ? ($rev !== null ? '<input name="a" value="'.$rev.'" type="radio"/><input name="b" value="'.$rev.'" type="radio"/><b>' : '<b style="margin-left:38px;">') : '';
|
||||
|
||||
$logEntries = DB::Aowow()->select('SELECT a.`username` AS `name`, gcl.`date`, gcl.`status`, gcl.`msg`, gcl.`rev` FROM ?_guides_changelog gcl JOIN ?_account a ON a.`id` = gcl.`userId` WHERE gcl.`id` = ?d ORDER BY gcl.`date` DESC', $this->_get['id']);
|
||||
foreach ($logEntries as $log)
|
||||
{
|
||||
if ($log['status'] != GuideMgr::STATUS_NONE)
|
||||
$buff .= '<li class="guide-changelog-status-change">'.$inp($log['rev']).'<b>'.Lang::guide('clStatusSet', [Lang::guide('status', $log['status'])]).'</b>'.Util::formatTimeDiff($log['date'])."</li>\n";
|
||||
else if ($log['msg'])
|
||||
$buff .= '<li>'.$inp($log['rev']).'<b>'.Util::formatTimeDiff($log['date']).Lang::main('colon').'</b>'.$log['msg'].' <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
else
|
||||
$buff .= '<li class="guide-changelog-minor-edit">'.$inp($log['rev']).'<b>'.Util::formatTimeDiff($log['date']).Lang::main('colon').'</b><i>'.Lang::guide('clMinorEdit').'</i> <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
}
|
||||
|
||||
// append creation
|
||||
$buff .= '<li class="guide-changelog-created">'.$inp(0).'<b>'.Lang::guide('clCreated').'</b>'.Util::formatTimeDiff($guide->getField('date'))."</li>\n</ul>\n";
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF) && false)
|
||||
$buff .= '<input type="button" value="Compare" onclick="alert(\'NYI\');" style="margin-left: 40px;"/>';
|
||||
|
||||
$this->extraHTML = $buff;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
214
endpoints/guide/edit.php
Normal file
214
endpoints/guide/edit.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuideEditResponse extends TemplateResponse
|
||||
{
|
||||
use TrGuideEditor;
|
||||
|
||||
protected ?string $articleUrl = 'edit';
|
||||
|
||||
protected string $template = 'guide-edit';
|
||||
protected string $pageName = 'guide=edit';
|
||||
protected ?int $activeTab = parent::TAB_GUIDES;
|
||||
protected array $breadcrumb = [6];
|
||||
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/article-description.js'],
|
||||
[SC_JS_FILE, 'js/article-editing.js'],
|
||||
[SC_JS_FILE, 'js/guide-editing.js'],
|
||||
[SC_JS_FILE, 'js/fileuploader.js'],
|
||||
[SC_JS_FILE, 'js/toolbar.js'],
|
||||
[SC_JS_FILE, 'js/AdjacentPreview.js'],
|
||||
[SC_CSS_FILE, 'css/article-editing.css'],
|
||||
[SC_CSS_FILE, 'css/fileuploader.css'],
|
||||
[SC_CSS_FILE, 'css/guide-edit.css'],
|
||||
[SC_CSS_FILE, 'css/AdjacentPreview.css'],
|
||||
[SC_CSS_STRING, <<<CSS
|
||||
|
||||
#upload-result input[type=text] { padding: 0px 2px; font-size: 12px; }
|
||||
#upload-result > span { display: block; height: 22px; }
|
||||
#upload-result { display: inline-block; text-align: right; }
|
||||
#upload-progress { display: inline-block; margin-right: 8px; }
|
||||
|
||||
CSS]
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'save' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ], // saved for more editing
|
||||
'submit' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ], // submitted for review
|
||||
'title' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'name' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'description' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkDescription'] ],
|
||||
'changelog' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ],
|
||||
'body' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ],
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFrom'] ],
|
||||
'category' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_value' => 1, 'max_value' => 9] ],
|
||||
'specId' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_value' => -1, 'max_value' => 2, 'default' => -1]],
|
||||
'classId' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_value' => 1, 'max_value' => 11, 'default' => 0]]
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT],
|
||||
'rev' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
public function __construct(string $param)
|
||||
{
|
||||
parent::__construct($param);
|
||||
|
||||
if (!User::canWriteGuide())
|
||||
$this->generateError();
|
||||
|
||||
if (!is_int($this->_get['id'])) // edit existing guide
|
||||
return;
|
||||
|
||||
$this->typeId = $this->_get['id']; // just to display sensible not-found msg
|
||||
$status = DB::Aowow()->selectCell('SELECT `status` FROM ?_guides WHERE `id` = ?d AND `status` <> ?d { AND `userId` = ?d }', $this->typeId, GuideMgr::STATUS_ARCHIVED, User::isInGroup(U_GROUP_STAFF) ? DBSIMPLE_SKIP : User::$id);
|
||||
if (!$status && $this->typeId)
|
||||
$this->generateNotFound(Lang::game('guide'), Lang::guide('notFound'));
|
||||
else if (!$this->typeId)
|
||||
return;
|
||||
|
||||
// just so we don't have to access GuideMgr from template
|
||||
$this->isDraft = $status == GuideMgr::STATUS_DRAFT;
|
||||
$this->editStatus = $status;
|
||||
$this->editRev = DB::Aowow()->selectCell('SELECT `rev` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d ORDER BY `rev` DESC', Type::GUIDE, $this->typeId);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($this->_post['save'] || $this->_post['submit'])
|
||||
{
|
||||
if (!$this->saveGuide())
|
||||
$this->error = Lang::main('intError');
|
||||
else if ($this->_get['id'] === 0)
|
||||
$this->forward('?guide=edit&id='.$this->typeId);
|
||||
}
|
||||
|
||||
$guide = new GuideList(array(['id', $this->typeId]));
|
||||
|
||||
$this->h1 = Lang::guide('editTitle');
|
||||
array_unshift($this->title, $this->h1.Lang::main('colon').$guide->getField('title'), Lang::game('guides'));
|
||||
|
||||
Lang::sort('guide', 'category');
|
||||
|
||||
// init required template vars
|
||||
$this->editCategory = $this->_post['category'] ?? $guide->getField('category');
|
||||
$this->editTitle = $this->_post['title'] ?? $guide->getField('title');
|
||||
$this->editName = $this->_post['name'] ?? $guide->getField('name');
|
||||
$this->editDescription = $this->_post['description'] ?? $guide->getField('description');
|
||||
$this->editText = $this->_post['body'] ?? $guide->getArticle();
|
||||
$this->editClassId = $this->_post['classId'] ?? $guide->getField('classId');
|
||||
$this->editSpecId = $this->_post['specId'] ?? $guide->getField('specId');
|
||||
$this->editLocale = $this->_post['locale'] ?? Locale::tryFrom($guide->getField('locale'));
|
||||
$this->editStatus = $this->editStatus ?: $guide->getField('status');
|
||||
$this->editStatusColor = GuideMgr::STATUS_COLORS[$this->editStatus];
|
||||
|
||||
$this->extendGlobalData($guide->getJSGlobals());
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
|
||||
private function saveGuide() : bool
|
||||
{
|
||||
// test requiered fields set
|
||||
if (!$this->assertPOST('title', 'name', 'body', 'locale', 'category'))
|
||||
{
|
||||
trigger_error('GuideEditResponse::saveGuide - received malformed request', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// test required fields context
|
||||
if (!$this->_post['locale']->validate())
|
||||
return false;
|
||||
|
||||
// sanitize: spec / class
|
||||
if ($this->_post['category'] == 1) // Classes
|
||||
{
|
||||
if ($this->_post['classId'] && !ChrClass::tryFrom($this->_post['classId']))
|
||||
$this->_post['classId'] = 0;
|
||||
|
||||
if ($this->_post['specId'] > -1 && !$this->_post['classId'])
|
||||
$this->_post['specId'] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_post['classId'] = 0;
|
||||
$this->_post['specId'] = -1;
|
||||
}
|
||||
|
||||
$guideData = array(
|
||||
'category' => $this->_post['category'],
|
||||
'classId' => $this->_post['classId'],
|
||||
'specId' => $this->_post['specId'],
|
||||
'title' => $this->_post['title'],
|
||||
'name' => $this->_post['name'],
|
||||
'description' => $this->_post['description'] ?: GuideMgr::createDescription($this->_post['body']),
|
||||
'locale' => $this->_post['locale']->value,
|
||||
'roles' => User::$groups,
|
||||
'status' => $this->_post['submit'] ? GuideMgr::STATUS_REVIEW : GuideMgr::STATUS_DRAFT,
|
||||
'date' => time()
|
||||
);
|
||||
|
||||
// new guide > reload editor
|
||||
if ($this->_get['id'] === 0)
|
||||
{
|
||||
$guideData += ['userId' => User::$id];
|
||||
if (!($this->typeId = (int)DB::Aowow()->query('INSERT INTO ?_guides (?#) VALUES (?a)', array_keys($guideData), array_values($guideData))))
|
||||
{
|
||||
trigger_error('GuideEditResponse::saveGuide - failed to save guide to db', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// existing guide > :shrug:
|
||||
else if (DB::Aowow()->query('UPDATE ?_guides SET ?a WHERE `id` = ?d', $guideData, $this->typeId))
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `rev`, `date`, `userId`, `msg`) VALUES (?d, ?d, ?d, ?d, ?)', $this->typeId, $this->editRev, time(), User::$id, $this->_post['changelog']);
|
||||
else
|
||||
{
|
||||
trigger_error('GuideEditResponse::saveGuide - failed to update guide in db', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// insert Article
|
||||
$articleId = DB::Aowow()->query(
|
||||
'INSERT INTO ?_articles (`type`, `typeId`, `locale`, `rev`, `editAccess`, `article`) VALUES (?d, ?d, ?d, ?d, ?d, ?)',
|
||||
Type::GUIDE,
|
||||
$this->typeId,
|
||||
$this->_post['locale']->value,
|
||||
++$this->editRev,
|
||||
User::$groups & U_GROUP_STAFF ? User::$groups : User::$groups | U_GROUP_BLOGGER,
|
||||
$this->_post['body']
|
||||
);
|
||||
|
||||
if (!is_int($articleId))
|
||||
{
|
||||
if ($this->_get['id'] === 0)
|
||||
DB::Aowow()->query('DELETE FROM ?_guides WHERE `id` = ?d', $this->typeId);
|
||||
|
||||
trigger_error('GuideEditResponse::saveGuide - failed to save article to db', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->_post['submit'] && $this->editStatus != GuideMgr::STATUS_REVIEW)
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `status`) VALUES (?d, ?d, ?d, ?d)', $this->typeId, time(), User::$id, GuideMgr::STATUS_REVIEW);
|
||||
|
||||
$this->editStatus = $guideData['status'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function checkDescription(string $str) : string
|
||||
{
|
||||
// run checkTextBlob and also replace \n => \s and \s+ => \s
|
||||
$str = preg_replace(parent::PATTERN_TEXT_BLOB, '', $str);
|
||||
|
||||
$str = strtr($str, ["\n" => ' ', "\r" => ' ']);
|
||||
|
||||
return preg_replace('/\s+/', ' ', trim($str));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
250
endpoints/guide/guide.php
Normal file
250
endpoints/guide/guide.php
Normal file
@@ -0,0 +1,250 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuideBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'guide';
|
||||
protected ?int $activeTab = parent::TAB_GUIDES;
|
||||
protected array $breadcrumb = [6];
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT],
|
||||
'rev' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
|
||||
public int $type = Type::GUIDE;
|
||||
public int $typeId = 0;
|
||||
public int $guideStatus = 0;
|
||||
public array $guideRating = [];
|
||||
public ?int $guideRevision = null;
|
||||
|
||||
private GuideList $subject;
|
||||
|
||||
public function __construct(string $nameOrId)
|
||||
{
|
||||
parent::__construct($nameOrId);
|
||||
|
||||
/**********************/
|
||||
/* get mode + guideId */
|
||||
/**********************/
|
||||
|
||||
if (Util::checkNumeric($nameOrId, NUM_CAST_INT))
|
||||
$this->typeId = $nameOrId;
|
||||
else if (preg_match(GuideMgr::VALID_URL, $nameOrId))
|
||||
{
|
||||
if ($id = DB::Aowow()->selectCell('SELECT `id` FROM ?_guides WHERE `url` = ?', Util::lower($nameOrId)))
|
||||
{
|
||||
$this->typeId = intVal($id);
|
||||
$this->articleUrl = Util::lower($nameOrId);
|
||||
}
|
||||
}
|
||||
|
||||
$this->contribute = Type::getClassAttrib($this->type, 'contribute') ?? CONTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->subject = new GuideList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->generateNotFound(Lang::game('guide'), Lang::guide('notFound'));
|
||||
|
||||
if (!$this->subject->canBeViewed() && !$this->subject->userCanView())
|
||||
$this->forward('?guides='.$this->subject->getField('category'));
|
||||
|
||||
$this->guideStatus = $this->subject->getField('status');
|
||||
if ($this->guideStatus != GuideMgr::STATUS_APPROVED && $this->guideStatus != GuideMgr::STATUS_ARCHIVED)
|
||||
{
|
||||
$this->cacheType = CACHE_TYPE_NONE;
|
||||
$this->contribute = CONTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
if ($this->articleUrl)
|
||||
$this->guideRevision = $this->subject->getField('rev');
|
||||
else if ($this->subject->userCanView())
|
||||
$this->guideRevision = $this->_get['rev'] ?? $this->subject->getField('latest');
|
||||
else
|
||||
$this->subject->getField('rev');
|
||||
|
||||
$this->h1 = $this->subject->getField('name');
|
||||
|
||||
$this->gPageInfo += array(
|
||||
'name' => $this->h1,
|
||||
'author' => $this->subject->getField('author')
|
||||
);
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
/*************/
|
||||
|
||||
if ($x = $this->subject?->getField('category'))
|
||||
$this->breadcrumb[] = $x;
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
/**************/
|
||||
|
||||
array_unshift($this->title, $this->subject->getField('title'), Lang::game('guides'));
|
||||
|
||||
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
if (!($this->subject->getField('cuFlags') & GUIDE_CU_NO_QUICKFACTS))
|
||||
$this->generateInfobox();
|
||||
|
||||
// needs post-cache updating
|
||||
if (!($this->subject->getField('cuFlags') & GUIDE_CU_NO_RATING))
|
||||
$this->guideRating = array(
|
||||
$this->subject->getField('rating'), // avg rating
|
||||
User::canUpvote() && User::canDownvote() ? 'true' : 'false',
|
||||
$this->subject->getField('_self'), // my rating amt; 0 = no vote
|
||||
$this->typeId // guide Id
|
||||
);
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
if ($this->subject->userCanView())
|
||||
$this->redButtons[BUTTON_GUIDE_EDIT] = User::canWriteGuide() && $this->guideStatus != GuideMgr::STATUS_ARCHIVED;
|
||||
|
||||
$this->redButtons[BUTTON_GUIDE_LOG] = true;
|
||||
$this->redButtons[BUTTON_GUIDE_REPORT] = $this->subject->canBeReported();
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], __forceTabs: true);
|
||||
|
||||
// the article text itself is added by PageTemplate::addArticle()
|
||||
parent::generate();
|
||||
|
||||
$this->result->registerDisplayHook('infobox', [self::class, 'infoboxHook']);
|
||||
if ($this->guideRating)
|
||||
$this->result->registerDisplayHook('guideRating', [self::class, 'starsHook']);
|
||||
}
|
||||
|
||||
private function generateInfobox() : void
|
||||
{
|
||||
$infobox = [];
|
||||
|
||||
if ($this->subject->getField('cuFlags') & CC_FLAG_STICKY)
|
||||
$infobox[] = '[span class=guide-sticky]'.Lang::guide('sticky').'[/span]';
|
||||
|
||||
$infobox[] = Lang::guide('author').'[url=?user='.$this->subject->getField('author').']'.$this->subject->getField('author').'[/url]';
|
||||
|
||||
if ($this->subject->getField('category') == 1)
|
||||
{
|
||||
$c = $this->subject->getField('classId');
|
||||
$s = $this->subject->getField('specId');
|
||||
if ($c > 0)
|
||||
{
|
||||
$this->extendGlobalIds(Type::CHR_CLASS, $c);
|
||||
$infobox[] = Util::ucFirst(Lang::game('class')).Lang::main('colon').'[class='.$c.']';
|
||||
}
|
||||
if ($s > -1)
|
||||
$infobox[] = Lang::guide('spec').'[icon class="c'.$c.' icontiny" name='.Game::$specIconStrings[$c][$s].']'.Lang::game('classSpecs', $c, $s).'[/icon]';
|
||||
}
|
||||
|
||||
// $infobox[] = Lang::guide('patch').Lang::main('colon').'3.3.5'; // replace with date
|
||||
$infobox[] = Lang::guide('added').'[tooltip name=added]'.date('l, G:i:s', $this->subject->getField('date')).'[/tooltip][span class=tip tooltip=added]'.date(Lang::main('dateFmtShort'), $this->subject->getField('date')).'[/span]';
|
||||
|
||||
if ($this->guideStatus == GuideMgr::STATUS_ARCHIVED)
|
||||
$infobox[] = Lang::guide('status', GuideMgr::STATUS_ARCHIVED);
|
||||
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
if ($this->guideStatus == GuideMgr::STATUS_REVIEW && User::isInGroup(U_GROUP_STAFF) && $this->_get['rev'])
|
||||
{
|
||||
$this->addScript([SC_JS_STRING, <<<JS
|
||||
|
||||
$(document).ready(function() {
|
||||
let send = function (status)
|
||||
{
|
||||
let message = "";
|
||||
let id = \$WH.g_getGets().guide;
|
||||
if (status == 4) // rejected
|
||||
{
|
||||
while (message === "")
|
||||
message = prompt("Please provide your reasoning.");
|
||||
|
||||
if (message === null)
|
||||
return false;
|
||||
}
|
||||
|
||||
$.ajax({cache: false, url: "?admin=guide", type: "POST",
|
||||
error: function() { alert("Operation failed."); },
|
||||
success: function(json)
|
||||
{
|
||||
if (json)
|
||||
alert("Operation failed.");
|
||||
else
|
||||
window.location.href = "?admin=guides";
|
||||
},
|
||||
data: { id: id, status: status, msg: message }
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
\$WH.ge("btn-accept").onclick = send.bind(null, 3);
|
||||
\$WH.ge("btn-reject").onclick = send.bind(null, 4);
|
||||
});
|
||||
|
||||
JS]);
|
||||
|
||||
$this->infobox->append('[h3 style="text-align:center"]Admin[/h3]');
|
||||
$this->infobox->append('[div style="text-align:center"][url=# id="btn-accept" class=icon-tick]Approve[/url][url=# style="margin-left:20px" id="btn-reject" class=icon-delete]Reject[/url][/div]');
|
||||
}
|
||||
}
|
||||
|
||||
public static function infoboxHook(Template\PageTemplate &$pt, ?InfoboxMarkup &$infobox) : void
|
||||
{
|
||||
if ($pt->guideStatus != GuideMgr::STATUS_APPROVED)
|
||||
return;
|
||||
|
||||
// increment and display views
|
||||
DB::Aowow()->query('UPDATE ?_guides SET `views` = `views` + 1 WHERE `id` = ?d', $pt->typeId);
|
||||
|
||||
$nViews = DB::Aowow()->selectCell('SELECT `views` FROM ?_guides WHERE `id` = ?d', $pt->typeId);
|
||||
|
||||
$infobox->addItem(Lang::guide('views').'[n5='.$nViews.']');
|
||||
|
||||
// should we have a rating item in the lv?
|
||||
if (!$pt->guideRating)
|
||||
return;
|
||||
|
||||
$rating = GuideMgr::getRatings([$pt->typeId]);
|
||||
if ($rating[$pt->typeId]['nvotes'] < 5)
|
||||
$infobox->addItem(Lang::guide('rating').Lang::guide('noVotes'));
|
||||
else
|
||||
$infobox->addItem(Lang::guide('rating').Lang::guide('votes', [round($rating[$pt->typeId]['rating'], 1), $rating[$pt->typeId]['nvotes']]));
|
||||
}
|
||||
|
||||
public static function starsHook(Template\PageTemplate &$pt, ?array &$guideRating) : void
|
||||
{
|
||||
if ($pt->guideStatus != GuideMgr::STATUS_APPROVED)
|
||||
return;
|
||||
|
||||
$rating = GuideMgr::getRatings([$pt->typeId]);
|
||||
$guideRating = array(
|
||||
$rating[$pt->typeId]['rating'],
|
||||
User::canUpvote() && User::canDownvote() ? 'true' : 'false',
|
||||
$rating[$pt->typeId]['_self'] ?? 0,
|
||||
$pt->typeId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
59
endpoints/guide/guide_power.php
Normal file
59
endpoints/guide/guide_power.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuidePowerResponse extends TextResponse implements ICache
|
||||
{
|
||||
use TrCache, TrTooltip;
|
||||
|
||||
private const /* string */ POWER_TEMPLATE = '$WowheadPower.registerGuide(%s, %d, %s);';
|
||||
|
||||
protected int $type = Type::GUIDE;
|
||||
protected int $typeId = 0;
|
||||
protected int $cacheType = CACHE_TYPE_TOOLTIP;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'domain' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFromDomain']]
|
||||
);
|
||||
|
||||
private string $url = '';
|
||||
|
||||
public function __construct(string $idOrName)
|
||||
{
|
||||
parent::__construct($idOrName);
|
||||
|
||||
// temp locale
|
||||
if ($this->_get['domain'])
|
||||
Lang::load($this->_get['domain']);
|
||||
|
||||
if (Util::checkNumeric($idOrName, NUM_CAST_INT))
|
||||
$this->typeId = $idOrName;
|
||||
else if ($id = DB::Aowow()->selectCell('SELECT `id` FROM ?_guides WHERE `url` = ?', Util::lower($idOrName)))
|
||||
{
|
||||
$this->typeId = intVal($id);
|
||||
$this->url = Util::lower($idOrName);
|
||||
}
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$opts = [];
|
||||
if ($this->typeId)
|
||||
if (!($guide = new GuideList(array(['id', $this->typeId])))->error)
|
||||
$opts = array(
|
||||
'name' => $guide->getField('name', true),
|
||||
'tooltip' => $guide->renderTooltip()
|
||||
);
|
||||
|
||||
if (!$opts)
|
||||
$this->cacheType = CACHE_TYPE_NONE;
|
||||
|
||||
$this->result = new Tooltip(self::POWER_TEMPLATE, $this->url ?: $this->typeId, $opts);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
66
endpoints/guide/new.php
Normal file
66
endpoints/guide/new.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuideNewResponse extends TemplateResponse
|
||||
{
|
||||
use TrGuideEditor;
|
||||
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected ?string $articleUrl = 'new';
|
||||
|
||||
protected string $template = 'guide-edit';
|
||||
protected string $pageName = 'guide=new';
|
||||
protected ?int $activeTab = parent::TAB_GUIDES;
|
||||
protected array $breadcrumb = [6];
|
||||
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/article-description.js'],
|
||||
[SC_JS_FILE, 'js/article-editing.js'],
|
||||
[SC_JS_FILE, 'js/guide-editing.js'],
|
||||
[SC_JS_FILE, 'js/fileuploader.js'],
|
||||
[SC_JS_FILE, 'js/toolbar.js'],
|
||||
[SC_JS_FILE, 'js/AdjacentPreview.js'],
|
||||
[SC_CSS_FILE, 'css/article-editing.css'],
|
||||
[SC_CSS_FILE, 'css/fileuploader.css'],
|
||||
[SC_CSS_FILE, 'css/guide-edit.css'],
|
||||
[SC_CSS_FILE, 'css/AdjacentPreview.css'],
|
||||
[SC_CSS_STRING, <<<CSS
|
||||
|
||||
#upload-result input[type=text] { padding: 0px 2px; font-size: 12px; }
|
||||
#upload-result > span { display: block; height: 22px; }
|
||||
#upload-result { display: inline-block; text-align: right; }
|
||||
#upload-progress { display: inline-block; margin-right: 8px; }
|
||||
|
||||
CSS]
|
||||
);
|
||||
|
||||
public function __construct(string $param)
|
||||
{
|
||||
parent::__construct($param);
|
||||
|
||||
if (!User::canWriteGuide())
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Lang::guide('newTitle');
|
||||
|
||||
array_unshift($this->title, $this->h1, Lang::game('guides'));
|
||||
|
||||
Lang::sort('guide', 'category');
|
||||
|
||||
// update required template vars
|
||||
$this->editLocale = Lang::getLocale();
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
50
endpoints/guide/vote.php
Normal file
50
endpoints/guide/vote.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuideVoteResponse extends TextResponse
|
||||
{
|
||||
protected string $contentType = MIME_TYPE_TEXT;
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'rating' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 0, 'max_range' => 5]]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertPOST('id', 'rating'))
|
||||
{
|
||||
trigger_error('GuideVoteResponse - malformed request received', E_USER_ERROR);
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
if (!User::canUpvote() || !User::canDownvote()) // same logic as comments?
|
||||
$this->generate403();
|
||||
|
||||
// by id, not own, published
|
||||
$points = $votes = 0;
|
||||
if ($g = DB::Aowow()->selectRow('SELECT `userId`, `cuFlags` FROM ?_guides WHERE `id` = ?d AND (`status` = ?d OR `rev` > 0)', $this->_post['id'], GuideMgr::STATUS_APPROVED))
|
||||
{
|
||||
// apparently you are allowed to vote on your own guide
|
||||
if ($g['cuFlags'] & GUIDE_CU_NO_RATING)
|
||||
$this->generate403();
|
||||
|
||||
if (!$this->_post['rating'])
|
||||
DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND `userId` = ?d', RATING_GUIDE, $this->_post['id'], User::$id);
|
||||
else
|
||||
DB::Aowow()->query('REPLACE INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)', RATING_GUIDE, $this->_post['id'], User::$id, $this->_post['rating']);
|
||||
|
||||
[$points, $votes] = DB::Aowow()->selectRow('SELECT IFNULL(SUM(`value`), 0) AS "0", IFNULL(COUNT(*), 0) AS "1" FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d', RATING_GUIDE, $this->_post['id']);
|
||||
}
|
||||
|
||||
$this->result = Util::toJSON($votes ? ['rating' => $points / $votes, 'nvotes' => $votes] : ['rating' => 0, 'nvotes' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
73
endpoints/guides/guides.php
Normal file
73
endpoints/guides/guides.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuidesBaseResponse extends TemplateResponse // implements ICache
|
||||
{
|
||||
use TrListPage/* , TrCache */;
|
||||
|
||||
// protected int $cacheType = CACHE_TYPE_PAGE; // really do? cache would need to be destroyed externally with each guide status update
|
||||
protected int $type = Type::GUIDE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'guides';
|
||||
protected ?int $activeTab = parent::TAB_GUIDES;
|
||||
protected array $breadcrumb = [6];
|
||||
|
||||
protected array $validCats = [null, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('guides'));
|
||||
|
||||
|
||||
if ($this->category)
|
||||
$this->breadcrumb[] = $this->category[0];
|
||||
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
if ($this->category)
|
||||
array_unshift($this->title, Lang::guide('category', $this->category[0]));
|
||||
|
||||
|
||||
$conditions = array(
|
||||
['locale', Lang::getLocale()->value],
|
||||
['status', GuideMgr::STATUS_ARCHIVED, '!'], // never archived guides
|
||||
[
|
||||
'OR',
|
||||
['status', GuideMgr::STATUS_APPROVED], // currently approved
|
||||
['rev', 0, '>'] // has previously approved revision
|
||||
]
|
||||
);
|
||||
if ($this->category)
|
||||
$conditions[] = ['category', $this->category[0]];
|
||||
|
||||
$this->redButtons = [BUTTON_GUIDE_NEW => User::canWriteGuide()];
|
||||
|
||||
$guides = new GuideList($conditions);
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $guides->getListviewData(),
|
||||
'name' => Util::ucFirst(Lang::game('guides')),
|
||||
'hiddenCols' => ['patch'], // pointless: display date instead
|
||||
'extraCols' => ['$Listview.extraCols.date'] // ok
|
||||
), GuideList::$brickFile));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
52
endpoints/my-guides/my-guides.php
Normal file
52
endpoints/my-guides/my-guides.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class MyguidesBaseResponse extends TemplateResponse
|
||||
{
|
||||
use TrListPage;
|
||||
|
||||
protected int $type = Type::GUIDE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'my-guides';
|
||||
protected ?int $activeTab = parent::TAB_GUIDES;
|
||||
// protected array $breadcrumb = [6]; // breadcrumb menu not displayed by WH.?
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if (!User::isLoggedIn() || $pageParam)
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::guide('myGuides'));
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
$this->redButtons = [BUTTON_GUIDE_NEW => User::canWriteGuide()];
|
||||
|
||||
$guides = new GuideList(array(['userId', User::$id]));
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]);
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $guides->getListviewData(),
|
||||
'name' => Util::ucFirst(Lang::game('guides')),
|
||||
'hiddenCols' => ['patch', 'author'],
|
||||
'visibleCols' => ['status'],
|
||||
'extraCols' => ['$Listview.extraCols.date']
|
||||
), GuideList::$brickFile));
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -253,7 +253,7 @@ class UserBaseResponse extends TemplateResponse
|
||||
}
|
||||
|
||||
// My Guides
|
||||
$guides = new GuideList(['status', [GUIDE_STATUS_APPROVED, GUIDE_STATUS_ARCHIVED]], ['userId', $this->user['id']]);
|
||||
$guides = new GuideList(['status', [GuideMgr::STATUS_APPROVED, GuideMgr::STATUS_ARCHIVED]], ['userId', $this->user['id']]);
|
||||
if (!$guides->error)
|
||||
{
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
|
||||
@@ -7,7 +7,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class AjaxAdmin extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['siteconfig', 'weight-presets', 'spawn-override', 'guide', 'comment'];
|
||||
protected $validParams = ['siteconfig', 'weight-presets', 'spawn-override', 'comment'];
|
||||
protected $_get = array(
|
||||
'action' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextLine' ],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkIdListUnsigned'],
|
||||
@@ -64,13 +64,6 @@ class AjaxAdmin extends AjaxHandler
|
||||
|
||||
$this->handler = 'spawnPosFix';
|
||||
}
|
||||
else if ($this->params[0] == 'guide')
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_STAFF))
|
||||
return;
|
||||
|
||||
$this->handler = 'guideManage';
|
||||
}
|
||||
else if ($this->params[0] == 'comment')
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD))
|
||||
@@ -207,57 +200,6 @@ class AjaxAdmin extends AjaxHandler
|
||||
return '-1';
|
||||
}
|
||||
|
||||
protected function guideManage() : string
|
||||
{
|
||||
$update = function (int $id, int $status, ?string $msg = null) : bool
|
||||
{
|
||||
if (!DB::Aowow()->query('UPDATE ?_guides SET `status` = ?d WHERE `id` = ?d', $status, $id))
|
||||
return false;
|
||||
|
||||
// set display rev to latest
|
||||
if ($status == GUIDE_STATUS_APPROVED)
|
||||
DB::Aowow()->query('UPDATE ?_guides SET `rev` = (SELECT `rev` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d ORDER BY `rev` DESC LIMIT 1), `approveUserId` = ?d, `approveDate` = ?d WHERE `id` = ?d', Type::GUIDE, $id, User::$id, time(), $id);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `status`) VALUES (?d, ?d, ?d, ?d)', $id, time(), User::$id, $status);
|
||||
if ($msg)
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `msg`) VALUES (?d, ?d, ?d, ?)', $id, time(), User::$id, $msg);
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!$this->_post['id'])
|
||||
trigger_error('AjaxHander::guideManage - malformed request: id: '.$this->_post['id'].', status: '.$this->_post['status']);
|
||||
else
|
||||
{
|
||||
$guide = DB::Aowow()->selectRow('SELECT `userId`, `status` FROM ?_guides WHERE `id` = ?d', $this->_post['id']);
|
||||
if (!$guide)
|
||||
trigger_error('AjaxHander::guideManage - guide #'.$this->_post['id'].' not found');
|
||||
else
|
||||
{
|
||||
if ($this->_post['status'] == $guide['status'])
|
||||
trigger_error('AjaxHander::guideManage - guide #'.$this->_post['id'].' already has status #'.$this->_post['status']);
|
||||
else
|
||||
{
|
||||
if ($this->_post['status'] == GUIDE_STATUS_APPROVED)
|
||||
{
|
||||
if ($update($this->_post['id'], GUIDE_STATUS_APPROVED, $this->_post['msg']))
|
||||
{
|
||||
Util::gainSiteReputation($guide['userId'], SITEREP_ACTION_ARTICLE, ['id' => $this->_post['id']]);
|
||||
return '1';
|
||||
}
|
||||
else
|
||||
return '-2';
|
||||
}
|
||||
else if ($this->_post['status'] == GUIDE_STATUS_REJECTED)
|
||||
return $update($this->_post['id'], GUIDE_STATUS_REJECTED, $this->_post['msg']) ? '1' : '-2';
|
||||
else
|
||||
trigger_error('AjaxHander::guideManage - unhandled status change request');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '-1';
|
||||
}
|
||||
|
||||
protected function commentOutOfDate() : string
|
||||
{
|
||||
$ok = false;
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxEdit extends AjaxHandler
|
||||
{
|
||||
protected $_get = array(
|
||||
'qqfile' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextLine'],
|
||||
'guide' => ['filter' => FILTER_SANITIZE_NUMBER_INT ]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$params)
|
||||
return;
|
||||
|
||||
if ($params[0] == 'image')
|
||||
$this->handler = 'handleUpload';
|
||||
else if ($params[0] == 'article') // has it's own editor page
|
||||
$this->handler = null;
|
||||
}
|
||||
|
||||
/*
|
||||
success: bool
|
||||
id: image enumerator
|
||||
type: 3 ? png : jpg
|
||||
name: old filename
|
||||
error: errString
|
||||
*/
|
||||
protected function handleUpload() : string
|
||||
{
|
||||
if (!User::canWriteGuide() || $this->_get['guide'] != 1)
|
||||
return Util::toJSON(['success' => false, 'error' => '']);
|
||||
|
||||
require_once('includes/libs/qqFileUploader.class.php');
|
||||
|
||||
$targetPath = 'static/uploads/guide/images/';
|
||||
$tmpPath = 'static/uploads/temp/';
|
||||
$tmpFile = User::$username.'-'.Type::GUIDE.'-0-'.Util::createHash(16);
|
||||
|
||||
$uploader = new \qqFileUploader(['jpg', 'jpeg', 'png'], 10 * 1024 * 1024);
|
||||
$result = $uploader->handleUpload($tmpPath, $tmpFile, true);
|
||||
|
||||
if (isset($result['success']))
|
||||
{
|
||||
$finfo = new \finfo(FILEINFO_MIME);
|
||||
$mime = $finfo->file($tmpPath.$result['newFilename']);
|
||||
if (preg_match('/^image\/(png|jpe?g)/i', $mime, $m))
|
||||
{
|
||||
$i = 1; // image index
|
||||
if ($files = scandir($targetPath, SCANDIR_SORT_DESCENDING))
|
||||
if (rsort($files, SORT_NATURAL) && $files[0] != '.' && $files[0] != '..')
|
||||
$i = explode('.', $files[0])[0] + 1;
|
||||
|
||||
$targetFile = $i . ($m[1] == 'png' ? '.png' : '.jpg');
|
||||
|
||||
// move to final location
|
||||
if (!rename($tmpPath.$result['newFilename'], $targetPath.$targetFile))
|
||||
return Util::toJSON(['error' => Lang::main('intError')]);
|
||||
|
||||
// send success
|
||||
return Util::toJSON(array(
|
||||
'success' => true,
|
||||
'id' => $i,
|
||||
'type' => $m[1] == 'png' ? 3 : 2,
|
||||
'name' => $this->_get['qqfile']
|
||||
));
|
||||
}
|
||||
|
||||
return Util::toJSON(['error' => Lang::screenshot('error', 'unkFormat')]);
|
||||
}
|
||||
|
||||
return Util::toJSON($result);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxGetdescription extends AjaxHandler
|
||||
{
|
||||
protected $_post = array(
|
||||
'description' => [FILTER_CALLBACK, ['options' => 'Aowow\AjaxHandler::checkTextBlob']]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$params || $params[0]) // should be empty
|
||||
return;
|
||||
|
||||
$this->handler = 'handleDescription';
|
||||
}
|
||||
|
||||
protected function handleDescription() : string
|
||||
{
|
||||
$this->contentType = MIME_TYPE_TEXT;
|
||||
|
||||
if (!User::canWriteGuide())
|
||||
return '';
|
||||
|
||||
$desc = Markup::stripTags($this->_post['description']);
|
||||
|
||||
return Lang::trimTextClean($desc, 120);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxGuide extends AjaxHandler
|
||||
{
|
||||
protected $_post = array(
|
||||
'id' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'rating' => [FILTER_SANITIZE_NUMBER_INT, null]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params || count($this->params) != 1)
|
||||
return;
|
||||
|
||||
$this->contentType = MIME_TYPE_TEXT;
|
||||
|
||||
// select handler
|
||||
if ($this->params[0] == 'vote')
|
||||
$this->handler = 'voteGuide';
|
||||
}
|
||||
|
||||
protected function voteGuide() : string
|
||||
{
|
||||
if (!$this->_post['id'] || $this->_post['rating'] < 0 || $this->_post['rating'] > 5)
|
||||
{
|
||||
header('HTTP/1.0 404 Not Found', true, 404);
|
||||
return '';
|
||||
}
|
||||
else if (!User::canUpvote() || !User::canDownvote()) // same logic as comments?
|
||||
{
|
||||
header('HTTP/1.0 403 Forbidden', true, 403);
|
||||
return '';
|
||||
}
|
||||
// by id, not own, published
|
||||
if ($g = DB::Aowow()->selectRow('SELECT `userId`, `cuFlags` FROM ?_guides WHERE `id` = ?d AND (`status` = ?d OR `rev` > 0)', $this->_post['id'], GUIDE_STATUS_APPROVED))
|
||||
{
|
||||
if ($g['cuFlags'] & GUIDE_CU_NO_RATING || $g['userId'] == User::$id)
|
||||
{
|
||||
header('HTTP/1.0 403 Forbidden', true, 403);
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!$this->_post['rating'])
|
||||
DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND `userId` = ?d', RATING_GUIDE, $this->_post['id'], User::$id);
|
||||
else
|
||||
DB::Aowow()->query('REPLACE INTO ?_user_ratings VALUES (?d, ?d, ?d, ?d)', RATING_GUIDE, $this->_post['id'], User::$id, $this->_post['rating']);
|
||||
|
||||
$res = DB::Aowow()->selectRow('SELECT IFNULL(SUM(`value`), 0) AS `t`, IFNULL(COUNT(*), 0) AS `n` FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d', RATING_GUIDE, $this->_post['id']);
|
||||
return Util::toJSON($res['n'] ? ['rating' => $res['t'] / $res['n'], 'nvotes' => $res['n']] : ['rating' => 0, 'nvotes' => 0]);
|
||||
}
|
||||
|
||||
return Util::toJSON(['rating' => 0, 'nvotes' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
106
includes/components/guidemgr.class.php
Normal file
106
includes/components/guidemgr.class.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
use GdImage;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuideMgr
|
||||
{
|
||||
public const /* int */ STATUS_NONE = 0;
|
||||
public const /* int */ STATUS_DRAFT = 1;
|
||||
public const /* int */ STATUS_REVIEW = 2;
|
||||
public const /* int */ STATUS_APPROVED = 3;
|
||||
public const /* int */ STATUS_REJECTED = 4;
|
||||
public const /* int */ STATUS_ARCHIVED = 5;
|
||||
|
||||
private const /* string */ IMG_DEST_DIR = 'static/uploads/guide/images/';
|
||||
private const /* string */ IMG_TMP_DIR = 'static/uploads/temp/';
|
||||
|
||||
public const VALID_URL = '/^[a-z0-9_\-]{2,64}$/i';
|
||||
public const STATUS_COLORS = array(
|
||||
self::STATUS_DRAFT => '#71D5FF',
|
||||
self::STATUS_REVIEW => '#FFFF00',
|
||||
self::STATUS_APPROVED => '#1EFF00',
|
||||
self::STATUS_REJECTED => '#FF4040',
|
||||
self::STATUS_ARCHIVED => '#FFD100'
|
||||
);
|
||||
|
||||
private static array $ratingsStore = [];
|
||||
private static ?int $imgUploadIdx = null;
|
||||
|
||||
public static function createDescription(string $text) : string
|
||||
{
|
||||
return Lang::trimTextClean(Markup::stripTags($text), 120);
|
||||
}
|
||||
|
||||
public static function getRatings(array $guideIds) : array
|
||||
{
|
||||
if (!$guideIds)
|
||||
return [];
|
||||
|
||||
if (array_keys(self::$ratingsStore) == $guideIds)
|
||||
return self::$ratingsStore;
|
||||
|
||||
self::$ratingsStore = array_fill_keys($guideIds, ['nvotes' => 0, 'rating' => -1]);
|
||||
|
||||
$ratings = DB::Aowow()->select('SELECT `entry` AS ARRAY_KEY, IFNULL(SUM(`value`), 0) AS "0", IFNULL(COUNT(*), 0) AS "1", IFNULL(MAX(IF(`userId` = ?d, `value`, 0)), 0) AS "2" FROM ?_user_ratings WHERE `type` = ?d AND `entry` IN (?a) GROUP BY `entry`', User::$id, RATING_GUIDE, $guideIds);
|
||||
foreach ($ratings as $id => [$total, $count, $self])
|
||||
{
|
||||
self::$ratingsStore[$id]['nvotes'] = (int)$count;
|
||||
self::$ratingsStore[$id]['_self'] = (int)$self;
|
||||
if ($count >= 5 )
|
||||
self::$ratingsStore[$id]['rating'] = $total / $count;
|
||||
}
|
||||
|
||||
return self::$ratingsStore;
|
||||
}
|
||||
|
||||
public static function handleUpload() : array
|
||||
{
|
||||
require_once('includes/libs/qqFileUploader.class.php');
|
||||
|
||||
$tmpFile = User::$username.'-'.Type::GUIDE.'-0-'.Util::createHash(16);
|
||||
|
||||
$uploader = new \qqFileUploader(['jpg', 'jpeg', 'png'], 10 * 1024 * 1024);
|
||||
$result = $uploader->handleUpload(self::IMG_TMP_DIR, $tmpFile, true);
|
||||
|
||||
if (isset($result['error']))
|
||||
return $result;
|
||||
|
||||
$mime = (new \finfo(FILEINFO_MIME))?->file(self::IMG_TMP_DIR . $result['newFilename']);
|
||||
|
||||
if (!preg_match('/^image\/(png|jpe?g)/i', $mime, $m))
|
||||
return ['error' => Lang::screenshot('error', 'unkFormat')];
|
||||
|
||||
// find next empty image name (an int)
|
||||
if (is_null(self::$imgUploadIdx))
|
||||
{
|
||||
if ($files = scandir(self::IMG_DEST_DIR, SCANDIR_SORT_DESCENDING))
|
||||
if (rsort($files, SORT_NATURAL) && $files[0] != '.' && $files[0] != '..')
|
||||
$i = explode('.', $files[0])[0] + 1;
|
||||
|
||||
self::$imgUploadIdx = $i ?? 1;
|
||||
}
|
||||
|
||||
$targetFile = self::$imgUploadIdx . ($m[1] == 'png' ? '.png' : '.jpg');
|
||||
|
||||
// move to final location
|
||||
if (!rename(self::IMG_TMP_DIR.$result['newFilename'], self::IMG_DEST_DIR.$targetFile))
|
||||
{
|
||||
trigger_error('GuideMgr::handleUpload - failed to move file', E_USER_ERROR);
|
||||
return ['error' => Lang::main('intError')];
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => true,
|
||||
'id' => self::$imgUploadIdx,
|
||||
'type' => $m[1] == 'png' ? 3 : 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -27,7 +27,6 @@ class PageTemplate
|
||||
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;
|
||||
|
||||
@@ -71,13 +71,15 @@ trait TrGuideEditor
|
||||
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 int $editStatus = GuideMgr::STATUS_DRAFT;
|
||||
public string $editStatusColor = GuideMgr::STATUS_COLORS[GuideMgr::STATUS_DRAFT];
|
||||
public string $editTitle = '';
|
||||
public string $editName = '';
|
||||
public string $editDescription = '';
|
||||
public string $editText = '';
|
||||
public string $error = '';
|
||||
public Locale $editLocale = Locale::EN;
|
||||
public bool $isDraft = false;
|
||||
}
|
||||
|
||||
class TemplateResponse extends BaseResponse
|
||||
|
||||
@@ -10,14 +10,6 @@ class GuideList extends DBTypeList
|
||||
{
|
||||
use ListviewHelper;
|
||||
|
||||
public const /* array */ STATUS_COLORS = array(
|
||||
GUIDE_STATUS_DRAFT => '#71D5FF',
|
||||
GUIDE_STATUS_REVIEW => '#FFFF00',
|
||||
GUIDE_STATUS_APPROVED => '#1EFF00',
|
||||
GUIDE_STATUS_REJECTED => '#FF4040',
|
||||
GUIDE_STATUS_ARCHIVED => '#FFD100'
|
||||
);
|
||||
|
||||
public static int $type = Type::GUIDE;
|
||||
public static string $brickFile = 'guide';
|
||||
public static string $dataTable = '?_guides';
|
||||
@@ -28,9 +20,10 @@ class GuideList extends DBTypeList
|
||||
|
||||
protected string $queryBase = 'SELECT g.*, g.`id` AS ARRAY_KEY FROM ?_guides g';
|
||||
protected array $queryOpts = array(
|
||||
'g' => [['a', 'c'], 'g' => 'g.`id`'],
|
||||
'a' => ['j' => ['?_account a ON a.`id` = g.`userId`', true], 's' => ', IFNULL(a.`username`, "") AS "author"'],
|
||||
'c' => ['j' => ['?_comments c ON c.`type` = '.Type::GUIDE.' AND c.`typeId` = g.`id` AND (c.`flags` & '.CC_FLAG_DELETED.') = 0', true], 's' => ', COUNT(c.`id`) AS "comments"']
|
||||
'g' => [['a', 'c', 'ar'], 'g' => 'g.`id`'],
|
||||
'a' => ['j' => ['?_account a ON a.`id` = g.`userId`', true], 's' => ', IFNULL(a.`username`, "") AS "author"'],
|
||||
'c' => ['j' => ['?_comments c ON c.`type` = '.Type::GUIDE.' AND c.`typeId` = g.`id` AND (c.`flags` & '.CC_FLAG_DELETED.') = 0', true], 's' => ', COUNT(c.`id`) AS "comments"'],
|
||||
'ar' => ['j' => ['?_articles ar ON ar.`type` = 300 AND ar.`typeId` = g.`id`'], 's' => ', MAX(ar.`rev`) AS "latest"']
|
||||
);
|
||||
|
||||
public function __construct(array $conditions = [], array $miscData = [])
|
||||
@@ -40,23 +33,11 @@ class GuideList extends DBTypeList
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$ratings = DB::Aowow()->select('SELECT `entry` AS ARRAY_KEY, IFNULL(SUM(`value`), 0) AS `t`, IFNULL(COUNT(*), 0) AS `n`, IFNULL(MAX(IF(`userId` = ?d, `value`, 0)), 0) AS `s` FROM ?_user_ratings WHERE `type` = ?d AND `entry` IN (?a)', User::$id, RATING_GUIDE, $this->getFoundIDs());
|
||||
$ratings = GuideMgr::getRatings($this->getFoundIDs());
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $id => &$_curTpl)
|
||||
{
|
||||
if (isset($ratings[$id]))
|
||||
{
|
||||
$_curTpl['nvotes'] = $ratings[$id]['n'];
|
||||
$_curTpl['rating'] = $ratings[$id]['n'] < 5 ? -1 : $ratings[$id]['t'] / $ratings[$id]['n'];
|
||||
$_curTpl['_self'] = $ratings[$id]['s'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$_curTpl['nvotes'] = 0;
|
||||
$_curTpl['rating'] = -1;
|
||||
}
|
||||
}
|
||||
$_curTpl = array_merge($_curTpl, $ratings[$id]);
|
||||
}
|
||||
|
||||
public static function getName(int $id) : ?LocString
|
||||
@@ -133,13 +114,13 @@ class GuideList extends DBTypeList
|
||||
public function canBeViewed() : bool
|
||||
{
|
||||
// currently approved || has prev. approved version
|
||||
return $this->getField('status') == GUIDE_STATUS_APPROVED || $this->getField('rev') > 0;
|
||||
return $this->getField('status') == GuideMgr::STATUS_APPROVED || $this->getField('rev') > 0;
|
||||
}
|
||||
|
||||
public function canBeReported() : bool
|
||||
{
|
||||
// not own guide && is not archived
|
||||
return $this->getField('userId') != User::$id && $this->getField('status') != GUIDE_STATUS_ARCHIVED;
|
||||
return $this->getField('userId') != User::$id && $this->getField('status') != GuideMgr::STATUS_ARCHIVED;
|
||||
}
|
||||
|
||||
public function getJSGlobals(int $addMask = GLOBALINFO_ANY) : array
|
||||
|
||||
@@ -227,13 +227,6 @@ define('STR_ALLOW_SHORT', 0x4);
|
||||
define('RATING_COMMENT', 1);
|
||||
define('RATING_GUIDE', 2);
|
||||
|
||||
define('GUIDE_STATUS_NONE', 0);
|
||||
define('GUIDE_STATUS_DRAFT', 1);
|
||||
define('GUIDE_STATUS_REVIEW', 2);
|
||||
define('GUIDE_STATUS_APPROVED', 3);
|
||||
define('GUIDE_STATUS_REJECTED', 4);
|
||||
define('GUIDE_STATUS_ARCHIVED', 5);
|
||||
|
||||
define('DEFAULT_ICON', 'inv_misc_questionmark');
|
||||
|
||||
define('MENU_IDX_ID', 0); // ID: A number or string; null makes the menu item a separator
|
||||
|
||||
@@ -132,7 +132,7 @@ class qqFileUploader
|
||||
|
||||
private function toBytes(string $str) : int
|
||||
{
|
||||
$val = trim($str);
|
||||
$val = substr(trim($str), 0, -1);
|
||||
$last = strtolower(substr($str, -1, 1));
|
||||
switch ($last)
|
||||
{
|
||||
|
||||
@@ -111,7 +111,7 @@ abstract class Type
|
||||
self::CURRENCY => [CurrencyList::class, 'currency', 'g_gatheredcurrencies', self::FLAG_RANDOM_SEARCHABLE | self::FLAG_DB_TYPE | self::FLAG_HAS_ICON],
|
||||
self::SOUND => [SoundList::class, 'sound', 'g_sounds', self::FLAG_RANDOM_SEARCHABLE | self::FLAG_FILTRABLE | self::FLAG_DB_TYPE],
|
||||
self::ICON => [IconList::class, 'icon', 'g_icons', self::FLAG_RANDOM_SEARCHABLE | self::FLAG_FILTRABLE | self::FLAG_DB_TYPE | self::FLAG_HAS_ICON],
|
||||
self::GUIDE => [GuideList::class, 'guide', '', self::FLAG_NONE],
|
||||
self::GUIDE => [GuideList::class, 'guide', '', self::FLAG_DB_TYPE],
|
||||
self::PROFILE => [ProfileList::class, 'profile', '', self::FLAG_FILTRABLE], // x - not known in javascript
|
||||
self::GUILD => [GuildList::class, 'guild', '', self::FLAG_FILTRABLE], // x
|
||||
self::ARENA_TEAM => [ArenaTeamList::class, 'arena-team', '', self::FLAG_FILTRABLE], // x
|
||||
|
||||
@@ -681,7 +681,7 @@ class User
|
||||
if (!self::isLoggedIn() || self::isBanned(ACC_BAN_GUIDE))
|
||||
return $result;
|
||||
|
||||
if ($guides = DB::Aowow()->select('SELECT `id`, `title`, `url` FROM ?_guides WHERE `userId` = ?d AND `status` <> ?d', self::$id, GUIDE_STATUS_ARCHIVED))
|
||||
if ($guides = DB::Aowow()->select('SELECT `id`, `title`, `url` FROM ?_guides WHERE `userId` = ?d AND `status` <> ?d', self::$id, GuideMgr::STATUS_ARCHIVED))
|
||||
{
|
||||
// fix url
|
||||
array_walk($guides, fn(&$x) => $x['url'] = '?guide='.($x['url'] ?: $x['id']));
|
||||
|
||||
@@ -75,8 +75,6 @@ abstract class Util
|
||||
|
||||
public static $mapSelectorString = '<a href="javascript:;" onclick="myMapper.update({zone: %d}); g_setSelectedLink(this, \'mapper\'); return false" onmousedown="return false">%s</a> (%d)';
|
||||
|
||||
public static $guideratingString = " $(document).ready(function() {\n $('#guiderating').append(GetStars(%.10F, %s, %u, %u));\n });";
|
||||
|
||||
public static $expansionString = [null, 'bc', 'wotlk'];
|
||||
|
||||
public static $tcEncoding = '0zMcmVokRsaqbdrfwihuGINALpTjnyxtgevElBCDFHJKOPQSUWXYZ123456789';
|
||||
|
||||
@@ -167,20 +167,20 @@ $lang = array(
|
||||
'myGuides' => "Meine Leitfäden",
|
||||
'editTitle' => "Eigenen Leitfaden bearbeiten",
|
||||
'newTitle' => "Leitfaden erstellen",
|
||||
'author' => "Autor",
|
||||
'spec' => "Spezialisierung",
|
||||
'author' => "Autor: ",
|
||||
'spec' => "Spezialisierung: ",
|
||||
'sticky' => "Angeheftet",
|
||||
'views' => "Ansichten",
|
||||
'views' => "Ansichten: ",
|
||||
'patch' => "Patch",
|
||||
'added' => "Hinzugefügt",
|
||||
'rating' => "Wertung",
|
||||
'votes' => "[span id=guiderating-value]%d[/span]/5 ([span id=guiderating-votes][n5=%d][/span] Bewertungen) [span id=guiderating][/span]",
|
||||
'added' => "Hinzugefügt: ",
|
||||
'rating' => "Wertung: ",
|
||||
'votes' => "[span id=guiderating-value]%.2g[/span]/5 ([span id=guiderating-votes][n5=%d][/span] Bewertungen) [span id=guiderating][/span]",
|
||||
'noVotes' => "nicht genug Bewertungen [span id=guiderating][/span]",
|
||||
'byAuthor' => "Von %s",
|
||||
'notFound' => "Dieser Leitfaden existiert nicht.",
|
||||
'clTitle' => 'Änderungsprotokoll für "<a href="?guide=%1$d">%2$s</a>"',
|
||||
'clStatusSet' => 'Status gesetzt auf %s',
|
||||
'clCreated' => 'Erstellt',
|
||||
'clStatusSet' => 'Status gesetzt auf %s: ',
|
||||
'clCreated' => 'Erstellt: ',
|
||||
'clMinorEdit' => 'Kleinere Bearbeitung',
|
||||
'editor' => array(
|
||||
'fullTitle' => 'Ganze Überschrift',
|
||||
@@ -188,7 +188,7 @@ $lang = array(
|
||||
'name' => 'Name',
|
||||
'nameTip' => 'Dies sollte ein einfacher und klarer Name für den Leitfaden sein, der an Orten wie Menüs und Leitfadenlisten verwendet werden kann.',
|
||||
'description' => 'Beschreibung',
|
||||
'descriptionTip' => 'Beschreibung, die für Suchmaschinen verwendet wird.<br /><br />Wenn leer, wird es automatisch generiert.',
|
||||
'descriptionTip' => 'Beschreibung, die für Suchmaschinen verwendet wird.<br /><br />Wenn leer, wird es automatisch generiert.',
|
||||
// 'commentEmail' => 'Emailbenachrichtigung',
|
||||
// 'commentEmailTip' => 'Soll der Autor darüber benachrichtigt werden, dass Nutzer diesen Guide kommentieren?',
|
||||
'changelog' => 'Änderungsprotokoll für diese Änderung',
|
||||
@@ -203,11 +203,11 @@ $lang = array(
|
||||
'testGuide' => 'Sehen Sie, wie Ihr Leitfaden aussehen wird',
|
||||
'images' => 'Bilder',
|
||||
'statusTip' => array(
|
||||
GUIDE_STATUS_DRAFT => 'Ihr Leitfaden ist im "Entwurfs"-Status und Sie sind der einzige der ihn sehen kann. Bearbeiten Sie ihn so lange Sie wollen und wenn Sie fertig sind reichen Sie ihn zur Überprüfung ein.',
|
||||
GUIDE_STATUS_REVIEW => 'Ihr Leitfaden wird überprüft.',
|
||||
GUIDE_STATUS_APPROVED => 'Ihr Leitfaden wurde veröffentlicht.',
|
||||
GUIDE_STATUS_REJECTED => 'Ihr Leitfaden wurde abgewiesen. Nachdem die Mängel behoben wurde kann er erneut zur Überprüfung eingereicht werden.',
|
||||
GUIDE_STATUS_ARCHIVED => 'Ihr Leitfaden ist veraltet und wurde archiviert. Er wird nicht mehr in der Übersicht gelistet und ist kann nicht mehr bearbeitet werden.]',
|
||||
GuideMgr::STATUS_DRAFT => 'Ihr Leitfaden ist im "Entwurfs"-Status und Sie sind der einzige der ihn sehen kann. Bearbeiten Sie ihn so lange Sie wollen und wenn Sie fertig sind reichen Sie ihn zur Überprüfung ein.',
|
||||
GuideMgr::STATUS_REVIEW => 'Ihr Leitfaden wird überprüft.',
|
||||
GuideMgr::STATUS_APPROVED => 'Ihr Leitfaden wurde veröffentlicht.',
|
||||
GuideMgr::STATUS_REJECTED => 'Ihr Leitfaden wurde abgewiesen. Nachdem die Mängel behoben wurde kann er erneut zur Überprüfung eingereicht werden.',
|
||||
GuideMgr::STATUS_ARCHIVED => 'Ihr Leitfaden ist veraltet und wurde archiviert. Er wird nicht mehr in der Übersicht gelistet und ist kann nicht mehr bearbeitet werden.]',
|
||||
)
|
||||
),
|
||||
'category' => array(
|
||||
|
||||
@@ -167,20 +167,20 @@ $lang = array(
|
||||
'myGuides' => "My Guides",
|
||||
'editTitle' => "Edit your Guide",
|
||||
'newTitle' => "Create New Guide",
|
||||
'author' => "Author",
|
||||
'spec' => "Specialization",
|
||||
'author' => "Author: ",
|
||||
'spec' => "Specialization: ",
|
||||
'sticky' => "Sticky Status",
|
||||
'views' => "Views",
|
||||
'views' => "Views: ",
|
||||
'patch' => "Patch",
|
||||
'added' => "Added",
|
||||
'rating' => "Rating",
|
||||
'votes' => "[span id=guiderating-value]%d[/span]/5 ([span id=guiderating-votes][n5=%d][/span] votes) [span id=guiderating][/span]",
|
||||
'added' => "Added: ",
|
||||
'rating' => "Rating: ",
|
||||
'votes' => "[span id=guiderating-value]%.2g[/span]/5 ([span id=guiderating-votes][n5=%d][/span] votes) [span id=guiderating][/span]",
|
||||
'noVotes' => "not enough votes [span id=guiderating][/span]",
|
||||
'byAuthor' => "By %s",
|
||||
'notFound' => "This guide doesn't exist.",
|
||||
'clTitle' => 'Changelog For "<a href="?guide=%1$d">%2$s</a>"',
|
||||
'clStatusSet' => 'Status set to %s',
|
||||
'clCreated' => 'Created',
|
||||
'clStatusSet' => 'Status set to %s: ',
|
||||
'clCreated' => 'Created: ',
|
||||
'clMinorEdit' => 'Minor Edit',
|
||||
'editor' => array(
|
||||
'fullTitle' => 'Full Title',
|
||||
@@ -188,7 +188,7 @@ $lang = array(
|
||||
'name' => 'Name',
|
||||
'nameTip' => 'This should be a simple and clear name of what the guide is, for use in places like menus and guide lists.',
|
||||
'description' => 'Description',
|
||||
'descriptionTip' => 'Description that will be used for search engines.<br><br>If left empty, it will be generated automatically.',
|
||||
'descriptionTip' => "Description that will be used for search engines.<br /> <br />If left empty, it will be generated automatically.",
|
||||
// 'commentEmail' => 'Comment Emails',
|
||||
// 'commentEmailTip' => 'Should the author get emailed whenever a user comments on this guide?',
|
||||
'changelog' => 'Changelog For This Edit',
|
||||
@@ -203,11 +203,11 @@ $lang = array(
|
||||
'testGuide' => 'See how your guide will look',
|
||||
'images' => 'Images',
|
||||
'statusTip' => array(
|
||||
GUIDE_STATUS_DRAFT => 'Your guide is in "Draft" status and you are the only one able to see it. Keep editing it as long as you like, and when you feel it's ready submit it for review.',
|
||||
GUIDE_STATUS_REVIEW => 'Your guide is being reviewed.',
|
||||
GUIDE_STATUS_APPROVED => 'Your guide has been published.',
|
||||
GUIDE_STATUS_REJECTED => 'Your guide has been rejected. After it\'s shortcomings have been remedied you may resubmit it for review.',
|
||||
GUIDE_STATUS_ARCHIVED => 'Your guide is outdated and has been archived. Is will no longer be listed and can\'t be edited.',
|
||||
GuideMgr::STATUS_DRAFT => 'Your guide is in "Draft" status and you are the only one able to see it. Keep editing it as long as you like, and when you feel it's ready submit it for review.',
|
||||
GuideMgr::STATUS_REVIEW => 'Your guide is being reviewed.',
|
||||
GuideMgr::STATUS_APPROVED => 'Your guide has been published.',
|
||||
GuideMgr::STATUS_REJECTED => 'Your guide has been rejected. After it\'s shortcomings have been remedied you may resubmit it for review.',
|
||||
GuideMgr::STATUS_ARCHIVED => 'Your guide is outdated and has been archived. Is will no longer be listed and can\'t be edited.',
|
||||
)
|
||||
),
|
||||
'category' => array(
|
||||
|
||||
@@ -167,20 +167,20 @@ $lang = array(
|
||||
'myGuides' => "Mis Guías",
|
||||
'editTitle' => "Editar tu Guía",
|
||||
'newTitle' => "Crear Nueva Guía",
|
||||
'author' => "Autor",
|
||||
'spec' => "Especialización",
|
||||
'author' => "Autor: ",
|
||||
'spec' => "Especialización: ",
|
||||
'sticky' => "Estado Fijo",
|
||||
'views' => "Visto",
|
||||
'views' => "Visto: ",
|
||||
'patch' => "Parche",
|
||||
'added' => "Añadido",
|
||||
'rating' => "Valoración",
|
||||
'votes' => "[span id=guiderating-value]%d[/span]/5 ([span id=guiderating-votes][n5=%d][/span] Votos) [span id=guiderating][/span]",
|
||||
'added' => "Añadido: ",
|
||||
'rating' => "Valoración: ",
|
||||
'votes' => "[span id=guiderating-value]%.2g[/span]/5 ([span id=guiderating-votes][n5=%d][/span] Votos) [span id=guiderating][/span]",
|
||||
'noVotes' => "necesita más votaciones [span id=guiderating][/span]",
|
||||
'byAuthor' => "Por %s",
|
||||
'notFound' => "Este/a guía no existe.",
|
||||
'clTitle' => 'Historial de cambios para "<a href="?guide=%1$d">%2$s</a>"',
|
||||
'clStatusSet' => 'Estado cambiado a %s',
|
||||
'clCreated' => 'Creado',
|
||||
'clStatusSet' => 'Estado cambiado a %s: ',
|
||||
'clCreated' => 'Creado: ',
|
||||
'clMinorEdit' => 'Modificación menor',
|
||||
'editor' => array(
|
||||
'fullTitle' => 'Título completo',
|
||||
@@ -188,7 +188,7 @@ $lang = array(
|
||||
'name' => 'Nombre',
|
||||
'nameTip' => 'Este debe ser un nombre simple y claro de lo que es la guía, para usar en menús y listas de guías.',
|
||||
'description' => 'Descripción',
|
||||
'descriptionTip' => 'Descripción utilizada para los motores de búsqueda.<br /><br />Si se deja vacío, se generará automáticamente.',
|
||||
'descriptionTip' => 'Descripción utilizada para los motores de búsqueda.<br /><br />Si se deja vacío, se generará automáticamente.',
|
||||
// 'commentEmail' => 'Enviar comentarios por email',
|
||||
// 'commentEmailTip' => '¿El autor debería ser notificado por correo cuando un usuario escriba comentarios en esta guía?',
|
||||
'changelog' => 'Historial de cambios para esta modificación',
|
||||
@@ -203,11 +203,11 @@ $lang = array(
|
||||
'testGuide' => 'Mira el aspecto de tu guía.',
|
||||
'images' => 'Imágenes',
|
||||
'statusTip' => array(
|
||||
GUIDE_STATUS_DRAFT => 'Tu guía está en estado "borrador" y solo tú puedes verla. Tienes todo el tiempo del mundo para editarla y, cuando creas que ya está lista, envíala para su revisión.',
|
||||
GUIDE_STATUS_REVIEW => 'Tu guía está siendo revisada.',
|
||||
GUIDE_STATUS_APPROVED => 'Tu guía ha sido publicada.',
|
||||
GUIDE_STATUS_REJECTED => 'Tu guía ha sido rechazada. Una vez que se hayan corregido las deficiencias, puedes volver a enviarla para revisión.',
|
||||
GUIDE_STATUS_ARCHIVED => 'Tu guía está desactualizada y ha sido archivada. Ya no aparecerá en la lista y no se puede editar.',
|
||||
GuideMgr::STATUS_DRAFT => 'Tu guía está en estado "borrador" y solo tú puedes verla. Tienes todo el tiempo del mundo para editarla y, cuando creas que ya está lista, envíala para su revisión.',
|
||||
GuideMgr::STATUS_REVIEW => 'Tu guía está siendo revisada.',
|
||||
GuideMgr::STATUS_APPROVED => 'Tu guía ha sido publicada.',
|
||||
GuideMgr::STATUS_REJECTED => 'Tu guía ha sido rechazada. Una vez que se hayan corregido las deficiencias, puedes volver a enviarla para revisión.',
|
||||
GuideMgr::STATUS_ARCHIVED => 'Tu guía está desactualizada y ha sido archivada. Ya no aparecerá en la lista y no se puede editar.',
|
||||
)
|
||||
),
|
||||
'category' => array(
|
||||
|
||||
@@ -167,20 +167,20 @@ $lang = array(
|
||||
'myGuides' => "Mes guides",
|
||||
'editTitle' => "Editez votre Guide",
|
||||
'newTitle' => "Créer un nouveau Guide",
|
||||
'author' => "Auteur",
|
||||
'spec' => "Spécialisation",
|
||||
'author' => "Auteur : ",
|
||||
'spec' => "Spécialisation : ",
|
||||
'sticky' => "Statut coller",
|
||||
'views' => "Vues",
|
||||
'views' => "Vues : ",
|
||||
'patch' => "Patch",
|
||||
'added' => "Ajouté",
|
||||
'rating' => "Note",
|
||||
'votes' => "[span id=guiderating-value]%d[/span]/5 ([span id=guiderating-votes][n5=%d][/span] Votes) [span id=guiderating][/span]",
|
||||
'added' => "Ajouté : ",
|
||||
'rating' => "Note : ",
|
||||
'votes' => "[span id=guiderating-value]%.2g[/span]/5 ([span id=guiderating-votes][n5=%d][/span] Votes) [span id=guiderating][/span]",
|
||||
'noVotes' => "pas assez de votes [span id=guiderating][/span]",
|
||||
'byAuthor' => "Par %s",
|
||||
'notFound' => "Ce guide n'existe pas.",
|
||||
'clTitle' => 'Journal des changements pour "<a href="?guide=%1$d">%2$s</a>"',
|
||||
'clStatusSet' => 'Statut défini comme %s',
|
||||
'clCreated' => 'Créé',
|
||||
'clStatusSet' => 'Statut défini comme %s : ',
|
||||
'clCreated' => 'Créé : ',
|
||||
'clMinorEdit' => 'Modification mineure',
|
||||
'editor' => array(
|
||||
'fullTitle' => 'Titre complet',
|
||||
@@ -188,7 +188,7 @@ $lang = array(
|
||||
'name' => 'Nom',
|
||||
'nameTip' => 'Ceci devrait être un nom clair et concis de ce en quoi consiste le guide, qui sera affiché dans les menus et listes de guides.',
|
||||
'description' => 'Description',
|
||||
'descriptionTip' => 'Description qui sera utilisée par les moteurs de recherche.<br /><br />S'il est laissé vide, le résumé sera généré automatiquement.',
|
||||
'descriptionTip' => 'Description qui sera utilisée par les moteurs de recherche.<br /><br />S'il est laissé vide, le résumé sera généré automatiquement.',
|
||||
// 'commentEmail' => 'Recevoir les commentaires par courriel',
|
||||
// 'commentEmailTip' => 'L'auteur doit-il recevoir un courriel chaque fois qu'un utilisateur commente ce guide ?',
|
||||
'changelog' => 'Journal des changements pour cette modification',
|
||||
@@ -203,11 +203,11 @@ $lang = array(
|
||||
'testGuide' => 'Ayez un aperçu de votre guide',
|
||||
'images' => 'Images',
|
||||
'statusTip' => array(
|
||||
GUIDE_STATUS_DRAFT => 'Votre guide est en statut "Brouillon" et vous êtes le seul à pouvoir le lire. Continuez de l'écrire comme vous le voulez, et quand vous sentez qu'il est prêt, soumettez-le pour approbation.',
|
||||
GUIDE_STATUS_REVIEW => 'Your guide is being reviewed.',
|
||||
GUIDE_STATUS_APPROVED => 'Your guide has been published.',
|
||||
GUIDE_STATUS_REJECTED => 'Your guide has been rejected. After it\'s shortcomings have been remedied you may resubmit it for review.',
|
||||
GUIDE_STATUS_ARCHIVED => 'Your guide is outdated and has been archived. Is will no longer be listed and can\'t be edited.',
|
||||
GuideMgr::STATUS_DRAFT => 'Votre guide est en statut "Brouillon" et vous êtes le seul à pouvoir le lire. Continuez de l'écrire comme vous le voulez, et quand vous sentez qu'il est prêt, soumettez-le pour approbation.',
|
||||
GuideMgr::STATUS_REVIEW => 'Your guide is being reviewed.',
|
||||
GuideMgr::STATUS_APPROVED => 'Your guide has been published.',
|
||||
GuideMgr::STATUS_REJECTED => 'Your guide has been rejected. After it\'s shortcomings have been remedied you may resubmit it for review.',
|
||||
GuideMgr::STATUS_ARCHIVED => 'Your guide is outdated and has been archived. Is will no longer be listed and can\'t be edited.',
|
||||
)
|
||||
),
|
||||
'category' => array(
|
||||
|
||||
@@ -167,20 +167,20 @@ $lang = array(
|
||||
'myGuides' => "Мои руководства",
|
||||
'editTitle' => "Редактировать руководство",
|
||||
'newTitle' => "Написать новое руководство",
|
||||
'author' => "Автор",
|
||||
'spec' => "Спек",
|
||||
'author' => "Автор: ",
|
||||
'spec' => "Спек: ",
|
||||
'sticky' => "Закрепленный",
|
||||
'views' => "Просмотры",
|
||||
'views' => "Просмотры: ",
|
||||
'patch' => "Обновление",
|
||||
'added' => "Добавлено",
|
||||
'rating' => "Рейтинг",
|
||||
'votes' => "[span id=guiderating-value]%d[/span]/5 ([span id=guiderating-votes][n5=%d][/span] проголосовало) [span id=guiderating][/span]",
|
||||
'added' => "Добавлено: ",
|
||||
'rating' => "Рейтинг: ",
|
||||
'votes' => "[span id=guiderating-value]%.2g[/span]/5 ([span id=guiderating-votes][n5=%d][/span] проголосовало) [span id=guiderating][/span]",
|
||||
'noVotes' => "недостаточно голосов [span id=guiderating][/span]",
|
||||
'byAuthor' => "От %s",
|
||||
'notFound' => "Такого руководство не существует.",
|
||||
'clTitle' => 'История изменений «<a href="?guide=%1$d">%2$s</a>»',
|
||||
'clStatusSet' => 'Присвоен статус «%s»',
|
||||
'clCreated' => 'Создано',
|
||||
'clStatusSet' => 'Присвоен статус «%s»: ',
|
||||
'clCreated' => 'Создано: ',
|
||||
'clMinorEdit' => 'Небольшое изменение',
|
||||
'editor' => array(
|
||||
'fullTitle' => 'Полный заголовок',
|
||||
@@ -188,7 +188,7 @@ $lang = array(
|
||||
'name' => 'Имя',
|
||||
'nameTip' => 'Укажите краткое и понятное название руководства. Оно будет использоватья в меню и перечнях руководств.',
|
||||
'description' => 'Описание',
|
||||
'descriptionTip' => 'Описание для поисковых систем.<br><br>Если поле будет оставлено пустым, то сайт сгенерирует описание автоматически.',
|
||||
'descriptionTip' => 'Описание для поисковых систем.<br /><br />Если поле будет оставлено пустым, то сайт сгенерирует описание автоматически.',
|
||||
// 'commentEmail' => 'E-mail уведомления',
|
||||
// 'commentEmailTip' => 'Должен ли автор руководства получать e-mail оповещения, когда к руководству оставляют комментарий?',
|
||||
'changelog' => 'История изменений, внесенных этой правкой',
|
||||
@@ -203,11 +203,11 @@ $lang = array(
|
||||
'testGuide' => 'Посмотрите, как будет выглядеть руководство',
|
||||
'images' => 'Images',
|
||||
'statusTip' => array(
|
||||
GUIDE_STATUS_DRAFT => 'Руководство сохранено как "Черновик" — видеть его можете только вы. Правьте руководство так долго, как сочтете нужным, а когда решите, что оно готово — отправьте на одобрение.',
|
||||
GUIDE_STATUS_REVIEW => 'Your guide is being reviewed.',
|
||||
GUIDE_STATUS_APPROVED => 'Your guide has been published.',
|
||||
GUIDE_STATUS_REJECTED => 'Your guide has been rejected. After it\'s shortcomings have been remedied you may resubmit it for review.',
|
||||
GUIDE_STATUS_ARCHIVED => 'Your guide is outdated and has been archived. Is will no longer be listed and can\'t be edited.',
|
||||
GuideMgr::STATUS_DRAFT => 'Руководство сохранено как "Черновик" — видеть его можете только вы. Правьте руководство так долго, как сочтете нужным, а когда решите, что оно готово — отправьте на одобрение.',
|
||||
GuideMgr::STATUS_REVIEW => 'Your guide is being reviewed.',
|
||||
GuideMgr::STATUS_APPROVED => 'Your guide has been published.',
|
||||
GuideMgr::STATUS_REJECTED => 'Your guide has been rejected. After it\'s shortcomings have been remedied you may resubmit it for review.',
|
||||
GuideMgr::STATUS_ARCHIVED => 'Your guide is outdated and has been archived. Is will no longer be listed and can\'t be edited.',
|
||||
)
|
||||
),
|
||||
'category' => array(
|
||||
|
||||
@@ -167,20 +167,20 @@ $lang = array(
|
||||
'myGuides' => "我的指南",
|
||||
'editTitle' => "编辑你的指南",
|
||||
'newTitle' => "创建新指南",
|
||||
'author' => "作者",
|
||||
'spec' => "专精",
|
||||
'author' => "作者:",
|
||||
'spec' => "专精:",
|
||||
'sticky' => "置顶状态",
|
||||
'views' => "浏览量",
|
||||
'views' => "浏览量:",
|
||||
'patch' => "补丁",
|
||||
'added' => "已添加",
|
||||
'rating' => "评分",
|
||||
'votes' => "[span id=guiderating-value]%d[/span]/5 ([span id=guiderating-votes][n5=%d][/span] 投票)[span id=guiderating][/span]",
|
||||
'added' => "已添加:",
|
||||
'rating' => "评分:",
|
||||
'votes' => "[span id=guiderating-value]%.2g[/span]/5 ([span id=guiderating-votes][n5=%d][/span] 投票)[span id=guiderating][/span]",
|
||||
'noVotes' => "投票数量不足 [span id=guiderating][/span]",
|
||||
'byAuthor' => "来自 %s",
|
||||
'notFound' => "该指南不存在。",
|
||||
'clTitle' => '修改日志 "<a href="?guide=%1$d">%2$s</a>"',
|
||||
'clStatusSet' => '状态已设置为 %s',
|
||||
'clCreated' => '已创建',
|
||||
'clStatusSet' => '状态已设置为 %s:',
|
||||
'clCreated' => '已创建:',
|
||||
'clMinorEdit' => '小修改',
|
||||
'editor' => array(
|
||||
'fullTitle' => '完整标题',
|
||||
@@ -188,7 +188,7 @@ $lang = array(
|
||||
'name' => '名称',
|
||||
'nameTip' => '这应该是一个简单明了的指南名称,用于菜单和指南列表',
|
||||
'description' => '描述',
|
||||
'descriptionTip' => '描述将用于说明片段<br /><br />如果不填,则自动生成。',
|
||||
'descriptionTip' => '描述将用于说明片段<br /><br />如果不填,则自动生成。',
|
||||
// 'commentEmail' => '评论电子邮件',
|
||||
// 'commentEmailTip' => '当用户对此指南发表评论时,作者是否收到电子邮件通知?',
|
||||
'changelog' => '当前编辑的修改日志',
|
||||
@@ -203,11 +203,11 @@ $lang = array(
|
||||
'testGuide' => '自我浏览你的指南',
|
||||
'images' => '图片',
|
||||
'statusTip' => array(
|
||||
GUIDE_STATUS_DRAFT => '你的指南目前是草稿状态,只有你自己可见。试着输入更多的文字,当你觉得可以了的时候就提交送审吧。',
|
||||
GUIDE_STATUS_REVIEW => '你的指南正在审核中',
|
||||
GUIDE_STATUS_APPROVED => '你的指南已发布',
|
||||
GUIDE_STATUS_REJECTED => '你的指南已被拒绝。在修正问题后,你可以重新提交审核。',
|
||||
GUIDE_STATUS_ARCHIVED => '你的指南已过时,并已归档。它将不再列出,也无法编辑。',
|
||||
GuideMgr::STATUS_DRAFT => '你的指南目前是草稿状态,只有你自己可见。试着输入更多的文字,当你觉得可以了的时候就提交送审吧。',
|
||||
GuideMgr::STATUS_REVIEW => '你的指南正在审核中',
|
||||
GuideMgr::STATUS_APPROVED => '你的指南已发布',
|
||||
GuideMgr::STATUS_REJECTED => '你的指南已被拒绝。在修正问题后,你可以重新提交审核。',
|
||||
GuideMgr::STATUS_ARCHIVED => '你的指南已过时,并已归档。它将不再列出,也无法编辑。',
|
||||
)
|
||||
),
|
||||
'category' => array(
|
||||
|
||||
@@ -225,7 +225,7 @@ class AdminPage extends GenericPage
|
||||
|
||||
private function handleGuideApprove() : void
|
||||
{
|
||||
$pending = new GuideList([['status', GUIDE_STATUS_REVIEW]]);
|
||||
$pending = new GuideList([['status', GuideMgr::STATUS_REVIEW]]);
|
||||
if ($pending->error)
|
||||
$data = [];
|
||||
else
|
||||
|
||||
549
pages/guide.php
549
pages/guide.php
@@ -1,549 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId ?: Category g_initPath()
|
||||
// tabid 6: Guides g_initHeader()
|
||||
class GuidePage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
|
||||
const SHOW_NEW = 1;
|
||||
const SHOW_EDITOR = 2;
|
||||
const SHOW_GUIDE = 3;
|
||||
const SHOW_CHANGELOG = 4;
|
||||
|
||||
const VALID_URL = '/^[a-z0-9=_&\.\/\-]{2,64}$/i';
|
||||
|
||||
protected /* array */ $guideRating = [];
|
||||
protected /* ?string */$extraHTML = null;
|
||||
|
||||
protected /* int */ $type = Type::GUIDE;
|
||||
protected /* int */ $typeId = 0;
|
||||
protected /* int */ $guideRevision = -1;
|
||||
protected /* string */ $tpl = 'detail-page-generic';
|
||||
protected /* array */ $path = [6];
|
||||
protected /* int */ $tabId = 6;
|
||||
protected /* int */ $mode = CACHE_TYPE_PAGE;
|
||||
protected /* string */ $author = '';
|
||||
protected /* array */ $gPageInfo = [];
|
||||
protected /* int */ $show = self::SHOW_GUIDE;
|
||||
|
||||
private /* array */ $validCats = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
private /* string */ $extra = '';
|
||||
private /* string */ $powerTpl = '$WowheadPower.registerGuide(%s, %d, %s);';
|
||||
private /* array */ $editorFields = [];
|
||||
private /* bool */ $save = false;
|
||||
|
||||
protected /* array */ $_get = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
|
||||
'rev' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt']
|
||||
);
|
||||
|
||||
protected /* array */ $_post = array(
|
||||
'save' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkEmptySet'],
|
||||
'submit' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkEmptySet'],
|
||||
'title' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkTextLine'],
|
||||
'name' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkTextLine'],
|
||||
'description' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GuidePage::checkDescription'],
|
||||
'changelog' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkTextBlob'],
|
||||
'body' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkTextBlob'],
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
|
||||
'category' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
|
||||
'specId' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
|
||||
'classId' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt']
|
||||
);
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
$guide = explode( "&", $pageParam, 2);
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
if (isset($guide[1]) && preg_match(self::VALID_URL, $guide[1]))
|
||||
$this->extra = $guide[1];
|
||||
|
||||
|
||||
/**********************/
|
||||
/* get mode + guideId */
|
||||
/**********************/
|
||||
|
||||
if (Util::checkNumeric($guide[0], NUM_CAST_INT))
|
||||
$this->typeId = $guide[0];
|
||||
else if (preg_match(self::VALID_URL, $guide[0]))
|
||||
{
|
||||
switch ($guide[0])
|
||||
{
|
||||
case 'changelog':
|
||||
if (!$this->_get['id'])
|
||||
break;
|
||||
|
||||
$this->show = self::SHOW_CHANGELOG;
|
||||
$this->tpl = 'text-page-generic';
|
||||
$this->article = false; // do not include article from db
|
||||
|
||||
// main container should be tagged: <div class="text guide-changelog">
|
||||
// why is this here: is there a mediawiki like diff function for staff?
|
||||
$this->addScript([SC_CSS_STRING, 'li input[type="radio"] {margin:0}']);
|
||||
|
||||
$this->typeId = $this->_get['id']; // just to display sensible not-found msg
|
||||
if ($id = DB::Aowow()->selectCell('SELECT `id` FROM ?_guides WHERE `id` = ?d', $this->typeId))
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
break;
|
||||
case 'new':
|
||||
if (User::canWriteGuide())
|
||||
{
|
||||
$this->show = self::SHOW_NEW;
|
||||
$this->guideRevision = null;
|
||||
|
||||
$this->initNew();
|
||||
return; // do not create new GuideList
|
||||
}
|
||||
break;
|
||||
case 'edit':
|
||||
if (User::canWriteGuide())
|
||||
{
|
||||
if (!$this->initEdit())
|
||||
$this->notFound(Lang::game('guide'), Lang::guide('notFound'));
|
||||
|
||||
$this->show = self::SHOW_EDITOR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ($id = DB::Aowow()->selectCell('SELECT `id` FROM ?_guides WHERE `url` = ?', Util::lower($guide[0])))
|
||||
{
|
||||
$this->typeId = intVal($id);
|
||||
$this->guideRevision = null;
|
||||
$this->articleUrl = Util::lower($guide[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* load actual guide */
|
||||
/*********************/
|
||||
|
||||
$this->subject = new GuideList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound(Lang::game('guide'), Lang::guide('notFound'));
|
||||
|
||||
if (!$this->subject->canBeViewed() && !$this->subject->userCanView())
|
||||
header('Location: ?guides='.$this->subject->getField('category'), true, 302);
|
||||
|
||||
if ($this->show == self::SHOW_GUIDE && $this->_get['rev'] !== null && !$this->articleUrl && $this->subject->userCanView())
|
||||
$this->guideRevision = $this->_get['rev'];
|
||||
else if ($this->show == self::SHOW_GUIDE && !$this->articleUrl)
|
||||
$this->guideRevision = $this->subject->getField('rev');
|
||||
else
|
||||
$this->guideRevision = null;
|
||||
|
||||
if (!$this->name)
|
||||
$this->name = $this->subject->getField('name');
|
||||
}
|
||||
|
||||
protected function generateContent() : void
|
||||
{
|
||||
match ($this->show)
|
||||
{
|
||||
self::SHOW_NEW => $this->displayNew(),
|
||||
self::SHOW_EDITOR => $this->displayEditor(),
|
||||
self::SHOW_GUIDE => $this->displayGuide(),
|
||||
self::SHOW_CHANGELOG => $this->displayChangelog(),
|
||||
default => trigger_error('GuidePage::generateContent - what content!?')
|
||||
};
|
||||
}
|
||||
|
||||
private function displayNew() : void
|
||||
{
|
||||
// init required template vars
|
||||
$this->editorFields = array(
|
||||
'locale' => Lang::getLocale()->value,
|
||||
'status' => GUIDE_STATUS_DRAFT
|
||||
);
|
||||
}
|
||||
|
||||
private function displayEditor() : void
|
||||
{
|
||||
// can't check in init as subject is unknown
|
||||
if ($this->subject->getField('status') == GUIDE_STATUS_ARCHIVED)
|
||||
$this->notFound(Lang::game('guide'), Lang::guide('notFound'));
|
||||
|
||||
$status = GUIDE_STATUS_NONE;
|
||||
$rev = DB::Aowow()->selectCell('SELECT `rev` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d ORDER BY `rev` DESC LIMIT 1', Type::GUIDE, $this->typeId);
|
||||
$curStatus = DB::Aowow()->selectCell('SELECT `status` FROM ?_guides WHERE `id` = ?d ', $this->typeId);
|
||||
if ($rev === null)
|
||||
$rev = 0;
|
||||
|
||||
if ($this->save)
|
||||
{
|
||||
$rev++;
|
||||
|
||||
// insert Article
|
||||
DB::Aowow()->query('INSERT INTO ?_articles (`type`, `typeId`, `locale`, `rev`, `editAccess`, `article`) VALUES (?d, ?d, ?d, ?d, ?d, ?)',
|
||||
Type::GUIDE, $this->typeId, $this->_post['locale'], $rev, User::$groups & U_GROUP_STAFF ? User::$groups : User::$groups | U_GROUP_BLOGGER, $this->_post['body']);
|
||||
|
||||
// link to Guide
|
||||
$guideData = array(
|
||||
'category' => $this->_post['category'],
|
||||
'classId' => $this->_post['classId'],
|
||||
'specId' => $this->_post['specId'],
|
||||
'title' => $this->_post['title'],
|
||||
'name' => $this->_post['name'],
|
||||
'description' => $this->_post['description'] ?: Lang::trimTextClean(Markup::stripTags($this->_post['body']), 120),
|
||||
'locale' => $this->_post['locale'],
|
||||
'roles' => User::$groups,
|
||||
'status' => GUIDE_STATUS_DRAFT
|
||||
);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_guides SET ?a WHERE `id` = ?d', $guideData, $this->typeId);
|
||||
|
||||
// new guide -> reload editor
|
||||
if ($this->_get['id'] === 0)
|
||||
header('Location: ?guide=edit&id='.$this->typeId, true, 302);
|
||||
else
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `rev`, `date`, `userId`, `msg`) VALUES (?d, ?d, ?d, ?d, ?)', $this->typeId, $rev, time(), User::$id, $this->_post['changelog']);
|
||||
|
||||
if ($this->_post['submit'])
|
||||
{
|
||||
$status = GUIDE_STATUS_REVIEW;
|
||||
if ($curStatus != GUIDE_STATUS_REVIEW)
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_guides SET `status` = ?d WHERE `id` = ?d', GUIDE_STATUS_REVIEW, $this->typeId);
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `status`) VALUES (?d, ?d, ?d, ?d)', $this->typeId, time(), User::$id, GUIDE_STATUS_REVIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// init required template vars
|
||||
$this->editorFields = array(
|
||||
'category' => $this->_post['category'] ?? $this->subject->getField('category'),
|
||||
'title' => $this->_post['title'] ?? $this->subject->getField('title'),
|
||||
'name' => $this->_post['name'] ?? $this->subject->getField('name'),
|
||||
'description' => $this->_post['description'] ?? $this->subject->getField('description'),
|
||||
'text' => $this->_post['body'] ?? $this->subject->getArticle(),
|
||||
'status' => $status ?: $this->subject->getField('status'),
|
||||
'classId' => $this->_post['classId'] ?? $this->subject->getField('classId'),
|
||||
'specId' => $this->_post['specId'] ?? $this->subject->getField('specId'),
|
||||
'locale' => $this->_post['locale'] ?? $this->subject->getField('locale'),
|
||||
'rev' => $rev
|
||||
);
|
||||
|
||||
$this->extendGlobalData($this->subject->getJSGlobals());
|
||||
}
|
||||
|
||||
private function displayGuide() : void
|
||||
{
|
||||
if (!($this->subject->getField('cuFlags') & GUIDE_CU_NO_QUICKFACTS))
|
||||
{
|
||||
$qf = [];
|
||||
if ($this->subject->getField('cuFlags') & CC_FLAG_STICKY)
|
||||
$qf[] = '[span class=guide-sticky]'.Lang::guide('sticky').'[/span]';
|
||||
|
||||
$qf[] = Lang::guide('author').Lang::main('colon').'[url=?user='.$this->subject->getField('author').']'.$this->subject->getField('author').'[/url]';
|
||||
|
||||
if ($this->subject->getField('category') == 1)
|
||||
{
|
||||
$c = $this->subject->getField('classId');
|
||||
$s = $this->subject->getField('specId');
|
||||
if ($c > 0)
|
||||
{
|
||||
$this->extendGlobalIds(Type::CHR_CLASS, $c);
|
||||
$qf[] = Util::ucFirst(Lang::game('class')).Lang::main('colon').'[class='.$c.']';
|
||||
}
|
||||
if ($s > -1)
|
||||
$qf[] = Lang::guide('spec').Lang::main('colon').'[icon class="c'.$c.' icontiny" name='.Game::$specIconStrings[$c][$s].']'.Lang::game('classSpecs', $c, $s).'[/icon]';
|
||||
}
|
||||
|
||||
// $qf[] = Lang::guide('patch').Lang::main('colon').'3.3.5'; // replace with date
|
||||
$qf[] = Lang::guide('added').Lang::main('colon').'[tooltip name=added]'.date('l, G:i:s', $this->subject->getField('date')).'[/tooltip][span class=tip tooltip=added]'.date(Lang::main('dateFmtShort'), $this->subject->getField('date')).'[/span]';
|
||||
|
||||
switch ($this->subject->getField('status'))
|
||||
{
|
||||
case GUIDE_STATUS_APPROVED:
|
||||
$qf[] = Lang::guide('views').Lang::main('colon').'[n5='.$this->subject->getField('views').']';
|
||||
|
||||
if (!($this->subject->getField('cuFlags') & GUIDE_CU_NO_RATING))
|
||||
{
|
||||
$this->guideRating = array(
|
||||
$this->subject->getField('rating'), // avg rating
|
||||
User::canUpvote() && User::canDownvote() ? 'true' : 'false',
|
||||
$this->subject->getField('_self'), // my rating amt; 0 = no vote
|
||||
$this->typeId // guide Id
|
||||
);
|
||||
|
||||
if ($this->subject->getField('nvotes') < 5)
|
||||
$qf[] = Lang::guide('rating').Lang::main('colon').Lang::guide('noVotes');
|
||||
else
|
||||
$qf[] = Lang::guide('rating').Lang::main('colon').Lang::guide('votes', [round($this->subject->getField('rating'), 1), $this->subject->getField('nvotes')]);
|
||||
}
|
||||
break;
|
||||
case GUIDE_STATUS_ARCHIVED:
|
||||
$qf[] = Lang::guide('status', GUIDE_STATUS_ARCHIVED);
|
||||
break;
|
||||
}
|
||||
|
||||
$qf = '[ul][li]'.implode('[/li][li]', $qf).'[/li][/ul]';
|
||||
|
||||
if ($this->subject->getField('status') == GUIDE_STATUS_REVIEW && User::isInGroup(U_GROUP_STAFF) && $this->_get['rev'])
|
||||
{
|
||||
$this->addScript([SC_JS_STRING, '
|
||||
DomContentLoaded.addEvent(function() {
|
||||
let send = function (status)
|
||||
{
|
||||
let message = "";
|
||||
let id = $WH.g_getGets().guide;
|
||||
if (status == 4) // rejected
|
||||
{
|
||||
while (message === "")
|
||||
message = prompt("Please provide your reasoning.");
|
||||
|
||||
if (message === null)
|
||||
return false;
|
||||
}
|
||||
|
||||
$.ajax({cache: false, url: "?admin=guide", type: "POST",
|
||||
error: function() {
|
||||
alert("Operation failed.");
|
||||
},
|
||||
success: function(json) {
|
||||
if (json != 1)
|
||||
alert("Operation failed.");
|
||||
else
|
||||
window.location.href = "?admin=guides";
|
||||
},
|
||||
data: { id: id, status: status, msg: message }
|
||||
})
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
$WH.ge("btn-accept").onclick = send.bind(null, 3);
|
||||
$WH.ge("btn-reject").onclick = send.bind(null, 4);
|
||||
});
|
||||
']);
|
||||
|
||||
$qf .= '[h3 style="text-align:center"]Admin[/h3]';
|
||||
|
||||
$qf .= '[div style="text-align:center"][url=# id="btn-accept" class=icon-tick]Approve[/url][url=# style="margin-left:20px" id="btn-reject" class=icon-delete]Reject[/url][/div]';
|
||||
}
|
||||
}
|
||||
|
||||
$this->redButtons[BUTTON_GUIDE_LOG] = true;
|
||||
$this->redButtons[BUTTON_GUIDE_REPORT] = $this->subject->canBeReported();
|
||||
|
||||
$this->infobox = $qf ?? '';
|
||||
$this->author = $this->subject->getField('author'); // add to g_pageInfo in GenericPage:prepareContent()
|
||||
|
||||
if ($this->subject->userCanView())
|
||||
$this->redButtons[BUTTON_GUIDE_EDIT] = User::canWriteGuide() && $this->subject->getField('status') != GUIDE_STATUS_ARCHIVED;
|
||||
|
||||
// the article text itself is added by GenericPage::addArticle()
|
||||
}
|
||||
|
||||
private function displayChangelog() : void
|
||||
{
|
||||
$this->addScript([SC_JS_STRING, '
|
||||
$(document).ready(function() {
|
||||
var radios = $("input[type=radio]");
|
||||
function limit(col, val) {
|
||||
radios.each(function(i, e) {
|
||||
if (col == e.name)
|
||||
return;
|
||||
|
||||
if (col == "b")
|
||||
e.disabled = (val <= parseInt(e.value));
|
||||
else if (col == "a")
|
||||
e.disabled = (val >= parseInt(e.value));
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
radios.each(function (i, e) {
|
||||
e.onchange = limit.bind(this, e.name, parseInt(e.value));
|
||||
|
||||
if (i < 2 && e.name == "b") // first pair
|
||||
$(e).trigger("click");
|
||||
else if (e.value == 0 && e.name == "a") // last pair
|
||||
$(e).trigger("click");
|
||||
});
|
||||
});
|
||||
']);
|
||||
|
||||
$buff = '<ul>';
|
||||
$inp = fn($rev) => User::isInGroup(U_GROUP_STAFF) ? ($rev !== null ? '<input name="a" value="'.$rev.'" type="radio"/><input name="b" value="'.$rev.'" type="radio"/><b>' : '<b style="margin-left:28px;">') : '';
|
||||
|
||||
$logEntries = DB::Aowow()->select('SELECT a.`username` AS `name`, gcl.`date`, gcl.`status`, gcl.`msg`, gcl.`rev` FROM ?_guides_changelog gcl JOIN ?_account a ON a.`id` = gcl.`userId` WHERE gcl.`id` = ?d ORDER BY gcl.`date` DESC', $this->typeId);
|
||||
foreach ($logEntries as $log)
|
||||
{
|
||||
if ($log['status'] != GUIDE_STATUS_NONE)
|
||||
$buff .= '<li class="guide-changelog-status-change">'.$inp($log['rev']).Lang::guide('clStatusSet', [Lang::guide('status', $log['status'])]).Lang::main('colon').'</b>'.Util::formatTimeDiff($log['date'])."</li>\n";
|
||||
else if ($log['msg'])
|
||||
$buff .= '<li>'.$inp($log['rev']).Util::formatTimeDiff($log['date']).Lang::main('colon').'</b>'.$log['msg'].' <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
else
|
||||
$buff .= '<li class="guide-changelog-minor-edit">'.$inp($log['rev']).Util::formatTimeDiff($log['date']).Lang::main('colon').'</b><i>'.Lang::guide('clMinorEdit').'</i> <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
}
|
||||
|
||||
// append creation
|
||||
$buff .= '<li class="guide-changelog-created">'.$inp(0).'<b>'.Lang::guide('clCreated').Lang::main('colon').'</b>'.Util::formatTimeDiff($this->subject->getField('date'))."</li>\n</ul>\n";
|
||||
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
$buff .= '<input type="button" value="Compare" onclick="alert(\'NYI\');"/>';
|
||||
|
||||
$this->name = lang::guide('clTitle', [$this->typeId, $this->subject->getField('title')]);
|
||||
$this->extraHTML = $buff;
|
||||
}
|
||||
|
||||
private function initNew() : void
|
||||
{
|
||||
$this->addScript(
|
||||
[SC_JS_FILE, 'js/article-description.js'],
|
||||
[SC_JS_FILE, 'js/article-editing.js'],
|
||||
[SC_JS_FILE, 'js/guide-editing.js'],
|
||||
[SC_JS_FILE, 'js/fileuploader.js'],
|
||||
[SC_JS_FILE, 'js/toolbar.js'],
|
||||
[SC_JS_FILE, 'js/AdjacentPreview.js'],
|
||||
[SC_CSS_FILE, 'css/article-editing.css'],
|
||||
[SC_CSS_FILE, 'css/fileuploader.css'],
|
||||
[SC_CSS_FILE, 'css/guide-edit.css'],
|
||||
[SC_CSS_FILE, 'css/AdjacentPreview.css'],
|
||||
|
||||
[SC_CSS_STRING, '#upload-result input[type=text] { padding: 0px 2px; font-size: 12px; }'],
|
||||
[SC_CSS_STRING, '#upload-result > span { display:block; height: 22px; }'],
|
||||
[SC_CSS_STRING, '#upload-result { display: inline-block; text-align:right; }'],
|
||||
[SC_CSS_STRING, '#upload-progress { display: inline-block; margin-right:8px; }']
|
||||
);
|
||||
|
||||
$this->articleUrl = 'new';
|
||||
$this->tpl = 'guide-edit';
|
||||
$this->name = Lang::guide('newTitle');
|
||||
|
||||
Lang::sort('guide', 'category');
|
||||
|
||||
$this->typeId = 0; // signals 'edit' to create new guide
|
||||
}
|
||||
|
||||
private function initEdit() : bool
|
||||
{
|
||||
$this->addScript(
|
||||
[SC_JS_FILE, 'js/article-description.js'],
|
||||
[SC_JS_FILE, 'js/article-editing.js'],
|
||||
[SC_JS_FILE, 'js/guide-editing.js'],
|
||||
[SC_JS_FILE, 'js/fileuploader.js'],
|
||||
[SC_JS_FILE, 'js/toolbar.js'],
|
||||
[SC_JS_FILE, 'js/AdjacentPreview.js'],
|
||||
[SC_CSS_FILE, 'css/article-editing.css'],
|
||||
[SC_CSS_FILE, 'css/fileuploader.css'],
|
||||
[SC_CSS_FILE, 'css/guide-edit.css'],
|
||||
[SC_CSS_FILE, 'css/AdjacentPreview.css'],
|
||||
|
||||
[SC_CSS_STRING, '#upload-result input[type=text] { padding: 0px 2px; font-size: 12px; }'],
|
||||
[SC_CSS_STRING, '#upload-result > span { display:block; height: 22px; }'],
|
||||
[SC_CSS_STRING, '#upload-result { display: inline-block; text-align:right; }'],
|
||||
[SC_CSS_STRING, '#upload-progress { display: inline-block; margin-right:8px; }']
|
||||
);
|
||||
|
||||
$this->articleUrl = 'edit';
|
||||
$this->tpl = 'guide-edit';
|
||||
$this->name = Lang::guide('editTitle');
|
||||
$this->save = $this->_post['save'] || $this->_post['submit'];
|
||||
|
||||
// reject inconsistent guide data
|
||||
if ($this->save)
|
||||
{
|
||||
// req: set data
|
||||
if (!$this->_post['title'] || !$this->_post['name'] || !$this->_post['body'] || $this->_post['locale'] === null)
|
||||
return false;
|
||||
|
||||
// req: valid data
|
||||
if (!in_array($this->_post['category'], $this->validCats) || !(Cfg::get('LOCALES') & (1 << $this->_post['locale'])))
|
||||
return false;
|
||||
|
||||
// sanitize: spec / class
|
||||
if ($this->_post['category'] == 1) // Classes
|
||||
{
|
||||
if ($this->_post['classId'] && !ChrClass::tryFrom($this->_post['classId']))
|
||||
$this->_post['classId'] = 0;
|
||||
|
||||
if (!in_array($this->_post['specId'], [-1, 0, 1, 2]))
|
||||
$this->_post['specId'] = -1;
|
||||
if ($this->_post['specId'] > -1 && !$this->_post['classId'])
|
||||
$this->_post['specId'] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_post['classId'] = 0;
|
||||
$this->_post['specId'] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_get['id']) // edit existing guide
|
||||
{
|
||||
$this->typeId = $this->_get['id']; // just to display sensible not-found msg
|
||||
if ($id = DB::Aowow()->selectCell('SELECT `id` FROM ?_guides WHERE `id` = ?d AND `status` <> ?d {AND `userId` = ?d}', $this->typeId, GUIDE_STATUS_ARCHIVED, User::isInGroup(U_GROUP_STAFF) ? DBSIMPLE_SKIP : User::$id))
|
||||
$this->typeId = intVal($id);
|
||||
}
|
||||
else if ($this->_get['id'] === 0) // create new guide and load in editor
|
||||
$this->typeId = DB::Aowow()->query('INSERT INTO ?_guides (`userId`, `date`, `status`) VALUES (?d, ?d, ?d)', User::$id, time(), GUIDE_STATUS_DRAFT);
|
||||
|
||||
return $this->typeId > 0;
|
||||
}
|
||||
|
||||
protected function editorFields(string $field, bool $asInt = false) : string|int
|
||||
{
|
||||
return $this->editorFields[$field] ?? ($asInt ? 0 : '');
|
||||
}
|
||||
|
||||
protected function generateTooltip()
|
||||
{
|
||||
$power = new \StdClass();
|
||||
if (!$this->subject->error)
|
||||
{
|
||||
$power->{'name_'.Lang::getLocale()->json()} = strip_tags($this->name);
|
||||
$power->{'tooltip_'.Lang::getLocale()->json()} = $this->subject->renderTooltip();
|
||||
}
|
||||
|
||||
return sprintf($this->powerTpl, Util::toJSON($this->articleUrl ?: $this->typeId), Lang::getLocale()->value, Util::toJSON($power, JSON_AOWOW_POWER));
|
||||
}
|
||||
|
||||
protected function generatePath() : void
|
||||
{
|
||||
if ($x = $this->subject?->getField('category'))
|
||||
$this->path[] = $x;
|
||||
}
|
||||
|
||||
protected function generateTitle() : void
|
||||
{
|
||||
if ($this->show == self::SHOW_EDITOR)
|
||||
array_unshift($this->title, Lang::guide('editTitle').Lang::main('colon').$this->subject->getField('title'), Lang::game('guides'));
|
||||
if ($this->show == self::SHOW_NEW)
|
||||
array_unshift($this->title, Lang::guide('newTitle'), Lang::game('guides'));
|
||||
else
|
||||
array_unshift($this->title, $this->subject->getField('title'), Lang::game('guides'));
|
||||
}
|
||||
|
||||
protected function postCache() : void
|
||||
{
|
||||
// increment views of published guide; ignore caching
|
||||
if ($this->subject?->getField('status') == GUIDE_STATUS_APPROVED)
|
||||
DB::Aowow()->query('UPDATE ?_guides SET `views` = `views` + 1 WHERE `id` = ?d', $this->typeId);
|
||||
}
|
||||
|
||||
protected static function checkDescription(string $str) : string
|
||||
{
|
||||
// run checkTextBlob and also replace \n => \s and \s+ => \s
|
||||
$str = preg_replace(parent::PATTERN_TEXT_BLOB, '', $str);
|
||||
|
||||
$str = strtr($str, ["\n" => ' ', "\r" => ' ']);
|
||||
|
||||
return preg_replace('/\s+/', ' ', trim($str));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
102
pages/guides.php
102
pages/guides.php
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId ?:Category g_initPath()
|
||||
// tabid 6:Guides g_initHeader()
|
||||
class GuidesPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
|
||||
protected $type = Type::GUIDE;
|
||||
protected $tpl = 'list-page-generic';
|
||||
protected $path = [6];
|
||||
protected $tabId = 6;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
protected $validCats = [null, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
private $myGuides = false;
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
if ($pageCall == 'my-guides')
|
||||
{
|
||||
if (!User::isLoggedIn())
|
||||
$this->error();
|
||||
|
||||
$this->name = Util::ucFirst(Lang::guide('myGuides'));
|
||||
$this->myGuides = true;
|
||||
}
|
||||
else
|
||||
$this->name = Util::ucFirst(Lang::game('guides'));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$hCols = ['patch']; // pointless: display date instead
|
||||
$vCols = [];
|
||||
$xCols = ['$Listview.extraCols.date']; // ok
|
||||
|
||||
if ($this->myGuides)
|
||||
{
|
||||
$conditions = [['userId', User::$id]];
|
||||
$hCols[] = 'author';
|
||||
$vCols[] = 'status';
|
||||
}
|
||||
else
|
||||
{
|
||||
$conditions = array(
|
||||
['locale', Lang::getLocale()->value],
|
||||
['status', GUIDE_STATUS_ARCHIVED, '!'], // never archived guides
|
||||
[
|
||||
'OR',
|
||||
['status', GUIDE_STATUS_APPROVED], // currently approved
|
||||
['rev', 0, '>'] // has previously approved revision
|
||||
]
|
||||
);
|
||||
if (isset($this->category[0]))
|
||||
$conditions[] = ['category', $this->category];
|
||||
}
|
||||
|
||||
$data = [];
|
||||
$guides = new GuideList($conditions);
|
||||
if (!$guides->error)
|
||||
$data = array_values($guides->getListviewData());
|
||||
|
||||
$tabData = array(
|
||||
'data' => $data,
|
||||
'name' => Util::ucFirst(Lang::game('guides')),
|
||||
'hiddenCols' => $hCols,
|
||||
'visibleCols' => $vCols,
|
||||
'extraCols' => $xCols
|
||||
);
|
||||
|
||||
$this->lvTabs[] = [GuideList::$brickFile, $tabData];
|
||||
|
||||
$this->redButtons = [BUTTON_GUIDE_NEW => User::canWriteGuide()];
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, $this->name);
|
||||
if (isset($this->category[0]))
|
||||
array_unshift($this->title, Lang::guide('category', $this->category[0]));
|
||||
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
if (isset($this->category[0]))
|
||||
$this->path[] = $this->category[0];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -22987,17 +22987,14 @@ function g_modifyUrl(url, params, opt) {
|
||||
}
|
||||
|
||||
function g_enhanceTextarea (ta, opt) {
|
||||
if (!(ta instanceof jQuery)) {
|
||||
if (!(ta instanceof jQuery))
|
||||
ta = $(ta);
|
||||
}
|
||||
|
||||
if (ta.data("wh-enhanced") || ta.prop("tagName") != "TEXTAREA") {
|
||||
if (ta.data("wh-enhanced") || ta.prop("tagName") != "TEXTAREA")
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof opt != "object") {
|
||||
if (typeof opt != "object")
|
||||
opt = {};
|
||||
}
|
||||
|
||||
var canResize = (function(el) {
|
||||
if (!el.dynamicResizeOption)
|
||||
@@ -23016,63 +23013,66 @@ function g_enhanceTextarea (ta, opt) {
|
||||
var wrapper = $("<div/>", { "class": "enhanced-textarea-wrapper" }).insertBefore(ta).append(ta);
|
||||
|
||||
if (!opt.hasOwnProperty("color"))
|
||||
wrapper.addClass("enhanced-textarea-dark")
|
||||
wrapper.addClass("enhanced-textarea-dark");
|
||||
else if (opt.color)
|
||||
wrapper.addClass("enhanced-textarea-" + opt.color)
|
||||
wrapper.addClass("enhanced-textarea-" + opt.color);
|
||||
|
||||
if (!opt.hasOwnProperty("dynamicSizing") || opt.dynamicSizing || opt.dynamicResizeOption) {
|
||||
var expander = $("<div/>", { "class": "enhanced-textarea-expander" }).prependTo(wrapper);
|
||||
var n = function(E, D, F) {
|
||||
if (!F())
|
||||
var dynamicResize = function(textarea, exactHeight, canResizeFn) {
|
||||
if (!canResizeFn())
|
||||
return;
|
||||
|
||||
// E.css("height", E.siblings(".enhanced-textarea-expander").html($WH.htmlentities(E.val()).replace(/\n/g, "<br>") + "<br>").height() + (D ? 14 : 34) + "px")
|
||||
E.css("height", E.siblings(".enhanced-textarea-expander").html($WH.htmlentities(E.val()) + "<br>").height() + (D ? 14 : 34) + "px")
|
||||
// E.css("height", E.siblings(".enhanced-textarea-expander").html($WH.htmlentities(E.val()).replace(/\n/g, "<br>") + "<br>").height() + (D ? 14 : 34) + "px");
|
||||
textarea.css("height", textarea.siblings(".enhanced-textarea-expander").html($WH.htmlentities(textarea.val()) + "<br>").height() + (exactHeight ? 14 : 34) + "px");
|
||||
};
|
||||
|
||||
ta.bind("keydown keyup change", n.bind(this, ta, opt.exactLineHeights, canResize));
|
||||
n(ta, opt.exactLineHeights, canResize);
|
||||
var setWidth = function(D) {
|
||||
D.css("width", D.parent().width() + "px")
|
||||
};
|
||||
ta.bind("keydown keyup change", dynamicResize.bind(this, ta, opt.exactLineHeights, canResize));
|
||||
dynamicResize(ta, opt.exactLineHeights, canResize);
|
||||
|
||||
var setWidth = function(el) { el.css("width", el.parent().width() + "px"); };
|
||||
|
||||
setWidth(expander);
|
||||
setTimeout(setWidth.bind(null, expander), 1);
|
||||
if (!opt.dynamicResizeOption || (opt.dynamicResizeOption && canResize())) {
|
||||
wrapper.addClass("enhanced-textarea-dynamic-sizing")
|
||||
}
|
||||
}
|
||||
if (!opt.hasOwnProperty("focusChanges") || opt.focusChanges) {
|
||||
wrapper.addClass("enhanced-textarea-focus-changes")
|
||||
|
||||
if (!opt.dynamicResizeOption || (opt.dynamicResizeOption && canResize()))
|
||||
wrapper.addClass("enhanced-textarea-dynamic-sizing");
|
||||
}
|
||||
|
||||
if (!opt.hasOwnProperty("focusChanges") || opt.focusChanges)
|
||||
wrapper.addClass("enhanced-textarea-focus-changes");
|
||||
|
||||
if (opt.markup) {
|
||||
var w = $("<div/>", { "class": "enhanced-textarea-markup-wrapper" }).prependTo(wrapper);
|
||||
var y = $("<div/>", { "class": "enhanced-textarea-markup" }).appendTo(w);
|
||||
var z = $("<div/>", { "class": "enhanced-textarea-markup-segment" }).appendTo(y);
|
||||
var k = $("<div/>", { "class": "enhanced-textarea-markup-segment" }).appendTo(y);
|
||||
var _markupMenu = $("<div/>", { "class": "enhanced-textarea-markup-wrapper" }).prependTo(wrapper);
|
||||
var _segments = $("<div/>", { "class": "enhanced-textarea-markup" }).appendTo(_markupMenu);
|
||||
var _toolbar = $("<div/>", { "class": "enhanced-textarea-markup-segment" }).appendTo(_segments);
|
||||
var _menu = $("<div/>", { "class": "enhanced-textarea-markup-segment" }).appendTo(_segments);
|
||||
|
||||
if (opt.markup == "inline")
|
||||
ar_AddInlineToolbar(ta.get(0), z.get(0), k.get(0));
|
||||
ar_AddInlineToolbar(ta.get(0), _toolbar.get(0), _menu.get(0));
|
||||
else
|
||||
ar_AddToolbar(ta.get(0), z.get(0), k.get(0));
|
||||
ar_AddToolbar(ta.get(0), _toolbar.get(0), _menu.get(0));
|
||||
|
||||
if (opt.dynamicResizeOption) {
|
||||
var t = $("<div/>", { "class": "enhanced-textarea-markup-segment" }).appendTo(y);
|
||||
var C = $("<label/>").appendTo(t);
|
||||
var A = $("<input/>", { type: "checkbox", checked: canResize() }).appendTo(C);
|
||||
A.change((function(E, D, H, J, F, G) {
|
||||
var I = this.is(":checked");
|
||||
$WH.localStorage.set("dynamic-textarea-resizing", JSON.stringify(I));
|
||||
if (I) {
|
||||
D.addClass("enhanced-textarea-dynamic-sizing");
|
||||
G(H, E.exactLineHeights, J);
|
||||
var _dynResize = $("<div/>", { "class": "enhanced-textarea-markup-segment" }).appendTo(_segments);
|
||||
var _lblDynResize = $("<label/>").appendTo(_dynResize);
|
||||
var _iDynResize = $("<input/>", { type: "checkbox", checked: canResize() }).appendTo(_lblDynResize);
|
||||
|
||||
_iDynResize.change((function(_opt, taWrapper, textarea, resizable, areaHeight, dynResizeFn) {
|
||||
var isChecked = this.is(":checked");
|
||||
|
||||
$WH.localStorage.set("dynamic-textarea-resizing", JSON.stringify(isChecked));
|
||||
if (isChecked) {
|
||||
taWrapper.addClass("enhanced-textarea-dynamic-sizing");
|
||||
dynResizeFn(textarea, _opt.exactLineHeights, resizable);
|
||||
}
|
||||
else {
|
||||
D.removeClass("enhanced-textarea-dynamic-sizing");
|
||||
H.css("height", F + "px");
|
||||
taWrapper.removeClass("enhanced-textarea-dynamic-sizing");
|
||||
textarea.css("height", areaHeight + "px");
|
||||
}
|
||||
}).bind(A, opt, wrapper, ta, canResize, height, n));
|
||||
}).bind(_iDynResize, opt, wrapper, ta, canResize, height, dynamicResize));
|
||||
|
||||
$("<span/>", { text: LANG.autoresizetextbox }).appendTo(C);
|
||||
$("<span/>", { text: LANG.autoresizetextbox }).appendTo(_lblDynResize);
|
||||
}
|
||||
|
||||
if (opt.scrollingMarkup) {
|
||||
@@ -23081,40 +23081,47 @@ function g_enhanceTextarea (ta, opt) {
|
||||
else
|
||||
g_enhanceTextarea.scrollerCount = 1;
|
||||
|
||||
var B = "fixable-markup-controls-" + g_enhanceTextarea.scrollerCount;
|
||||
var o = "fixed-markup-controls-" + g_enhanceTextarea.scrollerCount;
|
||||
var setBGColor = function(el) {
|
||||
var cssClassA = "fixable-markup-controls-" + g_enhanceTextarea.scrollerCount;
|
||||
var cssClassB = "fixed-markup-controls-" + g_enhanceTextarea.scrollerCount;
|
||||
|
||||
var getBGColor = function(el) {
|
||||
var color = el.css("backgroundColor");
|
||||
if (color == "rgba(0, 0, 0, 0)" || color == "transparent")
|
||||
return setBGColor(el.parent());
|
||||
return getBGColor(el.parent());
|
||||
else
|
||||
return color;
|
||||
};
|
||||
var r = setBGColor(y);
|
||||
for (var m, l = 0;
|
||||
(m = window.document.styleSheets[l]) && m.href; l++) {}
|
||||
if (!m) {
|
||||
|
||||
var bgColor = getBGColor(_segments);
|
||||
|
||||
for (var css, i = 0; (css = window.document.styleSheets[i]) && css.href; i++) {}
|
||||
if (!css) {
|
||||
window.document.head.appendChild(document.createElement("style"));
|
||||
m = window.document.styleSheets[l];
|
||||
css = window.document.styleSheets[i];
|
||||
}
|
||||
m.insertRule("." + o + " ." + B + " .enhanced-textarea-markup {background:" + r + ";padding-bottom:5px;padding-top:10px;position:fixed;top:0;z-index:3}", m.cssRules.length);
|
||||
m.insertRule(".touch-device ." + o + " ." + B + " .enhanced-textarea-markup {padding-top:50px}", m.cssRules.length);
|
||||
w.addClass(B);
|
||||
var s = function(F, D, cssClass, offset) {
|
||||
var H = this.scrollY || this.pageYOffset || 0;
|
||||
if (H > F.offset().top - 10 - offset && H < D.offset().top + D.height() - 100 - offset)
|
||||
css.insertRule("." + cssClassB + " ." + cssClassA + " .enhanced-textarea-markup {background:" + bgColor + ";padding-bottom:5px;padding-top:10px;position:fixed;top:0;z-index:3}", css.cssRules.length);
|
||||
css.insertRule(".touch-device ." + cssClassB + " ." + cssClassA + " .enhanced-textarea-markup {padding-top:50px}", css.cssRules.length);
|
||||
|
||||
_markupMenu.addClass(cssClassA);
|
||||
|
||||
var toggleFixedStyles = function(menuContainer, taContainer, cssClass, offset) {
|
||||
var pageY = this.scrollY || this.pageYOffset || 0;
|
||||
if (pageY > menuContainer.offset().top - 10 - offset && pageY < taContainer.offset().top + taContainer.height() - 100 - offset)
|
||||
$("body").addClass(cssClass);
|
||||
else
|
||||
$("body").removeClass(cssClass);
|
||||
};
|
||||
|
||||
$(window).scroll(s.bind(window, w, wrapper, o, 0));
|
||||
s.call(window, w, wrapper, o, 0);
|
||||
$(window).scroll(toggleFixedStyles.bind(window, _markupMenu, wrapper, cssClassB, 0));
|
||||
toggleFixedStyles.call(window, _markupMenu, wrapper, cssClassB, 0);
|
||||
|
||||
var setSize = (function(D, E) {
|
||||
E.css("width", D.width() + "px");
|
||||
D.css("height", E.height() + "px");
|
||||
}).bind(null, w, y);
|
||||
}).bind(null, _markupMenu, _segments);
|
||||
|
||||
setSize();
|
||||
|
||||
$(window).on("resize", setSize);
|
||||
$(function() { setTimeout(setSize, 2000) })
|
||||
}
|
||||
@@ -23139,119 +23146,123 @@ $WH.createOptionsMenuWidget = function (id, txt, opt) {
|
||||
if (opt.className)
|
||||
container.className += ' ' + opt.className;
|
||||
|
||||
if (opt.options instanceof Array) {
|
||||
var c = [];
|
||||
for (var itr = 0, d; d = opt.options[itr]; itr++) {
|
||||
var menu = [itr, d[MENU_IDX_NAME]];
|
||||
if ((typeof opt.selected == 'number' || typeof opt.selected == 'string') && opt.selected == d[MENU_IDX_ID]) {
|
||||
container.innerHTML = d[MENU_IDX_NAME] + chevron;
|
||||
if (d[MENU_IDX_SUB]) {
|
||||
switch (typeof d[MENU_IDX_SUB].className) {
|
||||
if (opt.options instanceof Array) {
|
||||
var widgetmenu = [];
|
||||
for (var itr = 0, submenu; submenu = opt.options[itr]; itr++) {
|
||||
var menu = [itr, submenu[MENU_IDX_NAME]];
|
||||
|
||||
if ((typeof opt.selected == 'number' || typeof opt.selected == 'string') && opt.selected == submenu[MENU_IDX_ID]) {
|
||||
container.innerHTML = submenu[MENU_IDX_NAME] + chevron;
|
||||
if (submenu[MENU_IDX_SUB]) {
|
||||
switch (typeof submenu[MENU_IDX_SUB].className) {
|
||||
case 'string':
|
||||
$.data(container, 'options-menu-widget-class', d[MENU_IDX_SUB].className);
|
||||
container.className += ' ' + d[MENU_IDX_SUB].className;
|
||||
$.data(container, 'options-menu-widget-class', submenu[MENU_IDX_SUB].className);
|
||||
container.className += ' ' + submenu[MENU_IDX_SUB].className;
|
||||
break;
|
||||
case 'function':
|
||||
$.data(container, 'options-menu-widget-class', d[MENU_IDX_SUB].className(d, true));
|
||||
container.className += ' ' + d[MENU_IDX_SUB].className(d, true);
|
||||
break
|
||||
$.data(container, 'options-menu-widget-class', submenu[MENU_IDX_SUB].className(submenu, true));
|
||||
container.className += ' ' + submenu[MENU_IDX_SUB].className(submenu, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d[MENU_IDX_URL]) {
|
||||
menu.push(function (chevron, container, i, opt) {
|
||||
switch (typeof i[MENU_IDX_URL]) {
|
||||
|
||||
if (submenu[MENU_IDX_URL]) {
|
||||
menu.push(function (chevron, container, submenu, opt) {
|
||||
switch (typeof submenu[MENU_IDX_URL]) {
|
||||
case 'string':
|
||||
window.location = i[MENU_IDX_URL];
|
||||
window.location = submenu[MENU_IDX_URL];
|
||||
break;
|
||||
case 'function':
|
||||
if (typeof opt.updateWidgetText == 'undefined' || opt.updateWidgetText) {
|
||||
container.innerHTML = i[MENU_IDX_NAME] + chevron;
|
||||
container.innerHTML = submenu[MENU_IDX_NAME] + chevron;
|
||||
|
||||
var o = $.data(container, 'options-menu-widget-class');
|
||||
if (o)
|
||||
container.className = container.className.replace(new RegExp(' *\\b' + o + '\\b'), '');
|
||||
|
||||
if (i[MENU_IDX_SUB]) {
|
||||
switch (typeof i[MENU_IDX_SUB].className) {
|
||||
if (submenu[MENU_IDX_SUB]) {
|
||||
switch (typeof submenu[MENU_IDX_SUB].className) {
|
||||
case 'string':
|
||||
$.data(container, 'options-menu-widget-class', i[MENU_IDX_SUB].className);
|
||||
container.className += ' ' + i[MENU_IDX_SUB].className;
|
||||
$.data(container, 'options-menu-widget-class', submenu[MENU_IDX_SUB].className);
|
||||
container.className += ' ' + submenu[MENU_IDX_SUB].className;
|
||||
break;
|
||||
case 'function':
|
||||
$.data(container, 'options-menu-widget-class', i[MENU_IDX_SUB].className(i, true));
|
||||
container.className += ' ' + i[MENU_IDX_SUB].className(i, true);
|
||||
$.data(container, 'options-menu-widget-class', submenu[MENU_IDX_SUB].className(submenu, true));
|
||||
container.className += ' ' + submenu[MENU_IDX_SUB].className(submenu, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i[MENU_IDX_URL](container, i);
|
||||
submenu[MENU_IDX_URL](container, submenu);
|
||||
break;
|
||||
}
|
||||
}.bind(null, chevron, Menu.add, d, opt))
|
||||
}.bind(null, chevron, Menu.add, submenu, opt))
|
||||
}
|
||||
else if (!d[MENU_IDX_SUB] || !d[MENU_IDX_SUB].menu)
|
||||
else if (!submenu[MENU_IDX_SUB] || !submenu[MENU_IDX_SUB].menu)
|
||||
menu[0] = null;
|
||||
|
||||
menu[MENU_IDX_OPT] = {};
|
||||
if (d[MENU_IDX_SUB]) {
|
||||
switch (typeof d[MENU_IDX_SUB].className) {
|
||||
if (submenu[MENU_IDX_SUB]) {
|
||||
switch (typeof submenu[MENU_IDX_SUB].className) {
|
||||
case 'string':
|
||||
menu[MENU_IDX_OPT].className = d[MENU_IDX_SUB].className;
|
||||
menu[MENU_IDX_OPT].className = submenu[MENU_IDX_SUB].className;
|
||||
break;
|
||||
case 'function':
|
||||
menu[MENU_IDX_OPT].className = d[MENU_IDX_SUB].className.bind(null, d, false);
|
||||
menu[MENU_IDX_OPT].className = submenu[MENU_IDX_SUB].className.bind(null, submenu, false);
|
||||
break;
|
||||
}
|
||||
switch (typeof d[MENU_IDX_SUB].column) {
|
||||
switch (typeof submenu[MENU_IDX_SUB].column) {
|
||||
case 'number':
|
||||
case 'string':
|
||||
menu[MENU_IDX_OPT].column = d[MENU_IDX_SUB].column;
|
||||
menu[MENU_IDX_OPT].column = submenu[MENU_IDX_SUB].column;
|
||||
break;
|
||||
case 'function':
|
||||
menu[MENU_IDX_OPT].column = d[MENU_IDX_SUB].column.bind(null, d);
|
||||
menu[MENU_IDX_OPT].column = submenu[MENU_IDX_SUB].column.bind(null, submenu);
|
||||
break;
|
||||
}
|
||||
switch (typeof d[MENU_IDX_SUB].tinyIcon) {
|
||||
switch (typeof submenu[MENU_IDX_SUB].tinyIcon) {
|
||||
case 'string':
|
||||
menu[MENU_IDX_OPT].tinyIcon = d[MENU_IDX_SUB].tinyIcon;
|
||||
menu[MENU_IDX_OPT].tinyIcon = submenu[MENU_IDX_SUB].tinyIcon;
|
||||
break;
|
||||
case 'function':
|
||||
menu[MENU_IDX_OPT].tinyIcon = d[MENU_IDX_SUB].tinyIcon.bind(null, d);
|
||||
menu[MENU_IDX_OPT].tinyIcon = submenu[MENU_IDX_SUB].tinyIcon.bind(null, submenu);
|
||||
break;
|
||||
}
|
||||
switch (typeof d[MENU_IDX_SUB].fontIcon) {
|
||||
switch (typeof submenu[MENU_IDX_SUB].fontIcon) {
|
||||
case 'string':
|
||||
menu[MENU_IDX_OPT].fontIcon = d[MENU_IDX_SUB].fontIcon;
|
||||
menu[MENU_IDX_OPT].fontIcon = submenu[MENU_IDX_SUB].fontIcon;
|
||||
break;
|
||||
case 'function':
|
||||
menu[MENU_IDX_OPT].fontIcon = d[MENU_IDX_SUB].fontIcon.bind(null, d);
|
||||
menu[MENU_IDX_OPT].fontIcon = submenu[MENU_IDX_SUB].fontIcon.bind(null, submenu);
|
||||
break;
|
||||
}
|
||||
|
||||
if (typeof d[MENU_IDX_SUB].isChecked == 'function')
|
||||
menu[MENU_IDX_OPT].checkedFunc = d[MENU_IDX_SUB].isChecked.bind(null, d);
|
||||
if (typeof submenu[MENU_IDX_SUB].isChecked == 'function')
|
||||
menu[MENU_IDX_OPT].checkedFunc = submenu[MENU_IDX_SUB].isChecked.bind(null, submenu);
|
||||
|
||||
if (typeof d[MENU_IDX_SUB].menu == 'object' && d[MENU_IDX_SUB].menu instanceof Array)
|
||||
Menu.setSubmenu(menu, d[MENU_IDX_SUB].menu); // <-- n.d. !
|
||||
if (typeof submenu[MENU_IDX_SUB].menu == 'object' && submenu[MENU_IDX_SUB].menu instanceof Array)
|
||||
Menu.setSubmenu(menu, submenu[MENU_IDX_SUB].menu); // <-- n.d. !
|
||||
|
||||
}
|
||||
c.push(menu);
|
||||
|
||||
widgetmenu.push(menu);
|
||||
}
|
||||
|
||||
container.menu = c;
|
||||
container.menu = widgetmenu;
|
||||
|
||||
if (opt.menuOnClick) {
|
||||
container.onmousedown = $WH.rf;
|
||||
Menu.add(container, c, { showAtElement: true });
|
||||
Menu.add(container, widgetmenu, { showAtElement: true });
|
||||
}
|
||||
else
|
||||
Menu.add(container, c);
|
||||
Menu.add(container, widgetmenu);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (opt.target)
|
||||
if (opt.target)
|
||||
$(opt.target).append(container);
|
||||
else
|
||||
else
|
||||
return container;
|
||||
};
|
||||
$WH.createOptionsMenuWidget.chevron = ' <i class="fa fa-chevron-down fa-color-gray">~</i>';
|
||||
|
||||
@@ -44,8 +44,8 @@ var _ = [
|
||||
alert('Operation failed.');
|
||||
},
|
||||
success: function(json) {
|
||||
if (json != 1)
|
||||
alert('Operation failed.');
|
||||
if (json)
|
||||
alert('Operation failed: ' + json);
|
||||
else
|
||||
$WH.de(el.parentNode);
|
||||
},
|
||||
|
||||
@@ -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">
|
||||
@@ -12,9 +15,9 @@ $this->brick('announcement');
|
||||
$this->brick('pageTemplate');
|
||||
?>
|
||||
<div class="text">
|
||||
<h1><?=$this->name; ?></h1>
|
||||
<h1><?=$this->h1; ?></h1>
|
||||
<?php
|
||||
$this->brick('article');
|
||||
$this->brick('markup', ['markup' => $this->article]);
|
||||
?>
|
||||
</div>
|
||||
<div class="pad"></div>
|
||||
@@ -24,14 +27,14 @@ $this->brick('pageTemplate');
|
||||
<form id="guide-form" method="post" action="?guide=edit&id=<?=$this->typeId;?>" onsubmit="leavePage(1)">
|
||||
<table class="responsive-collapse guide-form-main">
|
||||
<tr class="guide-form-guide-link">
|
||||
<td colspan="2"><h2 style="margin:0" class="heading-size-2"><a href="?guide=<?=$this->typeId;?>" target="_blank"><?=$this->editorFields('title');?></a></h2></td>
|
||||
<td colspan="2"><h2 style="margin:0" class="heading-size-2"><a href="?guide=<?=$this->typeId;?>" target="_blank"><?=$this->editTitle;?></a></h2></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th><label for="title"><dfn title="<?=Lang::guide('editor', 'fullTitleTip');?>"><?=Lang::guide('editor', 'fullTitle');?></dfn></label></th>
|
||||
<td>
|
||||
<input required="required" type="text" maxlength="100" name="title" id="title"
|
||||
value="<?=$this->editorFields('title');?>"
|
||||
value="<?=$this->editTitle;?>"
|
||||
placeholder="<?=Lang::guide('editor', 'fullTitleTip');?>"
|
||||
data-charwarning="title-char-warning">
|
||||
<small id="title-char-warning" class="char-warning"></small>
|
||||
@@ -43,7 +46,7 @@ $this->brick('pageTemplate');
|
||||
<th><label for="name"><dfn title="<?=Lang::guide('editor', 'nameTip');?>"><?=Lang::guide('editor', 'name');?></dfn></label></th>
|
||||
<td>
|
||||
<input required="required" type="text" maxlength="100" name="name" id="name"
|
||||
value="<?=$this->editorFields('name');?>"
|
||||
value="<?=$this->editName;?>"
|
||||
placeholder="<?=Lang::guide('editor', 'nameTip');?>"
|
||||
data-charwarning="name-char-warning">
|
||||
<small id="name-char-warning" class="char-warning"></small>
|
||||
@@ -54,13 +57,7 @@ $this->brick('pageTemplate');
|
||||
<tr>
|
||||
<th><label for="locale"><?=Lang::main('language');?></label></th>
|
||||
<td><select name="locale" id="locale" required="required" size="1">
|
||||
<?php
|
||||
foreach (Locale::cases() as $l):
|
||||
if ($l->validate()):
|
||||
echo ' <option value="'.$l->value.'"'.($this->editorFields('locale', true) == $l->value ? ' selected="selected"' : '').'>'.$l->title()."</option>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<?=$this->makeOptionsList(Lang::getLocale()::cases(), $this->editLocale, 24, function(&$v, &$k) { $k = $v->value; return $v = $v->validate()?->title(); }); ?>
|
||||
</select></td>
|
||||
</tr>
|
||||
|
||||
@@ -69,13 +66,7 @@ endforeach;
|
||||
<th><label for="category"><?=Lang::guide('editor', 'category');?></label></th>
|
||||
<td>
|
||||
<select id="category" name="category" required="required"><option></option>
|
||||
<?php
|
||||
foreach (Lang::guide('category') as $i => $c):
|
||||
if ($c):
|
||||
echo ' <option value="'.$i.'"'.($this->editorFields('category', true) == $i ? ' selected="selected"' : '').'>'.$c."</option>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<?=$this->makeOptionsList(Lang::guide('category'), $this->editCategory, 24); ?>
|
||||
</select>
|
||||
<script>
|
||||
(function() {
|
||||
@@ -98,8 +89,8 @@ endforeach;
|
||||
<tr id="class-guide-specialization-options">
|
||||
<th><label for="specId"><?=Lang::guide('editor', 'class-spec');?></label></th>
|
||||
<td>
|
||||
<input name="specId" id="specId" type="hidden" value="<?=$this->editorFields('specId');?>">
|
||||
<input name="classId" id="classId" type="hidden" value="<?=$this->editorFields('classId');?>">
|
||||
<input name="specId" id="specId" type="hidden" value="<?=$this->editSpecId;?>">
|
||||
<input name="classId" id="classId" type="hidden" value="<?=$this->editClassId;?>">
|
||||
<script>
|
||||
setTimeout(function() {
|
||||
// const PC = WH.Wow.PlayerClass;
|
||||
@@ -205,7 +196,7 @@ endforeach;
|
||||
<td colspan="3">
|
||||
<textarea rows="1" name="description" cols="100" id="description" style="height:69px"
|
||||
placeholder="<?=Lang::guide('editor', 'descriptionTip');?>"
|
||||
><?=$this->editorFields('description');?></textarea>
|
||||
><?=$this->editDescription;?></textarea>
|
||||
<script>g_enhanceTextarea('#description')</script>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -213,7 +204,6 @@ endforeach;
|
||||
<td></td>
|
||||
<td colspan="3"><span id="desc-info"></span></td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
/*
|
||||
<tr>
|
||||
@@ -227,13 +217,12 @@ endforeach;
|
||||
</tr>
|
||||
*/
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<th><?=Lang::main('status');?></th>
|
||||
<td colspan="3"><dfn title="<?=Lang::guide('editor', 'statusTip', $this->editorFields('status'));?>" style="color:<?=Guidelist::STATUS_COLORS[$this->editorFields('status')];?>"><?=Lang::guide('status', $this->editorFields('status'));?></dfn>
|
||||
<td colspan="3"><dfn title="<?=Lang::guide('editor', 'statusTip', $this->editStatus);?>" style="color:<?=$this->editStatusColor;?>"><?=Lang::guide('status', $this->editStatus);?></dfn>
|
||||
<?php
|
||||
if ($this->editorFields('status') == GUIDE_STATUS_DRAFT):
|
||||
echo '<small>(<a href="?guide='.$this->typeId.'&rev='.$this->editorFields('rev').'" target="_blank" class="q1">'.Lang::guide('editor', 'testGuide')."</a>)</small>\n";
|
||||
if ($this->isDraft && $this->typeId):
|
||||
echo ' <small>(<a href="?guide='.$this->typeId.'&rev='.$this->editRev.'" target="_blank" class="q1">'.Lang::guide('editor', 'testGuide')."</a>)</small>\n";
|
||||
endif;
|
||||
?>
|
||||
</td>
|
||||
@@ -263,7 +252,7 @@ endif;
|
||||
onchange="updatePreview(false, this)"
|
||||
rows="8"
|
||||
cols="40"
|
||||
style="width:95%"><?=$this->editorFields('text');?></textarea>
|
||||
style="width:95%"><?=$this->editText;?></textarea>
|
||||
<script>
|
||||
g_enhanceTextarea('#editBox', {
|
||||
markup: true,
|
||||
@@ -274,6 +263,12 @@ endif;
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<?php if ($this->error): ?>
|
||||
<div class="box msg-failure">
|
||||
<?=$this->error . PHP_EOL;?>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
<div class="guide-submission">
|
||||
<div class="guide-submission-options">
|
||||
<button type="button" class="btn btn-site" data-type="save" onclick="$('.guide-submission').attr('data-type', 'save'); $('#changelog').focus();"><?=Lang::guide('editor', 'save');?></button>
|
||||
@@ -288,7 +283,7 @@ endif;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img src="<?=Cfg::get('STATIC_URL');?>/images/icons/ajax.gif" style="display:none" class="spinning-circle">
|
||||
<img src="<?=$this->gStaticUrl;?>/images/icons/ajax.gif" style="display:none" class="spinning-circle">
|
||||
<span id="save-status"></span>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user