Guides: initial implementation

* a guide is a wrapper around an article providing management tools.
 * administration is limited to the review process. Needs to be expanded.
 * articles on DB pages are seperate. Editor will be added in the future.
This commit is contained in:
Sarjuuk 2022-03-02 18:19:50 +01:00
parent 33a870ef78
commit b890d6504e
63 changed files with 6734 additions and 338 deletions

View file

@ -5,9 +5,9 @@ if (!defined('AOWOW_REVISION'))
class AjaxAdmin extends AjaxHandler
{
protected $validParams = ['screenshots', 'siteconfig', 'weight-presets', 'spawn-override'];
protected $validParams = ['screenshots', 'siteconfig', 'weight-presets', 'spawn-override', 'guide'];
protected $_get = array(
'action' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
'action' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdListUnsigned'],
'key' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkKey' ],
'all' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkFulltext' ],
@ -20,21 +20,22 @@ class AjaxAdmin extends AjaxHandler
'floor' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt' ]
);
protected $_post = array(
'alt' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
'alt' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
'scale' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkScale'],
'__icon' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkKey' ]
'__icon' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkKey' ],
'status' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
'msg' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW]
);
public function __construct(array $params)
{
parent::__construct($params);
// requires 'action' parameter in any case
if (!$this->_get['action'] || !$this->params)
if (!$this->params)
return;
if ($this->params[0] == 'screenshots')
if ($this->params[0] == 'screenshots' && $this->_get['action'])
{
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT))
return;
@ -54,7 +55,7 @@ class AjaxAdmin extends AjaxHandler
else if ($this->_get['action'] == 'relocate')
$this->handler = 'ssRelocate';
}
else if ($this->params[0] == 'siteconfig')
else if ($this->params[0] == 'siteconfig' && $this->_get['action'])
{
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
return;
@ -66,7 +67,7 @@ class AjaxAdmin extends AjaxHandler
else if ($this->_get['action'] == 'update')
$this->handler = 'confUpdate';
}
else if ($this->params[0] == 'weight-presets')
else if ($this->params[0] == 'weight-presets' && $this->_get['action'])
{
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN | U_GROUP_BUREAU))
return;
@ -81,6 +82,13 @@ class AjaxAdmin extends AjaxHandler
$this->handler = 'spawnPosFix';
}
else if ($this->params[0] == 'guide')
{
if (!User::isInGroup(U_GROUP_STAFF))
return;
$this->handler = 'guideManage';
}
}
// get all => null (optional)
@ -467,6 +475,57 @@ 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) WHERE `id` = ?d', Type::GUIDE, $id, $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';
}
/***************************/
/* additional input filter */
@ -499,6 +558,11 @@ class AjaxAdmin extends AjaxHandler
return '';
}
/**********/
/* helper */
/**********/
private static function confOnChange(string $key, string $val, string &$msg) : bool
{
$fn = $buildList = null;

View file

@ -103,7 +103,7 @@ class AjaxComment extends AjaxHandler
Util::gainSiteReputation(User::$id, SITEREP_ACTION_COMMENT, ['id' => $postIdx]);
// every comment starts with a rating of +1 and i guess the simplest thing to do is create a db-entry with the system as owner
DB::Aowow()->query('INSERT INTO ?_comments_rates (commentId, userId, value) VALUES (?d, 0, 1)', $postIdx);
DB::Aowow()->query('INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, 0, 1)', RATING_COMMENT, $postIdx);
// flag target with hasComment
if ($tbl = Type::getClassAttrib($this->_get['type'], 'dataTable'))
@ -122,7 +122,13 @@ class AjaxComment extends AjaxHandler
$_SESSION['error']['co'] = Lang::main('cannotComment');
$this->doRedirect = true;
return '?'.Type::getFileString($this->_get['type']).'='.$this->_get['typeid'].'#comments';
$idOrUrl = $this->_get['typeid'];
if ($this->_get['type'] == Type::GUIDE)
if ($_ = DB::Aowow()->selectCell('SELECT `url` FROM ?_guides WHERE `id` = ?d', $this->_get['typeid']))
$idOrUrl = $_;
return '?'.Type::getFileString($this->_get['type']).'='.$idOrUrl.'#comments';
}
protected function handleCommentEdit() : void
@ -224,7 +230,7 @@ class AjaxComment extends AjaxHandler
if (!$this->_get['id'])
return Util::toJSON(['success' => 0]);
if ($votes = DB::Aowow()->selectRow('SELECT 1 AS success, SUM(IF(value > 0, value, 0)) AS up, SUM(IF(value < 0, -value, 0)) AS down FROM ?_comments_rates WHERE commentId = ?d and userId <> 0 GROUP BY commentId', $this->_get['id']))
if ($votes = DB::Aowow()->selectRow('SELECT 1 AS success, SUM(IF(`value` > 0, `value`, 0)) AS up, SUM(IF(`value` < 0, -`value`, 0)) AS down FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND userId <> 0 GROUP BY `entry`', RATING_COMMENT, $this->_get['id']))
return Util::toJSON($votes);
else
return Util::toJSON(['success' => 1, 'up' => 0, 'down' => 0]);
@ -235,7 +241,7 @@ class AjaxComment extends AjaxHandler
if (!User::$id || !$this->_get['id'] || !$this->_get['rating'])
return Util::toJSON(['error' => 1, 'message' => Lang::main('genericError')]);
$target = DB::Aowow()->selectRow('SELECT c.userId AS owner, cr.value FROM ?_comments c LEFT JOIN ?_comments_rates cr ON cr.commentId = c.id AND cr.userId = ?d WHERE c.id = ?d', User::$id, $this->_get['id']);
$target = DB::Aowow()->selectRow('SELECT c.`userId` AS owner, ur.`value` FROM ?_comments c LEFT JOIN ?_user_ratings ur ON ur.`type` = ?d AND ur.`entry` = c.id AND ur.`userId` = ?d WHERE c.id = ?d', RATING_COMMENT, User::$id, $this->_get['id']);
$val = User::canSupervote() ? 2 : 1;
if ($this->_get['rating'] < 0)
$val *= -1;
@ -250,9 +256,9 @@ class AjaxComment extends AjaxHandler
$ok = false;
// old and new have same sign; undo vote (user may have gained/lost access to superVote in the meantime)
if ($target['value'] && ($target['value'] < 0) == ($val < 0))
$ok = DB::Aowow()->query('DELETE FROM ?_comments_rates WHERE commentId = ?d AND userId = ?d', $this->_get['id'], User::$id);
$ok = DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND `userId` = ?d', RATING_COMMENT, $this->_get['id'], User::$id);
else // replace, because we may be overwriting an old, opposing vote
if ($ok = DB::Aowow()->query('REPLACE INTO ?_comments_rates (commentId, userId, value) VALUES (?d, ?d, ?d)', (int)$this->_get['id'], User::$id, $val))
if ($ok = DB::Aowow()->query('REPLACE INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)', RATING_COMMENT, (int)$this->_get['id'], User::$id, $val))
User::decrementDailyVotes(); // do not refund retracted votes!
if (!$ok)
@ -385,7 +391,7 @@ class AjaxComment extends AjaxHandler
}
if (DB::Aowow()->query('DELETE FROM ?_comments WHERE id = ?d{ AND userId = ?d}', $this->_post['id'][0], User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id))
DB::Aowow()->query('DELETE FROM ?_comments_rates WHERE commentId = ?d', $this->_post['id'][0]);
DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d', RATING_COMMENT, $this->_post['id'][0]);
else
trigger_error('AjaxComment::handleReplyDelete - deleting comment #'.$this->_post['id'][0].' by user #'.User::$id.' from db failed', E_USER_ERROR);
}
@ -417,7 +423,8 @@ class AjaxComment extends AjaxHandler
}
$ok = DB::Aowow()->query(
'INSERT INTO ?_comments_rates (commentId, userId, value) VALUES (?d, ?d, ?d)',
'INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)',
RATING_COMMENT,
$this->_post['id'][0],
User::$id,
User::canSupervote() ? 2 : 1
@ -448,7 +455,8 @@ class AjaxComment extends AjaxHandler
}
$ok = DB::Aowow()->query(
'INSERT INTO ?_comments_rates (commentId, userId, value) VALUES (?d, ?d, ?d)',
'INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)',
RATING_COMMENT,
$this->_post['id'][0],
User::$id,
User::canSupervote() ? -2 : -1

View file

@ -0,0 +1,80 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AjaxEdit extends AjaxHandler
{
protected $_get = array(
'qqfile' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
'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::$id || $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::$displayName.'-'.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);
}
}
?>

View file

@ -0,0 +1,35 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
class AjaxGetdescription extends AjaxHandler
{
protected $_post = array(
'description' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkFulltext']]
);
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::$id)
return '';
$desc = (new Markup($this->_post['description']))->stripTags();
return Lang::trimTextClean($desc, 120);
}
}
?>

View file

@ -0,0 +1,61 @@
<?php
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]);
}
}
?>

View file

@ -28,8 +28,8 @@ class CommunityContent
a2.displayName AS editUser,
a3.displayName AS deleteUser,
a4.displayName AS responseUser,
IFNULL(SUM(cr.value), 0) AS rating,
SUM(IF(cr.userId > 0 AND cr.userId = ?d, cr.value, 0)) AS userRating,
IFNULL(SUM(ur.value), 0) AS rating,
SUM(IF(ur.userId > 0 AND ur.userId = ?d, ur.value, 0)) AS userRating,
SUM(IF( r.userId > 0 AND r.userId = ?d, 1, 0)) AS userReported
FROM
?_comments c
@ -42,7 +42,7 @@ class CommunityContent
LEFT JOIN
?_account a4 ON c.responseUserId = a4.id
LEFT JOIN
?_comments_rates cr ON c.id = cr.commentId
?_user_ratings ur ON c.id = ur.entry AND ur.type = ?d
LEFT JOIN
?_reports r ON r.subject = c.id AND r.mode = 1 AND r.reason = 19
WHERE
@ -81,14 +81,14 @@ class CommunityContent
IF(c.flags & ?d, 1, 0) AS deleted,
IF(c.type <> 0, c.type, c2.type) AS type,
IF(c.typeId <> 0, c.typeId, c2.typeId) AS typeId,
IFNULL(SUM(cr.value), 0) AS rating,
IFNULL(SUM(ur.value), 0) AS rating,
a.displayName AS user
FROM
?_comments c
JOIN
?_account a ON c.userId = a.id
LEFT JOIN
?_comments_rates cr ON cr.commentId = c.id AND cr.userId <> 0
?_user_ratings ur ON ur.entry = c.id AND ur.userId <> 0 AND ur.`type` = 1
LEFT JOIN
?_comments c2 ON c.replyTo = c2.id
WHERE
@ -179,13 +179,13 @@ class CommunityContent
return $comments;
}
public static function getCommentReplies(int $commentId, int $limit = 0, int &$nFound = 0) : array
public static function getCommentReplies(int $commentId, int $limit = 0, ?int &$nFound = 0) : array
{
$replies = [];
$query = $limit > 0 ? self::$coQuery.' LIMIT '.$limit : self::$coQuery;
// get replies
$results = DB::Aowow()->selectPage($nFound, $query, User::$id, User::$id, $commentId, 0, 0, CC_FLAG_DELETED, User::$id, User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
$results = DB::Aowow()->selectPage($nFound, $query, User::$id, User::$id, RATING_COMMENT, $commentId, 0, 0, CC_FLAG_DELETED, User::$id, User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
foreach ($results as $r)
{
(new Markup($r['body']))->parseGlobalsFromText(self::$jsGlobals);
@ -341,7 +341,7 @@ class CommunityContent
public static function getComments(int $type, int $typeId) : array
{
$results = DB::Aowow()->query(self::$coQuery, User::$id, User::$id, 0, $type, $typeId, CC_FLAG_DELETED, User::$id, (int)User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
$results = DB::Aowow()->query(self::$coQuery, User::$id, User::$id, RATING_COMMENT, 0, $type, $typeId, CC_FLAG_DELETED, User::$id, (int)User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
$comments = [];
// additional informations

View file

@ -66,7 +66,7 @@ define('ACC_BAN_COMMENT', 0x08); // cannot comment an
define('ACC_BAN_UPLOAD', 0x10); // cannot upload avatar / signature files [originally: ban from data upload]
define('ACC_BAN_SCREENSHOT', 0x20); // cannot upload screenshots
define('ACC_BAN_VIDEO', 0x40); // cannot suggest videos
// define('ACC_BAN_FORUM', 0x80); // cannot use forums [not used here]
define('ACC_BAN_GUIDE', 0x80); // cannot write a guide
// Site Reputation/Privileges
define('SITEREP_ACTION_REGISTER', 1); // Registered account
@ -164,6 +164,10 @@ define('BUTTON_TALENT', 6);
define('BUTTON_EQUIP', 7);
define('BUTTON_PLAYLIST', 8);
define('BUTTON_RESYNC', 9);
define('BUTTON_GUIDE_REPORT', 10);
define('BUTTON_GUIDE_NEW', 11);
define('BUTTON_GUIDE_EDIT', 12);
define('BUTTON_GUIDE_LOG', 13);
// generic filter handler
define('FILTER_CR_BOOLEAN', 1);
@ -240,6 +244,16 @@ define('STR_LOCALIZED', 0x1);
define('STR_MATCH_EXACT', 0x2);
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);
/*
* Game
*/
@ -299,6 +313,9 @@ define('PROFILER_CU_DELETED', 0x04);
define('PROFILER_CU_PROFILE', 0x08);
define('PROFILER_CU_NEEDS_RESYNC', 0x10);
define('GUIDE_CU_NO_QUICKFACTS', 0x100); // merge with CC_FLAG_*
define('GUIDE_CU_NO_RATING', 0x200);
define('MAX_LEVEL', 80);
define('MAX_SKILL', 450);
define('MAX_LOCALES', 16); // technical limitation, 6 in use here

View file

@ -14,6 +14,25 @@ class Game
'9d9d9d', 'ffffff', '1eff00', '0070dd', 'a335ee', 'ff8000', 'e5cc80', 'e6cc80'
);
public static $specIconStrings = array(
-1 => 'inv_misc_questionmark',
0 => 'spell_nature_elementalabsorption',
6 => ['spell_deathknight_bloodpresence', 'spell_deathknight_frostpresence', 'spell_deathknight_unholypresence' ],
11 => ['spell_nature_starfall', 'ability_racial_bearform', 'spell_nature_healingtouch' ],
3 => ['ability_hunter_beasttaming', 'ability_marksmanship', 'ability_hunter_swiftstrike' ],
8 => ['spell_holy_magicalsentry', 'spell_fire_firebolt02', 'spell_frost_frostbolt02' ],
2 => ['spell_holy_holybolt', 'spell_holy_devotionaura', 'spell_holy_auraoflight' ],
5 => ['spell_holy_wordfortitude', 'spell_holy_holybolt', 'spell_shadow_shadowwordpain' ],
4 => ['ability_rogue_eviscerate', 'ability_backstab', 'ability_stealth' ],
7 => ['spell_nature_lightning', 'spell_nature_lightningshield', 'spell_nature_magicimmunity' ],
9 => ['spell_shadow_deathcoil', 'spell_shadow_metamorphosis', 'spell_shadow_rainoffire' ],
1 => ['ability_rogue_eviscerate', 'ability_warrior_innerrage', 'ability_warrior_defensivestance' ]
);
public static $classFileStrings = array(
null, 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'
);
private static $combatRatingToItemMod = array( // zero-indexed idx:CR; val:Mod
null, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28,

View file

@ -266,7 +266,7 @@ if (!CLI)
$str = explode('&', mb_strtolower($_SERVER['QUERY_STRING'] ?? ''), 2)[0];
$_ = explode('=', $str, 2);
$pageCall = $_[0];
$pageParam = isset($_[1]) ? $_[1] : '';
$pageParam = $_[1] ?? '';
Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str;
}

View file

@ -0,0 +1,187 @@
<?php
/****************************************
Example of how to use this uploader class...
You can uncomment the following lines (minus the require) to use these as your defaults.
// list of valid extensions, ex. array("jpeg", "xml", "bmp")
$allowedExtensions = array();
// max file size in bytes
$sizeLimit = 10 * 1024 * 1024;
require('valums-file-uploader/server/php.php');
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
// Call handleUpload() with the name of the folder, relative to PHP's getcwd()
$result = $uploader->handleUpload('uploads/');
// to pass data through iframe you will need to encode all html tags
echo htmlspecialchars(json_encode($result), ENT_NOQUOTES);
/******************************************/
/**
* Handle file uploads via XMLHttpRequest
*/
class qqUploadedFileXhr
{
/**
* Save the file to the specified path
* @return boolean TRUE on success
*/
function save(string $path) : bool
{
$input = fopen("php://input", "r");
$temp = tmpfile();
$realSize = stream_copy_to_stream($input, $temp);
fclose($input);
if ($realSize != $this->getSize())
return false;
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
stream_copy_to_stream($temp, $target);
fclose($target);
return true;
}
function getName() : string
{
return $_GET['qqfile'];
}
function getSize(): int
{
if (isset($_SERVER["CONTENT_LENGTH"]))
return (int)$_SERVER["CONTENT_LENGTH"];
throw new Exception('Getting content length is not supported.');
return 0;
}
}
/**
* Handle file uploads via regular form post (uses the $_FILES array)
*/
class qqUploadedFileForm
{
/**
* Save the file to the specified path
* @return boolean TRUE on success
*/
function save(string $path) : bool
{
if(!move_uploaded_file($_FILES['qqfile']['tmp_name'], $path))
return false;
return true;
}
function getName() : string
{
return $_FILES['qqfile']['name'];
}
function getSize() : int
{
return $_FILES['qqfile']['size'];
}
}
class qqFileUploader
{
private $allowedExtensions = array();
private $sizeLimit = 10485760;
private $file;
public function __construct(array $allowedExtensions = array(), $sizeLimit = 10485760)
{
$this->allowedExtensions = array_map("strtolower", $allowedExtensions);
$this->sizeLimit = $sizeLimit;
$this->checkServerSettings();
if (isset($_GET['qqfile']))
$this->file = new qqUploadedFileXhr();
else if (isset($_FILES['qqfile']))
$this->file = new qqUploadedFileForm();
else
$this->file = null;
}
public function getName() : string
{
return $this->file?->getName() ?? '';
}
private function checkServerSettings() : void
{
$postSize = $this->toBytes(ini_get('post_max_size'));
$uploadSize = $this->toBytes(ini_get('upload_max_filesize'));
if ($postSize < $this->sizeLimit || $uploadSize < $this->sizeLimit)
{
$size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';
die("{'error':'increase post_max_size and upload_max_filesize to $size'}");
}
}
private function toBytes(string $str) : int
{
$val = trim($str);
$last = strtolower(substr($str, -1, 1));
switch ($last)
{
case 'g': $val *= 1024;
case 'm': $val *= 1024;
case 'k': $val *= 1024;
}
return $val;
}
/**
* Returns array('success' => true, 'newFilename' => 'myDoc123.doc') or array('error' => 'error message')
*/
function handleUpload(string $uploadDirectory, string $newName = '', bool $replaceOldFile = FALSE) : array
{
if (!is_writable($uploadDirectory))
return ['error' => "Server error. Upload directory isn't writable."];
if (!$this->file)
return ['error' => 'No files were uploaded.'];
$size = $this->file->getSize();
if ($size == 0)
return ['error' => 'File is empty'];
if ($size > $this->sizeLimit)
return ['error' => 'File is too large'];
$pathinfo = pathinfo($this->getName());
$filename = $newName ?: $pathinfo['filename'];
//$filename = md5(uniqid());
$ext = @$pathinfo['extension']; // hide notices if extension is empty
if ($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions))
{
$these = implode(', ', $this->allowedExtensions);
return ['error' => 'File has an invalid extension, it should be one of '. $these . '.'];
}
// don't overwrite previous files that were uploaded
if (!$replaceOldFile)
while (file_exists($uploadDirectory . $filename . '.' . $ext))
$filename .= rand(10, 99);
if ($this->file->save($uploadDirectory . $filename . '.' . $ext))
return ['success' => true, 'newFilename' => $filename . '.' . $ext];
else
return ['error' => 'Could not save uploaded file. The upload was cancelled, or server error encountered'];
}
}

View file

@ -1,6 +1,6 @@
<?php
define('AOWOW_REVISION', 32);
define('AOWOW_REVISION', 33);
define('CLI', PHP_SAPI === 'cli');

View file

@ -0,0 +1,167 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
class GuideList extends BaseType
{
use ListviewHelper;
public const 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 $type = Type::GUIDE;
public static $brickFile = 'guide';
public static $dataTable = '?_guides';
private $article = [];
private $jsGlobals = [];
protected $queryBase = 'SELECT g.*, g.id AS ARRAY_KEY FROM ?_guides g';
protected $queryOpts = array(
'g' => [['a', 'c'], 'g' => 'g.`id`'],
'a' => ['j' => ['?_account a ON a.id = g.userId', true], 's' => ', IFNULL(a.displayName, "") 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`']
);
public function __construct($conditions = [])
{
parent::__construct($conditions);
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());
// 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;
}
}
}
public function getArticle(int $rev = -1) : string
{
if ($rev < -1)
$rev = -1;
if (empty($this->article[$rev]))
{
$a = DB::Aowow()->selectRow('SELECT `article`, `rev` FROM ?_articles WHERE ((`type` = ?d AND `typeId` = ?d){ OR `url` = ?}){ AND `rev`= ?d} ORDER BY `rev` DESC LIMIT 1',
Type::GUIDE, $this->id, $this->getField('url') ?: DBSIMPLE_SKIP, $rev < 0 ? DBSIMPLE_SKIP : $rev);
$this->article[$a['rev']] = $a['article'];
if ($this->article[$a['rev']])
{
(new Markup($this->article[$a['rev']]))->parseGlobalsFromText($this->jsGlobals);
return $this->article[$a['rev']];
}
else
trigger_error('GuideList::getArticle - linked article is missing');
}
return $this->article[$rev] ?? '';
}
public function getListviewData(bool $addDescription = false) : array
{
$data = [];
foreach ($this->iterate() as $__)
{
$data[$this->id] = array(
'id' => $this->id,
'category' => $this->getField('category'),
'title' => $this->getField('title'),
'description' => $this->getField('description'),
'sticky' => !!($this->getField('cuFlags') & CC_FLAG_STICKY),
'nvotes' => $this->getField('nvotes'),
'url' => '/?guide=' . ($this->getField('url') ?: $this->id),
'status' => $this->getField('status'),
'author' => $this->getField('author'),
'authorroles' => $this->getField('roles'),
'rating' => $this->getField('rating'),
'views' => $this->getField('views'),
'comments' => $this->getField('comments'),
// 'patch' => $this->getField(''), // 30305 - patch is pointless, use date instead
'date' => $this->getField('date'), // ok
'when' => date(Util::$dateFormatInternal, $this->getField('date'))
);
}
return $data;
}
public function userCanView() : bool
{
// is owner || is staff
return $this->getField('userId') == User::$id || User::isInGroup(U_GROUP_STAFF);
}
public function canBeViewed() : bool
{
// currently approved || has prev. approved version
return $this->getField('status') == GUIDE_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;
}
public function getJSGlobals($addMask = GLOBALINFO_ANY) : array
{
return $this->jsGlobals;
}
public function renderTooltip() : string
{
$specStr = '';
if ($this->getField('classId') && $this->getField('category') == 1)
{
$c = $this->getField('classId');
if (($s = $this->getField('specId')) > -1)
{
$i = Game::$specIconStrings[$c][$s];
$n = Lang::game('classSpecs', $c, $s);
}
else
{
$i = 'class_'.Game::$classFileStrings[$c];
$n = Lang::game('cl', $c);
}
$specStr = '&nbsp;&nbsp;&nbsp;&nbsp;<span class="icontiny c'.$c.'" style="background-image: url('.STATIC_URL.'/images/wow/icons/tiny/'.$i.'.gif)">'.$n.'</span>';
}
$tt = '<table><tr><td><div style="max-width: 320px"><b class="q">'.$this->getField('title').'</b><br>';
$tt .= '<table width="100%"><tr><td>'.Lang::guide('guide').'</td><th>'.Lang::guide('byAuthor', [$this->getField('author')]).'</th></tr></table>';
$tt .= '<table width="100%"><tr><td>'.Lang::guide('category', $this->getField('category')).$specStr.'</td><th>'.Lang::guide('patch').' 3.3.5</th></tr></table>';
$tt .= '<div class="q" style="margin: 0.25em 0">'.$this->getField('description').'</div>';
$tt .= '</div></td></tr></table>';
return $tt;
}
}
?>

View file

@ -518,6 +518,14 @@ class User
return true;
}
public static function canWriteGuide()
{
if (!self::$id || self::$banStatus & (ACC_BAN_GUIDE | ACC_BAN_PERM | ACC_BAN_TEMP))
return false;
return true;
}
public static function canSuggestVideo()
{
if (!self::$id || self::$banStatus & (ACC_BAN_VIDEO | ACC_BAN_PERM | ACC_BAN_TEMP))
@ -589,6 +597,9 @@ class User
if ($_ = self::getProfiles())
$gUser['profiles'] = $_;
if ($_ = self::getGuides())
$gUser['guides'] = $_;
if ($_ = self::getWeightScales())
$gUser['weightscales'] = $_;
@ -641,6 +652,20 @@ class User
return self::$profiles->getJSGlobals(PROFILEINFO_PROFILE);
}
public static function getGuides()
{
$result = [];
if ($guides = DB::Aowow()->select('SELECT `id`, `title`, `url` FROM ?_guides WHERE `userId` = ?d AND `status` <> ?d', self::$id, GUIDE_STATUS_ARCHIVED))
{
// fix url
array_walk($guides, fn(&$x) => $x['url'] = '/?guide='.($x['url'] ?? $x['id']));
$result = $guides;
}
return $result;
}
public static function getCookies()
{
$data = [];

View file

@ -486,6 +486,8 @@ 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>&nbsp;(%d)';
public static $guideratingString = " $(document).ready(function() {\n $('#guiderating').append(GetStars(%.10F, %s, %u, %u));\n });";
public static $expansionString = array( // 3 & 4 unused .. obviously
null, 'bc', 'wotlk', 'cata', 'mop'
);
@ -1084,8 +1086,8 @@ abstract class Util
$x['sourceA'] = $miscData['id'];
$x['amount'] = $action == SITEREP_ACTION_GOOD_REPORT ? CFG_REP_REWARD_GOOD_REPORT : CFG_REP_REWARD_BAD_REPORT;
break;
case SITEREP_ACTION_ARTICLE: // NYI
if (empty($miscData['id'])) // reportId
case SITEREP_ACTION_ARTICLE:
if (empty($miscData['id'])) // guideId
return false;
$x['sourceA'] = $miscData['id'];

View file

@ -39,6 +39,8 @@ switch ($pageCall)
case 'events':
case 'faction':
case 'factions':
case 'guide':
case 'guides':
case 'guild':
case 'guilds':
case 'icon':
@ -50,6 +52,9 @@ switch ($pageCall)
case 'maps': // tool: map listing
case 'mail':
case 'mails':
case 'my-guides':
if ($pageCall == 'my-guides')
$altClass = 'guides';
case 'npc':
case 'npcs':
case 'object':
@ -86,6 +91,8 @@ switch ($pageCall)
case 'cookie': // lossless cookies and user settings
case 'contactus':
case 'comment':
case 'edit': // guide editor: targeted by QQ fileuploader, detail-page article editor
case 'get-description': // guide editor: shorten fulltext into description
case 'filter': // pre-evaluate filter POST-data; sanitize and forward as GET-data
case 'go-to-comment': // find page the comment is on and forward
case 'locale': // subdomain-workaround, change the language
@ -140,7 +147,6 @@ switch ($pageCall)
(new MorePage($pageCall, $pageParam))->display();
break;
case 'latest-additions':
case 'latest-articles':
case 'latest-comments':
case 'latest-screenshots':
case 'latest-videos':

View file

@ -35,10 +35,20 @@ class Lang
private static $spell;
private static $title;
private static $zone;
private static $guide;
private static $emote;
private static $enchantment;
private static $locales = array(
LOCALE_EN => 'English',
LOCALE_FR => 'Français',
LOCALE_DE => 'Deutsch',
LOCALE_CN => '简体中文',
LOCALE_ES => 'Español',
LOCALE_RU => 'Русский'
);
public static function load($loc)
{
if (!file_exists('localization/locale_'.$loc.'.php'))

View file

@ -52,8 +52,11 @@ $lang = array(
'or' => " oder ",
'back' => "Zurück",
'reputationTip' => "Rufpunkte",
'byUserTimeAgo' => 'Von <a href="'.HOST_URL.'/?user=%s">%1$s</a> vor %s',
'byUser' => 'Von <a href="'.HOST_URL.'/?user=%1$s"%2$s>%1$s</a> ',
'help' => "Hilfe",
'status' => "Status",
'yes' => "Ja",
'no' => "Nein",
// filter
'extSearch' => "Erweiterte Suche",
@ -80,6 +83,10 @@ $lang = array(
'compare' => "Vergleichen",
'view3D' => "3D-Ansicht",
'findUpgrades' => "Bessere Gegenstände finden…",
'report' => "Melden",
'writeGuide' => "Neuen Leitfaden erstellen",
'edit' => "Bearbeiten",
'changelog' => 'Änderungsprotokoll',
// miscTools
'errPageTitle' => "Seite nicht gefunden",
@ -121,6 +128,7 @@ $lang = array(
'colon' => ': ',
'dateFmtShort' => "d.m.Y",
'dateFmtLong' => "d.m.Y \u\m H:i",
'timeAgo' => 'vor %s',
// error
'intError' => "Ein interner Fehler ist aufgetreten.",
@ -150,6 +158,63 @@ $lang = array(
)
)
),
'guide' => array(
'guide' => "Leitfaden",
'guides' => "Leitfäden",
'myGuides' => "Meine Leitfäden",
'editTitle' => "Eigenen Leitfaden bearbeiten",
'newTitle' => "Leitfaden erstellen",
'author' => "Autor",
'spec' => "Spezialisierung",
'sticky' => "Angeheftet",
'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]",
'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',
'clMinorEdit' => 'Kleinere Bearbeitung',
'editor' => array(
'fullTitle' => 'Ganze Überschrift',
'fullTitleTip' => 'Der vollständige Titel des Leitfadens wird auf der Leitfadenseite verwendet und kann eine SEO-orientierte Formulierung enthalten.',
'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.&lt;br /&gt;&lt;br /&gt;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',
'changelogTip' => 'Änderungsprotokoll für diese Änderung',
'save' => 'Speichern',
'submit' => 'Zur Ansicht einsenden',
'autoupdate' => 'Autom. Update',
'showAdjPrev' => 'Zeige angrenzende Vorschau',
'preview' => 'Vorschau',
'class-spec' => 'Klasse / Spez.',
'category' => 'Kategorie',
'testGuide' => 'Sehen Sie, wie Ihr Leitfaden aussehen wird',
'images' => 'Bilder',
'statusTip' => array(
GUIDE_STATUS_DRAFT => 'Ihr Leitfaden ist im &quot;Entwurfs&quot;-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.]',
)
),
'category' => array(
null, "Klassen", "Berufe", "Weltereignisse", "Neue Spieler & Stufenfortschritt",
"Schlachtzüge & Bosskämpfe", "Wirtschaft & Währung", "Erfolge", "Gegenstände, Haus- & Reittiere", "Anderes"
),
'status' => array(
null, "Entwurf", "Zulassung ausstehend", "Zugelassen", "Abgelehnt", "Archiviert"
)
),
'profiler' => array(
'realm' => "Realm",
'region' => "Region",
@ -344,6 +409,20 @@ $lang = array(
38 => "Schimäre", 39 => "Teufelssaurier", 41 => "Silithid", 42 => "Wurm", 43 => "Rhinozeros", 44 => "Wespe",
45 => "Kernhund", 46 => "Geisterbestie"
),
'classSpecs' => array(
-1 => 'Untalentiert',
0 => 'Hybride',
6 => ['Blut', 'Frost', 'Unheilig' ],
11 => ['Gleichgewicht', 'Wilder Kampf', 'Wiederherstellung'],
3 => ['Tierherrschaft', 'Treffsicherheit', 'Überleben' ],
8 => ['Arkan', 'Feuer', 'Frost' ],
2 => ['Heilig', 'Schutz', 'Vergeltung' ],
5 => ['Disziplin', 'Heilig', 'Schattenmagie' ],
4 => ['Meucheln', 'Kampf', 'Täuschung' ],
7 => ['Elementarkampf', 'Verstärkung', 'Wiederherstellung'],
9 => ['Gebrechen', 'Dämonologie', 'Zerstörung' ],
1 => ['Waffen', 'Furor', 'Schutz' ]
),
'pvpRank' => array(
null, "Gefreiter / Späher", "Fußknecht / Grunzer",
"Landsknecht / Waffenträger", "Feldwebel / Schlachtrufer", "Fähnrich / Rottenmeister",

View file

@ -52,8 +52,11 @@ $lang = array(
'or' => " or ",
'back' => "Back",
'reputationTip' => "Reputation points",
'byUserTimeAgo' => 'By <a href="'.HOST_URL.'/?user=%s">%1$s</a> %s ago',
'byUser' => 'By <a href="'.HOST_URL.'/?user=%1$s"%2$s>%1$s</a> ', // mind the \s
'help' => "Help",
'status' => "Status",
'yes' => "Yes",
'no' => "No",
// filter
'extSearch' => "Extended search",
@ -80,6 +83,10 @@ $lang = array(
'compare' => "Compare",
'view3D' => "View in 3D",
'findUpgrades' => "Find upgrades…",
'report' => "Report",
'writeGuide' => "Write New Guide",
'edit' => "Edit",
'changelog' => 'Changelog',
// misc Tools
'errPageTitle' => "Page not found",
@ -120,7 +127,8 @@ $lang = array(
// formating
'colon' => ': ',
'dateFmtShort' => "Y/m/d",
'dateFmtLong' => "Y/m/d \a\\t H:i",
'dateFmtLong' => "Y/m/d \a\\t H:i A",
'timeAgo' => "%s ago",
// error
'intError' => "An internal error has occurred.",
@ -150,6 +158,63 @@ $lang = array(
)
)
),
'guide' => array(
'guide' => "Guide",
'guides' => "Guides",
'myGuides' => "My Guides",
'editTitle' => "Edit your Guide",
'newTitle' => "Create New Guide",
'author' => "Author",
'spec' => "Specialization",
'sticky' => "Sticky Status",
'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]",
'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',
'clMinorEdit' => 'Minor Edit',
'editor' => array(
'fullTitle' => 'Full Title',
'fullTitleTip' => 'The full guide title will be used on the guide page and may include SEO-oriented phrasing.',
'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.&lt;br&gt;&lt;br&gt;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',
'changelogTip' => 'Enter your changelog for this update here.',
'save' => 'Save',
'submit' => 'Submit for Review',
'autoupdate' => 'Autoupdate',
'showAdjPrev' => 'Show adjacent preview',
'preview' => 'Preview',
'class-spec' => 'Class / Spec',
'category' => 'Category',
'testGuide' => 'See how your guide will look',
'images' => 'Images',
'statusTip' => array(
GUIDE_STATUS_DRAFT => 'Your guide is in &quot;Draft&quot; status and you are the only one able to see it. Keep editing it as long as you like, and when you feel it&apos;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.',
)
),
'category' => array(
null, "Classes", "Professions", "World Events", "New Players & Leveling",
"Raid & Boss Fights", "Economy & Money", "Achievements", "Vanity Items, Pets & Mounts", "Other"
),
'status' => array(
null, "Draft", "Waiting for Approval", "Approved", "Rejected", "Archived"
),
),
'profiler' => array(
'realm' => "Realm",
'region' => "Region",
@ -344,6 +409,20 @@ $lang = array(
38 => "Chimaera", 39 => "Devilsaur", 41 => "Silithid", 42 => "Worm", 43 => "Rhino", 44 => "Wasp",
45 => "Core Hound", 46 => "Spirit Beast"
),
'classSpecs' => array(
-1 => 'Untalented',
0 => 'Hybrid',
1 => ['Arms', 'Fury', 'Protection' ],
2 => ['Holy', 'Protection', 'Retribution' ],
3 => ['Beast Mastery', 'Marksmanship', 'Survival' ],
4 => ['Assassination', 'Combat', 'Subtlety' ],
5 => ['Discipline', 'Holy', 'Shadow Magic'],
6 => ['Blood', 'Frost', 'Unholy' ],
7 => ['Elemental Combat', 'Enhancement', 'Restoration' ],
8 => ['Arcane', 'Fire', 'Frost' ],
9 => ['Affliction', 'Demonology', 'Destruction' ],
11 => ['Balance', 'Feral Combat', 'Restoration' ]
),
'pvpRank' => array( // PVP_RANK_\d_\d(_FEMALE)?
null, "Private / Scout", "Corporal / Grunt",
"Sergeant / Sergeant", "Master Sergeant / Senior Sergeant", "Sergeant Major / First Sergeant",

View file

@ -52,8 +52,11 @@ $lang = array(
'or' => " o ",
'back' => "Atrás",
'reputationTip' => "Puntos de reputación",
'byUserTimeAgo' => 'Por <a href="'.HOST_URL.'/?user=%s">%1$s</a> hace %s',
'byUser' => 'Por <a href="'.HOST_URL.'/?user=%1$s"%2$s>%1$s</a> ',
'help' => "Ayuda",
'status' => "Estado",
'yes' => "",
'no' => "No",
// filter
'extSearch' => "Extender búsqueda",
@ -80,6 +83,10 @@ $lang = array(
'compare' => "Comparar",
'view3D' => "Ver en 3D",
'findUpgrades' => "Buscar mejoras…",
'report' => "Reportar",
'writeGuide' => "Crear Nueva Guía",
'edit' => "Editar",
'changelog' => 'Changelog',
// misc Tools
'errPageTitle' => "Página no encontrada",
@ -120,7 +127,8 @@ $lang = array(
// formating
'colon' => ': ',
'dateFmtShort' => "d/m/Y",
'dateFmtLong' => "d/m/Y \a \l\a\s H:i",
'dateFmtLong' => "d/m/Y \a \l\a\s H:i A",
'timeAgo' => 'hace %s',
// error
'intError' => "Un error interno ha ocurrido.",
@ -150,6 +158,63 @@ $lang = array(
)
)
),
'guide' => array(
'guide' => "Guía",
'guides' => "Guías",
'myGuides' => "Mis Guías",
'editTitle' => "Editar tu Guía",
'newTitle' => "Crear Nueva Guía",
'author' => "Autor",
'spec' => "Especialización",
'sticky' => "Estado Fijo",
'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]",
'noVotes' => "necesita votaciones más [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',
'clMinorEdit' => 'Modificación menor',
'editor' => array(
'fullTitle' => 'Full Title',
'fullTitleTip' => 'The full guide title will be used on the guide page and may include SEO-oriented phrasing.',
'name' => 'Nombre',
'nameTip' => 'This should be a simple and clear name of what the guide is, for use in places like menus and guide lists.',
'description' => 'Descripción',
'descriptionTip' => 'Descripción empleada para los motores de búsqueda.&lt;br /&gt;&lt;br /&gt;Si se deja vacío, será generada 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 modifiación',
'changelogTip' => 'Historial de cambios para esta modifiación',
'save' => 'Guardar',
'submit' => 'Enviar para revisión',
'autoupdate' => 'Actualización automática',
'showAdjPrev' => 'Mostrar vista previa adyacente',
'preview' => 'Visualizar',
'class-spec' => 'Clase / Spec',
'category' => 'Categoría',
'testGuide' => 'Mira el aspecto de tu guía.',
'images' => 'Imágenes',
'statusTip' => array(
GUIDE_STATUS_DRAFT => 'Tu guía está en estado &quot;borrador&quot; 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 => '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.',
)
),
'category' => array(
null, "Clases", "Profesiones", "Eventos del mundo", "Nuevos Jugadores y Leveling",
"Combates de Bandas y Jefes", "Economía y Dinero", "Logros", "Objetos de vanidad, Mascotas y Monturas", "Otros"
),
'status' => array(
null, "Borrador", "Esperando aprobación", "Aprobado", "Rechazado", "Archivada"
)
),
'profiler' => array(
'realm' => "Reino",
'region' => "Región",
@ -344,6 +409,20 @@ $lang = array(
38 => "Quimera", 39 => "Demosaurio", 41 => "Silítido", 42 => "Gusano", 43 => "Rinoceronte", 44 => "Avispa",
45 => "Can del Núcleo", 46 => "Bestia espíritu"
),
'classSpecs' => array(
-1 => 'Sin talentos',
0 => 'Híbrido',
6 => ['Sangre', 'Escarcha', 'Profano' ],
11 => ['Equilibrio', 'Combate feral', 'Restauración' ],
3 => ['Dominio de bestias', 'Puntería', 'Supervivencia'],
8 => ['Arcano', 'Fuego', 'Escarcha' ],
2 => ['Sagrado', 'Protección', 'Reprensión' ],
5 => ['Disciplina', 'Sagrado', 'Magia sombría'],
4 => ['Asesinato', 'Combate', 'Sutileza' ],
7 => ['Combate elemental', 'Mejora', 'Restauración' ],
9 => ['Aflicción', 'Demonología', 'Destrucción' ],
1 => ['Armas', 'Furia', 'Protección' ]
),
'pvpRank' => array(
null, "Soldado / Explorador", "Cabo / Bruto",
"Sargento / Sargento", "Sargento maestro / Sargento jefe", "Sargento mayor / Sargento primero",

View file

@ -52,8 +52,11 @@ $lang = array(
'or' => " ou ",
'back' => "Redro",
'reputationTip' => "Points de réputation",
'byUserTimeAgo' => 'Par <a href="'.HOST_URL.'/?user=%s">%1$s</a> il y a %s',
'byUser' => 'Par <a href="'.HOST_URL.'/?user=%1$s"%2$s>%1$s</a> ',
'help' => "Aide",
'status' => "Statut",
'yes' => "Oui",
'no' => "Non",
// filter
'extSearch' => "Recherche avancée",
@ -80,6 +83,10 @@ $lang = array(
'compare' => "Comparer",
'view3D' => "Voir en 3D",
'findUpgrades' => "Trouver des améliorations…",
'report' => "Signaler",
'writeGuide' => "Créer un nouveau Guide",
'edit' => "Édition",
'changelog' => 'Journal des changements',
// misc Tools
'errPageTitle' => "Page non trouvée",
@ -120,7 +127,8 @@ $lang = array(
// formating
'colon' => ' : ',
'dateFmtShort' => "Y-m-d",
'dateFmtLong' => "Y-m-d à H:i",
'dateFmtLong' => "Y-m-d à H:i A",
'timeAgo' => 'il y a %s',
// error
'intError' => "[An internal error occured.]",
@ -150,6 +158,63 @@ $lang = array(
)
)
),
'guide' => array(
'guide' => "Guide",
'guides' => "Guides",
'myGuides' => "Mes guides",
'editTitle' => "Editez votre Guide",
'newTitle' => "Créer un nouveau Guide",
'author' => "Auteur",
'spec' => "Spécialisation",
'sticky' => "Statut coller",
'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]",
'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éé',
'clMinorEdit' => 'Modification mineure',
'editor' => array(
'fullTitle' => 'Titre complet',
'fullTitleTip' => 'Le titre complet du guide sera utilisé sur la page du guide et peut contenir des éléments destinés aux moteurs de recherche.',
'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.&lt;br /&gt;&lt;br /&gt;S&apos;il est laissé vide, le résumé sera généré automatiquement.',
// 'commentEmail' => 'Recevoir les commentaires par courriel',
// 'commentEmailTip' => 'L&apos;auteur doit-il recevoir un courriel chaque fois qu&apos;un utilisateur commente ce guide ?',
'changelog' => 'Journal des changements pour cette modification',
'changelogTip' => 'Entrez votre journal de modifications pour cette mise à jour ici.',
'save' => 'Sauver',
'submit' => 'Soumettre pour examen',
'autoupdate' => 'Mise à jour automatique',
'showAdjPrev' => 'Show adjacent preview',
'preview' => 'Aperçu',
'class-spec' => 'Classe / Spé',
'category' => 'Catégorie',
'testGuide' => 'Ayez un aperçu de votre guide',
'images' => 'Images',
'statusTip' => array(
GUIDE_STATUS_DRAFT => 'Votre guide est en statut &quot;Brouillon&quot; et vous êtes le seul à pouvoir le lire. Continuez de l&apos;écrire comme vous le voulez, et quand vous sentez qu&apos;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.',
)
),
'category' => array(
null, "Classes", "Métiers", "Évènements mondiaux", "Nouveaux Joueurs & Montée en niveau",
"Raids & Combats contre des boss","Economie et Argent", "Hauts faits", "Objets tape-à-l'oeil, Compagnons et Montures","Autre"
),
'status' => array(
null, "Brouillon", "Attente d'approbation", "Approuvé", "Rejeter", "Archivé"
)
),
'profiler' => array(
'realm' => "Royaume",
'region' => "Région",
@ -344,6 +409,20 @@ $lang = array(
38 => "Chimère", 39 => "Diablosaure", 41 => "Silithide", 42 => "Ver", 43 => "Rhinocéros", 44 => "Guêpe",
45 => "Chien du Magma", 46 => "Esprit de bête"
),
'classSpecs' => array(
-1 => 'Sans talent',
0 => 'Hybride',
6 => ['Sang', 'Givre', 'Impie' ],
11 => ['Equilibre', 'Combat farouche', 'Restauration' ],
3 => ['Maîtrise des bêtes', 'Précision', 'Survie' ],
8 => ['Arcanes', 'Feu', 'Givre' ],
2 => ['Sacré', 'Protection', 'Vindicte' ],
5 => ['Discipline', 'Sacré', 'Magie de l\'ombre'],
4 => ['Assassinat', 'Combat', 'Finesse' ],
7 => ['Combat élémentaire', 'Amélioration', 'Restauration' ],
9 => ['Affliction', 'Démonologie', 'Destruction' ],
1 => ['Armes', 'Fureur', 'Protection' ]
),
'pvpRank' => array(
null, "Private / Scout", "Corporal / Grunt",
"Sergeant / Sergeant", "Master Sergeant / Senior Sergeant", "Sergeant Major / First Sergeant",

View file

@ -52,8 +52,11 @@ $lang = array(
'or' => " или ",
'back' => "Назад",
'reputationTip' => "Очки репутации",
'byUserTimeAgo' => 'От <a href="'.HOST_URL.'/?user=%s">%1s</a> %s назад',
'byUser' => 'От <a href="'.HOST_URL.'/?user=%1$s"%2$s>%1s</a> ',
'help' => "Справка",
'status' => "Статус",
'yes' => "Да",
'no' => "Нет",
// filter
'extSearch' => "Расширенный поиск",
@ -80,6 +83,10 @@ $lang = array(
'compare' => "Сравнить",
'view3D' => "Посмотреть в 3D",
'findUpgrades' => "Найти лучше…",
'report' => "Жалоба",
'writeGuide' => "Написать новое руководство",
'edit' => "Редактировать",
'changelog' => 'История изменений',
// misc Tools
'errPageTitle' => "Страница не найдена",
@ -120,7 +127,8 @@ $lang = array(
// formating
'colon' => ": ",
'dateFmtShort' => "Y-m-d",
'dateFmtLong' => "Y-m-d в H:i",
'dateFmtLong' => "Y-m-d в H:i A",
'timeAgo' => '%s назад',
// error
'intError' => "[An internal error occured.]",
@ -150,6 +158,63 @@ $lang = array(
)
)
),
'guide' => array(
'guide' => "Руководство",
'guides' => "Руководство",
'myGuides' => "Мои руководства",
'editTitle' => "Редактировать руководство",
'newTitle' => "Написать новое руководство",
'author' => "Автор",
'spec' => "Спек",
'sticky' => "Закрепленный",
'views' => "Просмотры",
'patch' => "Обновление",
'added' => "Добавлено",
'rating' => "Рейтинг",
'votes' => "[span id=guiderating-value]%d[/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' => 'Создано',
'clMinorEdit' => 'Небольшое изменение',
'editor' => array(
'fullTitle' => 'Полный заголовок',
'fullTitleTip' => 'Укажите полное название руководства. Оно будет использоваться в качестве заголовка. Допустимо использование ключевых слов.',
'name' => 'Имя',
'nameTip' => 'Укажите краткое и понятное название руководства. Оно будет использоватья в меню и перечнях руководств.',
'description' => 'Описание',
'descriptionTip' => 'Описание для поисковых систем.&lt;br&gt;&lt;br&gt;Если поле будет оставлено пустым, то сайт сгенерирует описание автоматически.',
// 'commentEmail' => 'E-mail уведомления',
// 'commentEmailTip' => 'Должен ли автор руководства получать e-mail оповещения, когда к руководству оставляют комментарий?',
'changelog' => 'История изменений, внесенных этой правкой',
'changelogTip' => 'Введите вашу историю изменений для текущего патча здесь.',
'save' => 'Сохранить',
'submit' => 'Отправить на одобрение',
'autoupdate' => 'Автообновление',
'showAdjPrev' => 'Открыть окно предварительного просмотра',
'preview' => 'Предварительный просмотр',
'class-spec' => 'Класс / Спек',
'category' => 'Category',
'testGuide' => 'Посмотрите, как будет выглядеть руководство',
'images' => 'Images',
'statusTip' => array(
GUIDE_STATUS_DRAFT => 'Руководство сохранено как &quot;Черновик&quot; — видеть его можете только вы. Правьте руководство так долго, как сочтете нужным, а когда решите, что оно готово — отправьте на одобрение.',
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.',
)
),
'category' => array(
null, "Классы", "Профессии", "Игровые события", "Новые игроки",
"Подземелья и рейды", "Экономика и деньги", "Достижения", "Забавные предметы", "Разное"
),
'status' => array(
null, "Черновик", "Ожидание проверки", "Принято", "Отклонено", "Архивирован"
)
),
'profiler' => array(
'realm' => "Игровой мир",
'region' => "Регион",
@ -344,6 +409,20 @@ $lang = array(
38 => "Химера", 39 => "Дьявозавр", 41 => "Силитид", 42 => "Червь", 43 => "Люторог", 44 => "Оса",
45 => "Гончая Недр", 46 => "Дух зверя"
),
'classSpecs' => array(
-1 => 'Нет талантов',
0 => 'Гибрид',
6 => ['Кровь', 'Лед', 'Нечестивость'],
11 => ['Баланс', 'Сила зверя', 'Исцеление' ],
3 => ['Повелитель зверей', 'Стрельба', 'Выживание' ],
8 => ['Тайная магия', 'Огонь', 'Лед' ],
2 => ['Свет', 'Защита', 'Воздаяние' ],
5 => ['Послушание', 'Свет', 'Темная магия'],
4 => ['Ликвидация', 'Бой', 'Скрытность' ],
7 => ['Стихии', 'Совершенствование', 'Исцеление' ],
9 => ['Колдовство', 'Демонология', 'Разрушение' ],
1 => ['Оружие', 'Неистовство', 'Защита' ]
),
'pvpRank' => array(
null, "Private / Scout", "Corporal / Grunt",
"Sergeant / Sergeant", "Master Sergeant / Senior Sergeant", "Sergeant Major / First Sergeant",

View file

@ -52,8 +52,11 @@ $lang = array(
'or' => "",
'back' => "返回",
'reputationTip' => "声望点数",
'byUserTimeAgo' => '由<a href="'.HOST_URL.'/?user=%s">%1$s</a>%s之前',
'byUser' => '由<a href="'.HOST_URL.'/?user=%1$s"%2$s>%1$s</a>',
'help' => "帮助",
'status' => "状态",
'yes' => "",
'no' => "",
// filter
'extSearch' => "扩展搜索",
@ -80,6 +83,10 @@ $lang = array(
'compare' => "比较",
'view3D' => "3D查看",
'findUpgrades' => "查找升级…",
'report' => "报告",
'writeGuide' => "创建新指南",
'edit' => "编辑",
'changelog' => '[Changelog]',
// misc Tools
'errPageTitle' => "页面未找到",
@ -120,7 +127,8 @@ $lang = array(
// formating
'colon' => '',
'dateFmtShort' => "Y/m/d",
'dateFmtLong' => "Y/m/d \a\\t H:i",
'dateFmtLong' => "Y/m/d \a\\t H:i A",
'timeAgo' => '%s之前',
// error
'intError' => "发生内部错误。",
@ -150,6 +158,63 @@ $lang = array(
)
)
),
'guide' => array(
'guide' => "指南",
'guides' => "指南",
'myGuides' => "我的指南",
'editTitle' => "编辑你的指南",
'newTitle' => "创建新指南",
'author' => "作者",
'spec' => "专精",
'sticky' => "置顶状态",
'views' => "浏览量",
'patch' => "补丁",
'added' => "已添加",
'rating' => "评分",
'votes' => "[span id=guiderating-value]%d[/span]/5 [span id=guiderating-votes][n5=%d][/span] 投票)[span id=guiderating][/span]",
'noVotes' => "[not enough votes] [span id=guiderating][/span]",
'byAuthor' => "来自 %s",
'notFound' => "[This 指南 doesn't exist.]",
'clTitle' => '[Changelog For] "<a href="?guide=%1$d">%2$s</a>"',
'clStatusSet' => '[Status set to] %s',
'clCreated' => '已创建',
'clMinorEdit' => '[Minor Edit]',
'editor' => array(
'fullTitle' => '完整标题',
'fullTitleTip' => '[The full guide title will be used on the guide page and may include SEO-oriented phrasing.]',
'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' => '描述',
'descriptionTip' => '描述将用于说明片段&lt;br /&gt;&lt;br /&gt;如果不填,则自动生成。',
// 'commentEmail' => 'Comment Emails',
// 'commentEmailTip' => 'Should the author get emailed whenever a user comments on this guide?',
'changelog' => '当前编辑的修改日志',
'changelogTip' => '[Enter your changelog for this update here.]',
'save' => '保存',
'submit' => '提交以供审核',
'autoupdate' => '预览',
'showAdjPrev' => '显示相邻预览',
'preview' => '自动更新',
'class-spec' => '职业 / 专精',
'category' => '分类',
'testGuide' => '自我浏览你的指南',
'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.]',
)
),
'category' => array(
null, "职业", "专业", "世界事件", "新玩家",
"地下城与团队副本", "经济与金钱", "成就", "华丽收藏", "杂项"
),
'status' => array(
null, "草稿", "等待审批", "同意", "拒绝", "已归档"
)
),
'profiler' => array(
'realm' => "服务器",
'region' => "区域",
@ -344,6 +409,20 @@ $lang = array(
38 => "奇美拉", 39 => "魔暴龙", 41 => "异种虫", 42 => "蠕虫", 43 => "犀牛", 44 => "巨蜂",
45 => "熔岩犬", 46 => "灵魂兽",
),
'classSpecs' => array(
-1 => '没有天赋',
0 => '混合',
6 => ['鲜血', '冰霜', '邪恶'],
11 => ['平衡', '野性战斗', '恢复'],
3 => ['野兽控制', '射击', '生存'],
8 => ['奥术', '火焰', '冰霜'],
2 => ['神圣', '防护', '惩戒'],
5 => ['戒律', '神圣', '暗影'],
4 => ['刺杀', '战斗', '敏锐'],
7 => ['元素', '增强', '恢复'],
9 => ['痛苦', '恶魔学识', '毁灭'],
1 => ['武器', '狂怒', '防护']
),
'pvpRank' => array(
null, "下士 / 斥候", "下士 / 步兵",
"中士 / 中士", "军士长 / 高阶军士", "士官长 / 一等军士长",

View file

@ -57,13 +57,21 @@ class AdminPage extends GenericPage
array_push($this->path, 2, 16);
$this->name = 'Weight Presets';
break;
case 'guides':
$this->reqUGroup = U_GROUP_STAFF;
$this->generator = 'handleGuideApprove';
$this->tpl = 'list-page-generic';
array_push($this->path, 1, 25);
$this->name = 'Pending Guides';
break;
default: // error out through unset template
}
parent::__construct($pageCall, $pageParam);
}
protected function generateContent()
protected function generateContent() : void
{
if (!$this->generator || function_exists($this->generator))
return;
@ -71,7 +79,7 @@ class AdminPage extends GenericPage
$this->{$this->generator}();
}
private function handleConfig()
private function handleConfig() : void
{
$this->addScript(
[CSS_STRING, '.grid input[type=\'text\'], .grid input[type=\'number\'] { width:250px; text-align:left; }'],
@ -121,7 +129,7 @@ class AdminPage extends GenericPage
)];
}
private function handlePhpInfo()
private function handlePhpInfo() : void
{
$this->addScript([
CSS_STRING, "\npre {margin: 0px; font-family: monospace;}\n" .
@ -185,7 +193,7 @@ class AdminPage extends GenericPage
}
}
private function handleScreenshots()
private function handleScreenshots() : void
{
$this->addScript(
[JS_FILE, 'screenshot.js'],
@ -223,7 +231,7 @@ class AdminPage extends GenericPage
$this->ssNFound = $nMatches; // ssm_numPagesFound
}
private function handleWeightPresets()
private function handleWeightPresets() : void
{
$this->addScript(
[JS_FILE, 'filters.js'],
@ -252,6 +260,26 @@ class AdminPage extends GenericPage
$this->extraHTML = '<script type="text/javascript">var wt_presets = '.Util::toJSON($weights).";</script>\n\n";
}
private function handleGuideApprove() : void
{
$pending = new GuideList([['status', GUIDE_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[] = ['guide', array(
'data' => array_values($data),
'hiddenCols' => ['patch', 'comments', 'views', 'rating'],
'extraCols' => '$_'
), 'guideAdminCol'];
}
private function configAddRow($r)
{
$buff = '<tr>';

View file

@ -233,7 +233,8 @@ class GenericPage
'title' => ['template' => 'title', 'id' => 'titles', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_titles' ],
'topusers' => ['template' => 'topusers', 'id' => 'topusers', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.topusers' ],
'video' => ['template' => 'video', 'id' => 'videos', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_videos' ],
'zone' => ['template' => 'zone', 'id' => 'zones', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_zones' ]
'zone' => ['template' => 'zone', 'id' => 'zones', 'parent' => 'lv-generic', 'data' => [], 'name' => '$LANG.tab_zones' ],
'guide' => ['template' => 'guide', 'id' => 'guides', 'parent' => 'lv-generic', 'data' => [], ]
);
public function __construct(string $pageCall = '', string $pageParam = '')
@ -363,18 +364,24 @@ class GenericPage
{
if (!$this->loadCache())
{
$this->addArticle();
$this->generateContent();
$this->generatePath();
$this->generateTitle();
$this->addArticle();
$this->applyGlobals();
$this->saveCache();
}
if (isset($this->type) && isset($this->typeId))
if ($this instanceof GuidePage)
{
$this->gPageInfo = ['name' => $this->name];
if (isset($this->author))
$this->gPageInfo['author'] = $this->author;
}
else if (isset($this->type) && isset($this->typeId))
{
$this->gPageInfo = array( // varies slightly for special pages like maps, user-dashboard or profiler
'type' => $this->type,
@ -382,7 +389,9 @@ class GenericPage
'name' => $this->name
);
}
else if (!empty($this->articleUrl))
// only adds edit links to the staff menu: precursor to guides?
if (!empty($this->articleUrl) && !($this instanceof GuidePage && $this->show == GuidePage::SHOW_GUIDE))
{
$this->gPageInfo = array(
'articleUrl' => $this->fullParams, // is actually be the url-param
@ -462,19 +471,19 @@ class GenericPage
// get article & static infobox (run before processing jsGlobals)
private function addArticle() :void
{
if (isset($this->article))
return;
$article = [];
if (!empty($this->type) && isset($this->typeId))
{
$article = DB::Aowow()->selectRow('SELECT article, quickInfo, locale, editAccess FROM ?_articles WHERE type = ?d AND typeId = ?d AND locale = ?d UNION ALL SELECT article, quickInfo, locale, editAccess FROM ?_articles WHERE type = ?d AND typeId = ?d AND locale = 0 ORDER BY locale DESC LIMIT 1',
$this->type, $this->typeId, User::$localeId, $this->type, $this->typeId
);
}
if (isset($this->guideRevision))
$article = DB::Aowow()->selectRow('SELECT `article`, `quickInfo`, `locale`, `editAccess` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d AND `rev` = ?d',
Type::GUIDE, $this->typeId, $this->guideRevision);
else if (!empty($this->articleUrl))
{
$article = DB::Aowow()->selectRow('SELECT article, quickInfo, locale, editAccess FROM ?_articles WHERE url = ? AND locale = ?d UNION ALL SELECT article, quickInfo, locale, editAccess FROM ?_articles WHERE url = ? AND locale = 0 ORDER BY locale DESC LIMIT 1',
$this->articleUrl, User::$localeId, $this->articleUrl
);
}
$article = DB::Aowow()->selectRow('SELECT `article`, `quickInfo`, `locale`, `editAccess` FROM ?_articles WHERE `url` = ? AND `locale` IN (?a) ORDER BY `locale`, `rev` DESC LIMIT 1',
$this->articleUrl, [User::$localeId, LOCALE_EN]);
else if (!empty($this->type) && isset($this->typeId))
$article = DB::Aowow()->selectRow('SELECT `article`, `quickInfo`, `locale`, `editAccess` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d AND `locale` IN (?a) ORDER BY `locale`, `rev` DESC LIMIT 1',
$this->type, $this->typeId, [User::$localeId, LOCALE_EN]);
if ($article)
{
@ -730,6 +739,9 @@ class GenericPage
{
$buff = '';
if (!empty($this->guideRating))
$buff .= sprintf(Util::$guideratingString, ...$this->guideRating);
foreach ($this->jsGlobals as $type => $struct)
{
$buff .= " var _ = ".$struct[0].';';

555
pages/guide.php Normal file
View file

@ -0,0 +1,555 @@
<?php
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 /* 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;
protected /* int */ $articleUrl = '';
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 = [];
protected /* array */ $_get = array(
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt'],
'rev' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt']
);
protected /* array */ $_post = array(
'save' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkEmptySet'],
'submit' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkEmptySet'],
'title' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
'name' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
'description' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
'changelog' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
'body' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkFulltext'],
'locale' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt'],
'category' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt'],
'specId' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt'],
'classId' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt']
);
public function __construct($pageCall, $pageParam)
{
$this->contribute = CONTRIBUTE_CO;
$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([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::guide('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::guide('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!?')
};
*/
switch ($this->show)
{
case self::SHOW_NEW:
$this->displayNew();
break;
case self::SHOW_EDITOR:
$this->displayEditor();
break;
case self::SHOW_GUIDE:
$this->displayGuide();
break;
case self::SHOW_CHANGELOG:
$this->displayChangelog();
break;
default:
trigger_error('GuidePage::generateContent - what content!?');
}
}
private function displayNew() : void
{
// init required template vars
$this->editorFields = array(
'locale' => User::$localeId,
'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::guide('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, $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((new Markup($this->_post['body']))->stripTags(), 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->rating['avg'], 1), $this->rating['n']]);
}
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([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([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.`displayName` 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(
[JS_FILE, 'article-description.js'],
[JS_FILE, 'article-editing.js'],
[JS_FILE, 'guide-editing.js'],
[JS_FILE, 'fileuploader.js'],
[JS_FILE, 'toolbar.js'],
[JS_FILE, 'AdjacentPreview.js'],
[CSS_FILE, 'article-editing.css'],
[CSS_FILE, 'fileuploader.css'],
[CSS_FILE, 'guide-edit.css'],
[CSS_FILE, 'AdjacentPreview.css'],
[CSS_STRING, '#upload-result input[type=text] { padding: 0px 2px; font-size: 12px; }'],
[CSS_STRING, '#upload-result > span { display:block; height: 22px; }'],
[CSS_STRING, '#upload-result { display: inline-block; text-align:right; }'],
[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(
[JS_FILE, 'article-description.js'],
[JS_FILE, 'article-editing.js'],
[JS_FILE, 'guide-editing.js'],
[JS_FILE, 'fileuploader.js'],
[JS_FILE, 'toolbar.js'],
[JS_FILE, 'AdjacentPreview.js'],
[CSS_FILE, 'article-editing.css'],
[CSS_FILE, 'fileuploader.css'],
[CSS_FILE, 'guide-edit.css'],
[CSS_FILE, 'AdjacentPreview.css'],
[CSS_STRING, '#upload-result input[type=text] { padding: 0px 2px; font-size: 12px; }'],
[CSS_STRING, '#upload-result > span { display:block; height: 22px; }'],
[CSS_STRING, '#upload-result { display: inline-block; text-align:right; }'],
[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_LOCALES & (1 << $this->_post['locale'])))
return false;
// sanitize: spec / class
if ($this->_post['category'] == 1) // Classes
{
if ($this->_post['classId'] && !((1 << $this->_post['classId']) & CLASS_MASK_ALL))
$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_'.User::$localeString} = $this->name;
$power->{'tooltip_'.User::$localeString} = $this->subject->renderTooltip();
}
return sprintf($this->powerTpl, Util::toJSON($this->articleUrl ?: $this->typeId), User::$localeId, 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::guide('guides'));
if ($this->show == self::SHOW_NEW)
array_unshift($this->title, Lang::guide('newTitle'), Lang::guide('guides'));
else
array_unshift($this->title, $this->subject->getField('title'), Lang::guide('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);
}
}
?>

100
pages/guides.php Normal file
View file

@ -0,0 +1,100 @@
<?php
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::$id)
$this->error();
$this->name = Util::ucFirst(Lang::guide('myGuides'));
$this->myGuides = true;
}
else
$this->name = Util::ucFirst(Lang::guide('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', User::$localeId],
['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::guide('guides')),
'hiddenCols' => $hCols,
'visibleCols' => $vCols,
'extraCols' => $xCols
);
$this->lvTabs[] = [GuideList::$brickFile, $tabData];
$this->redButtons = [BUTTON_GUIDE_NEW => User::$id && User::canComment()];
}
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];
}
}
?>

View file

@ -60,7 +60,8 @@ class UserPage extends GenericPage
// contrib -> [url=http://www.wowhead.com/client]Data uploads: n [small]([tooltip=tooltip_totaldatauploads]xx.y MB[/tooltip])[/small][/url]
$co = DB::Aowow()->selectRow(
'SELECT COUNT(DISTINCT c.id) AS sum, SUM(IFNULL(cr.value, 0)) AS nRates FROM ?_comments c LEFT JOIN ?_comments_rates cr ON cr.commentId = c.id AND cr.userId <> 0 WHERE c.replyTo = 0 AND c.userId = ?d',
'SELECT COUNT(DISTINCT c.id) AS sum, SUM(IFNULL(ur.value, 0)) AS nRates FROM ?_comments c LEFT JOIN ?_user_ratings ur ON ur.entry = c.id AND ur.type = ?d AND ur.userId <> 0 WHERE c.replyTo = 0 AND c.userId = ?d',
RATING_COMMENT,
$this->user['id']
);
if ($co['sum'])

View file

@ -13,7 +13,7 @@ class UtilityPage extends GenericPage
protected $tabId = 1;
protected $mode = CACHE_TYPE_NONE;
protected $validPages = array(
'latest-additions', 'latest-articles', 'latest-comments', 'latest-screenshots', 'random',
null, null, 'latest-comments', 'latest-screenshots', 'random',
'unrated-comments', 11 => 'latest-videos', 12 => 'most-comments', 13 => 'missing-screenshots'
);
@ -63,7 +63,7 @@ class UtilityPage extends GenericPage
/* Main Content */
/****************/
if (in_array(array_search($this->page, $this->validPages), [0, 1, 2, 3, 11, 12]))
if (in_array(array_search($this->page, $this->validPages), [2, 3, 11, 12]))
$this->h1Links = '<small><a href="?'.$this->page.($this->category ? '='.$this->category[0] : null).'&rss" class="icon-rss">'.Lang::main('subscribe').'</a></small>';
switch ($this->page)
@ -151,14 +151,28 @@ class UtilityPage extends GenericPage
else
$this->lvTabs[] = ['video', ['data' => array_values($data)]];
break;
case 'latest-articles': // rss
$this->lvTabs = [];
break;
case 'latest-additions': // rss
$extraText = '';
break;
case 'unrated-comments':
// EXPLAIN SELECT ac.* FROM aowow_comments ac LEFT JOIN aowow_comments_rates acr ON acr.commentId = ac.id AND acr.userId <> 0 WHERE acr.commentId IS NULL;
if ($_ = CommunityContent::getCommentPreviews(['user' => User::$id, 'replies' => false], $nFound))
{
$tabData = array(
'data' => $_,
'onBeforeCreate' => '$Listview.funcBox.beforeUserComments',
'_totalCount' => $nFound
);
if ($nFound > CFG_SQL_LIMIT_DEFAULT)
{
$tabData['name'] = '$LANG.tab_latestcomments';
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_usercomments, '.$nFound.')';
}
$this->lvTabs[] = ['commentpreview', $tabData];
}
$this->lvTabs[] = ['commentpreview', ['data' => []]];
break;
case 'missing-screenshots':

File diff suppressed because one or more lines are too long

View file

@ -345,6 +345,23 @@ var Markup = {
return str.replace(/<br\b[\s\S]*?>/gi, "\n");
}
},
changelog:
{
empty: false,
attr:
{
open: { req: false, valid: /^true$/ }
},
allowedClass: MARKUP_CLASS_STAFF,
toHtml: function (attr) {
var e = '<a id="revealtoggle-changelog" class="revealtoggle changelog" href="javascript:;" onclick="Markup.toggleReveal(\'changelog\');">Show Changelog</a>';
var c = "display: none";
if (attr.open == "true") {
e = c = "";
}
return ['<div style="margin: 1em 0" id="guide-changelog"><div id="reveal-changelog" style="' + c + '"><h3 class="heading-size-3">Changelog</h3>', "</div>" + e + "</div>"];
}
},
'class':
{
empty: true,
@ -417,7 +434,12 @@ var Markup = {
},
allowedClass: MARKUP_CLASS_STAFF,
/* Syntax: name: class */
extraColors: {deathknight: 'c6', dk: 'c6', druid: 'c11', hunter: 'c3', mage: 'c8', paladin: 'c2', priest: 'c5', rogue: 'c4', shaman: 'c7', warlock: 'c9', warrior: 'c1', poor: 'q0', common: 'q1', uncommon: 'q2', rare: 'q3', epic: 'q4', legendary: 'q5', artifact: 'q6', heirloom: 'q7'},
extraColors: {
deathknight: 'c6', dk: 'c6', druid: 'c11', hunter: 'c3', mage: 'c8', paladin: 'c2', priest: 'c5', rogue: 'c4', shaman: 'c7', warlock: 'c9', warrior: 'c1', poor: 'q0', common: 'q1', uncommon: 'q2', rare: 'q3', epic: 'q4', legendary: 'q5', artifact: 'q6', heirloom: 'q7',
'meta-gem': 'gem1', 'red-gem': 'gem2', 'yellow-gem': 'gem4', 'orange-gem': 'gem6', 'blue-gem': 'gem8', 'purple-gem': 'gem10', 'green-gem': 'gem12', 'prismatic-gem': 'gem14',
yell: 's1', say: 's2', whsiper: 's3', emote: 's4',
hated: 'rep0', hostile: 'rep1', unfriendly: 'rep2', neutral: 'rep3', friendly: 'rep4', honored: 'rep5', revered: 'rep6', exalted: 'rep7'
},
toHtml: function(attr)
{
var valid = /^(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow|c\d+|r\d+|q\d*?|#[a-f0-9]{6})$/i;
@ -839,7 +861,7 @@ var Markup = {
if(attr.style && Markup.allow >= Markup.CLASS_STAFF)
styles.push(attr.style);
if(styles.length)
str += ' styles="' + styles.join(';') + '"';
str += ' style="' + styles.join(';') + '"';
return [str + '>', '</h2>'];
},
fromHtml: function(str)
@ -877,7 +899,7 @@ var Markup = {
if(attr.style && Markup.allow >= Markup.CLASS_STAFF)
styles.push(attr.style);
if(styles.length)
str += ' styles="' + styles.join(';') + '"';
str += ' style="' + styles.join(';') + '"';
return [str + '>', '</h3>'];
},
fromHtml: function(str)
@ -2973,7 +2995,7 @@ var Markup = {
trim: true,
ltrim: true,
rtrim: true,
collect: { h2: 1, h3: 1 },
collect: { h2: 1, h3: 1, changelog: 1 },
exclude: { tabs: { h2: 1, h3: 1 }, minibox: { h2: 1, h3: 1 } },
allowedClass: MARKUP_CLASS_STAFF,
attr:
@ -2999,6 +3021,8 @@ var Markup = {
myNodes.push(nodes.h2[node]);
for(var node in nodes.h3)
myNodes.push(nodes.h3[node]);
for(var node in nodes.changelog)
myNodes.push(nodes.changelog[node]);
myNodes.sort(function(a, b) {
return a.offset - b.offset;
});
@ -3006,7 +3030,17 @@ var Markup = {
for(var i in myNodes)
{
node = myNodes[i];
if(node.name == 'h2' && node.attr.toc != 'false')
if(node.name == 'changelog')
{
if (lastNode == "h3")
{
str += "</ul>";
indent--;
}
str += "<li><b><a href='#guide-changelog' onclick=\"Markup.toggleReveal('changelog');\">Changelog</a></b></li>";
lastNode = "h2";
}
if(node.name == 'h2' && node.attr.toc !== false)
{
if(lastNode == 'h3')
{
@ -3016,7 +3050,7 @@ var Markup = {
str += '<li><b><a href=\'#' + (node.attr.id ? g_urlize(node.attr.id) : g_urlize(node.attr._textContents)) + '\'>' + node.attr._textContents + '</a></b></li>';
lastNode = 'h2';
}
if(node.name == 'h3' && allowH3 && node.attr.toc != 'false' && (lastNode != '' || nodes.h2.length == 0))
if(node.name == 'h3' && allowH3 && node.attr.toc !== false && (lastNode != '' || nodes.h2.length == 0))
{
if(lastNode == 'h2')
{
@ -4253,7 +4287,10 @@ var Markup = {
else
{
span.show();
toggle.text('(hide)');
if (toggle.hasClass('changelog'))
toggle.hide();
else
toggle.text('(hide)');
}
},

View file

@ -37,6 +37,7 @@ if (typeof $WowheadPower == "undefined") {
itemsets = {},
currencies = {},
profiles = {},
guides = {},
showLogo = 1,
@ -61,14 +62,18 @@ if (typeof $WowheadPower == "undefined") {
TYPE_HOLIDAY = 12,
TYPE_CURRENCY = 17,
TYPE_PROFILE = 100,
TYPE_GUIDE = 300,
CURSOR_HSPACE = 15,
CURSOR_VSPACE = 15,
_LANG = {
loading: "Loading...",
noresponse: "No response from server :(",
achievementcomplete: "Achievement earned by $1 on $2/$3/$4"
0: { achievementComplete: "Achievement earned by $1 on $2/$3/$4", loading: "Loading…", noResponse: "No response from server :(", notFound: "%s Not Found" },
2: { achievementComplete: "Haut-fait reçu par $1 le $2/$3/$4", loading: "Chargement…", noResponse: "Pas de réponse du serveur :(", notFound: "%s non trouvé" },
3: { achievementComplete: "Erfolg wurde von $1 am $3.$2.$4 errungen", loading: "Lädt…", noResponse: "Keine Antwort vom Server :(", notFound: "%s nicht gefunden" },
4: { achievementComplete: "$1在$2/$3/$4上获得成就", loading: "正在载入…", noResponse: "服务器没有响应 :(", notFound: "%s未找到" },
8: { achievementComplete: "$1 получил(а) это достижение $2/$3/$4", loading: "Загрузка…", noResponse: "Нет ответа от сервера :(", notFound: "%s не найдено" },
6: { achievementComplete: "Logro conseguido por $1 el $2/$3/$4", loading: "Cargando…", noResponse: "No hay respuesta del servidor :(", notFound: "%s no encontrado/a" },
},
LOOKUPS = {
1: [npcs, "npc", "NPC" ],
@ -80,7 +85,8 @@ if (typeof $WowheadPower == "undefined") {
10: [achievements, "achievement", "Achievement"],
12: [holidays, "event", "Holiday" ],
17: [currencies, "currency", "Currency" ],
100: [profiles, "profile", "Profile" ]
100: [profiles, "profile", "Profile" ],
300: [guides, "guide", "Guide" ]
},
SCALES = {
3: { url: "?data=item-scaling" },
@ -285,7 +291,7 @@ if (typeof $WowheadPower == "undefined") {
url = t.href.match(/^https?:\/\/(.*)\/?\??(item|quest|spell|achievement|event|npc|object|itemset|currency)=(-?[0-9]+)/);
if (url == null) {
// url = t.href.match(/^http:\/\/(.+?)?\.?wowhead\.com\/\?(profile)=([^&#]+)/)
url = t.href.match(/^https?:\/\/(.*)\/?\??(profile)=([^&#]+)/);
url = t.href.match(/^https?:\/\/(.*)\/?\??(profile|guide)=([^&#]+)/);
}
showLogo = 0;
@ -293,7 +299,7 @@ if (typeof $WowheadPower == "undefined") {
else {
url = t.href.match(/()\?(item|quest|spell|achievement|event|npc|object|itemset|currency)=(-?[0-9]+)/);
if (url == null) {
url = t.href.match(/()\?(profile)=([^&#]+)/);
url = t.href.match(/()\?(profile|guide)=([^&#]+)/);
}
showLogo = 1;
@ -311,6 +317,10 @@ if (typeof $WowheadPower == "undefined") {
showLogo = 1;
}
// aowow - skip protected guide names
if (url && url[2] == 'guide' && (url[3] == 'new' || url[3] == 'edit' || url[3] == 'changelog'))
return;
t.href.replace(/([a-zA-Z]+)=?([a-zA-Z0-9:-]*)/g, p);
if (rel) {
rel.replace(/([a-zA-Z]+)=?([a-zA-Z0-9:-]*)/g, p);
@ -520,7 +530,7 @@ if (typeof $WowheadPower == "undefined") {
showTooltip(arr[fullId][getTooltipField(locale)], arr[fullId][getIconField()], arr[fullId].map, arr[fullId][getSpellsField(locale)], arr[fullId][getTooltipField(locale, 2)]);
}
else if (arr[fullId].status[locale] == STATUS_QUERYING || arr[fullId].status[locale] == STATUS_SCALES) {
showTooltip(_LANG.loading);
showTooltip(_LANG[locale].loading);
}
else {
request(type, id, locale, null, params);
@ -582,54 +592,52 @@ if (typeof $WowheadPower == "undefined") {
initCSS();
var notFound = false;
if (!html) {
html = LOOKUPS[currentType][2] + " not found :(";
html = $WH.sprintf(_LANG[currentLocale].notFound, LOOKUPS[currentType][2]);
icon = "inv_misc_questionmark";
notFound = true;
}
else {
if (currentParams != null) {
if (currentParams.pcs && currentParams.pcs.length) {
var n = 0;
for (var i = 0, len = currentParams.pcs.length; i < len; ++i) {
var m;
if (m = html.match(new RegExp("<span><!--si([0-9]+:)*" + currentParams.pcs[i] + '(:[0-9]+)*--><a href="\\?item=(\\d+)">(.+?)</a></span>'))) {
html = html.replace(m[0], '<span class="q8"><!--si' + currentParams.pcs[i] + '--><a href="?item=' + m[3] + '">' + (($WH.isset("g_items") && g_items[currentParams.pcs[i]]) ? g_items[currentParams.pcs[i]]["name_" + LOCALES[currentLocale]] : m[4]) + "</a></span>");
++n;
}
}
if (n > 0) {
html = html.replace("(0/", "(" + n + "/");
html = html.replace(new RegExp("<span>\\(([0-" + n + "])\\)", "g"), '<span class="q2">($1)');
else if (currentParams != null) {
if (currentParams.pcs && currentParams.pcs.length) {
var n = 0;
for (var i = 0, len = currentParams.pcs.length; i < len; ++i) {
var m;
if (m = html.match(new RegExp("<span><!--si([0-9]+:)*" + currentParams.pcs[i] + '(:[0-9]+)*--><a href="\\?item=(\\d+)">(.+?)</a></span>'))) {
html = html.replace(m[0], '<span class="q8"><!--si' + currentParams.pcs[i] + '--><a href="?item=' + m[3] + '">' + (($WH.isset("g_items") && g_items[currentParams.pcs[i]]) ? g_items[currentParams.pcs[i]]["name_" + LOCALES[currentLocale]] : m[4]) + "</a></span>");
++n;
}
}
if (currentParams.c) {
html = html.replace(/<span class="c([0-9]+?)">(.+?)<\/span><br \/>/g, '<span class="c$1" style="display: none">$2</span>');
html = html.replace(new RegExp('<span class="c(' + currentParams.c + ')" style="display: none">(.+?)</span>', "g"), '<span class="c$1">$2</span><br />');
if (n > 0) {
html = html.replace("(0/", "(" + n + "/");
html = html.replace(new RegExp("<span>\\(([0-" + n + "])\\)", "g"), '<span class="q2">($1)');
}
}
if (currentParams.know && currentParams.know.length) {
html = $WH.g_setTooltipSpells(html, currentParams.know, spellData);
}
if (currentParams.c) {
html = html.replace(/<span class="c([0-9]+?)">(.+?)<\/span><br \/>/g, '<span class="c$1" style="display: none">$2</span>');
html = html.replace(new RegExp('<span class="c(' + currentParams.c + ')" style="display: none">(.+?)</span>', "g"), '<span class="c$1">$2</span><br />');
}
if (currentParams.lvl) {
html = $WH.g_setTooltipLevel(html, currentParams.lvl, currentParams.buff);
}
// custom start
else if ($WH.gc('compare_level') && window.location.href.match(/\?compare/i)) {
html = $WH.g_setTooltipLevel(html, $WH.gc('compare_level'), currentParams.buff);
}
// custom end
if (currentParams.know && currentParams.know.length) {
html = $WH.g_setTooltipSpells(html, currentParams.know, spellData);
}
if (currentParams.who && currentParams.when) {
html = html.replace("<table><tr><td><br />", '<table><tr><td><br /><span class="q2">' + $WH.sprintf(_LANG.achievementcomplete, currentParams.who, currentParams.when.getMonth() + 1, currentParams.when.getDate(), currentParams.when.getFullYear()) + "</span><br /><br />");
html = html.replace(/class="q0"/g, 'class="r3"');
}
if ((currentType == TYPE_ACHIEVEMENT) && currentParams.cri) {
for (var i = 0; i < currentParams.cri.length; i++) {
html = html.replace(new RegExp("<!--cr" + parseInt(currentParams.cri[i]) + ":[^<]+", "g"), '<span class="q2">$&</span>')
}
if (currentParams.lvl) {
html = $WH.g_setTooltipLevel(html, currentParams.lvl, currentParams.buff);
}
// custom start
else if ($WH.gc('compare_level') && window.location.href.match(/\?compare/i)) {
html = $WH.g_setTooltipLevel(html, $WH.gc('compare_level'), currentParams.buff);
}
// custom end
if (currentParams.who && currentParams.when) {
html = html.replace("<table><tr><td><br />", '<table><tr><td><br /><span class="q2">' + $WH.sprintf(_LANG[currentLocale].achievementComplete, currentParams.who, currentParams.when.getMonth() + 1, currentParams.when.getDate(), currentParams.when.getFullYear()) + "</span><br /><br />");
html = html.replace(/class="q0"/g, 'class="r3"');
}
if ((currentType == TYPE_ACHIEVEMENT) && currentParams.cri) {
for (var i = 0; i < currentParams.cri.length; i++) {
html = html.replace(new RegExp("<!--cr" + parseInt(currentParams.cri[i]) + ":[^<]+", "g"), '<span class="q2">$&</span>')
}
}
}
@ -654,7 +662,7 @@ if (typeof $WowheadPower == "undefined") {
function showLoading(type, id, locale) {
if (currentType == type && currentId == id && currentLocale == locale) {
showTooltip(_LANG.loading);
showTooltip(_LANG[locale].loading);
var arr = LOOKUPS[type][0];
arr[id].timer = setTimeout(function () {
@ -668,7 +676,7 @@ if (typeof $WowheadPower == "undefined") {
arr[id].status[locale] = STATUS_ERROR;
if (currentType == type && currentId == id && currentLocale == locale) {
showTooltip(_LANG.noresponse);
showTooltip(_LANG[locale].noResponse);
}
}
@ -774,6 +782,10 @@ if (typeof $WowheadPower == "undefined") {
this.register(TYPE_PROFILE, id, locale, json);
};
this.registerGuide = function (id, locale, json) {
this.register(TYPE_GUIDE, id, locale, json);
};
this.displayTooltip = function (type, id, locale, params) {
display(type, id, locale, params);
};

View file

@ -0,0 +1,47 @@
-- create new tables
DROP TABLE IF EXISTS `aowow_guides`, `aowow_guides_changelog`, `aowow_user_ratings`;
CREATE TABLE `aowow_guides` (
`id` mediumint unsigned NOT NULL AUTO_INCREMENT,
`category` smallint unsigned NOT NULL DEFAULT '0',
`classId` tinyint unsigned DEFAULT NULL,
`specId` tinyint DEFAULT NULL,
`title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'title for menus + lists',
`name` varchar(100) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'title for the page tiself',
`description` varchar(200) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`url` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`locale` tinyint unsigned NOT NULL DEFAULT '0',
`status` tinyint unsigned NOT NULL DEFAULT '1',
`rev` tinyint unsigned NOT NULL DEFAULT '0',
`cuFlags` int unsigned NOT NULL DEFAULT '0',
`roles` smallint unsigned NOT NULL DEFAULT '0',
`views` mediumint unsigned NOT NULL DEFAULT '0',
`userId` mediumint unsigned DEFAULT NULL,
`date` int unsigned NOT NULL DEFAULT '0',
`approveUserId` mediumint unsigned DEFAULT NULL,
`approveDate` int unsigned NOT NULL DEFAULT '0',
`deleteUserId` mediumint unsigned DEFAULT NULL,
`deleteData` int unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `aowow_guides_changelog` (
`id` mediumint unsigned NOT NULL,
`rev` tinyint unsigned DEFAULT NULL,
`date` int unsigned NOT NULL,
`userId` mediumint unsigned NOT NULL,
`status` tinyint unsigned NOT NULL DEFAULT '0',
`msg` varchar(200) COLLATE utf8mb4_general_ci DEFAULT '',
KEY `id` (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `aowow_user_ratings` (
`type` enum('Comment','Guide') COLLATE utf8mb4_unicode_ci NOT NULL,
`entry` int NOT NULL DEFAULT '0',
`userId` int unsigned NOT NULL DEFAULT '0' COMMENT 'User ID',
`value` tinyint NOT NULL DEFAULT '0' COMMENT 'Rating Set',
PRIMARY KEY (`type`,`entry`,`userId`),
KEY `FK_acc_co_rate_user` (`userId`),
CONSTRAINT `FK_userId` FOREIGN KEY (`userId`) REFERENCES `aowow_account` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View file

@ -0,0 +1,17 @@
SET FOREIGN_KEY_CHECKS=0;
-- move comments over to new table
INSERT INTO `aowow_user_ratings` SELECT 1, `commentId`, `userId`, `value` FROM `aowow_comments_rates`;
-- drop aowow_comment_rates at own discretion
-- modify aowow_articles
ALTER TABLE `aowow_articles` DROP KEY `type`, DROP KEY `locale_url`;
ALTER TABLE `aowow_articles` ADD `rev` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `url`;
ALTER TABLE `aowow_articles` MODIFY COLUMN `editAccess` SMALLINT(5) UNSIGNED DEFAULT 2 NOT NULL;
ALTER TABLE `aowow_articles` ADD UNIQUE KEY `type_id_locale` (`type`,`typeId`,`locale`,`rev`), ADD UNIQUE KEY `url_locale` (`url`,`locale`,`rev`);
REPLACE INTO `aowow_articles` (`locale`,`url`,`article`) VALUES
(0,'new','Any user can write a guide and then share it with the community. Before a guide will be available to the public, it will be put in a queue where it can be approved or rejected by the staff. We suggest that you make sure your guide is complete before you put it through this process. A complete guide will generally be thorough, 100% accurate for World of Warcraft''s current build, and include details such as images.\n\n[h3]Tips For Creating Quality Guides[/h3]\n\n[ul][li][b]Use [url=?help=markup-guide]Aowow''s BBCode[/url].[/b][/li]\n[li][b]Choose the correct category.[/b] Guides placed in the wrong category risk being rejected. Don''t see your category? Email [feedback]![/li]\n[li][b]Always submit only complete guides.[/b] You can save in-progress ones indefinitely so you won''t risk losing them.[/li]\n[li][b]Make sure it''s on a unique topic with unique advice.[/b] If someone has already covered your topic, make sure that your guide offers something different and/or better advice or else it may be downvoted by our community.[/li]\n[li][b]Extremely short guides may be better off as a comment.[/b] Though overall there is no predetermined length for a good guide.[/li]\n[li][b]We do not tolerate plagiarism in any form.[/b] Make sure to include credits to other sources and a hyperlink if you use their images or otherwise.[/li][/ul]'),
(0,'edit','Any user can write a guide and then share it with the community. Before a guide will be available to the public, it will be put in a queue where it can be approved or rejected by the staff. We suggest that you make sure your guide is complete before you put it through this process. A complete guide will generally be thorough, 100% accurate for World of Warcraft''s current build, and include details such as images.\n\n[h3]Tips For Creating Quality Guides[/h3]\n\n[ul][li][b]Use [url=?help=markup-guide]Aowow''s BBCode[/url].[/b][/li]\n[li][b]Choose the correct category.[/b] Guides placed in the wrong category risk being rejected. Don''t see your category? Email [feedback]![/li]\n[li][b]Always submit only complete guides.[/b] You can save in-progress ones indefinitely so you won''t risk losing them.[/li]\n[li][b]Make sure it''s on a unique topic with unique advice.[/b] If someone has already covered your topic, make sure that your guide offers something different and/or better advice or else it may be downvoted by our community.[/li]\n[li][b]Extremely short guides may be better off as a comment.[/b] Though overall there is no predetermined length for a good guide.[/li]\n[li][b]We do not tolerate plagiarism in any form.[/b] Make sure to include credits to other sources and a hyperlink if you use their images or otherwise.[/li][/ul]');
SET FOREIGN_KEY_CHECKS=1;

View file

@ -0,0 +1,63 @@
@media screen and (max-width: 999px) {
.adjacent-preview-controls {
display: none !important;
}
}
@media screen and (min-width: 1000px) {
.adjacent-preview-controls {
display: none;
margin: 10px 0;
}
.adjacent-preview-controls label {
background: #181818;
border-radius: 6px;
cursor: pointer;
float: left;
padding: 10px;
}
.adjacent-preview-controls label:hover {
color: #fff;
}
.adjacent-preview-controls input[type="checkbox"] {
position: relative;
top: 2px;
}
.adjacent-preview-controls:after {
clear: left;
content: " ";
display: block;
}
body[data-adjacent-preview="enabled"] {
overflow: hidden;
}
body[data-adjacent-preview="enabled"] .adjacent-preview {
background: #242424;
border-top: 2px solid #181818;
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 40px;
z-index: 100;
}
body[data-adjacent-preview="enabled"] .adjacent-preview .adjacent-preview-edit,
body[data-adjacent-preview="enabled"] .adjacent-preview .adjacent-preview-preview {
bottom: 0;
left: 0;
overflow: auto;
padding: 10px;
position: absolute;
right: 0;
top: 0;
}
body[data-adjacent-preview="enabled"] .adjacent-preview .adjacent-preview-edit > *:first-child,
body[data-adjacent-preview="enabled"] .adjacent-preview .adjacent-preview-preview > *:first-child {
margin-top: 0;
}
body[data-adjacent-preview="enabled"] .adjacent-preview .adjacent-preview-edit {
right: 50%;
}
body[data-adjacent-preview="enabled"] .adjacent-preview .adjacent-preview-preview {
left: 50%;
}
}

View file

@ -4102,27 +4102,30 @@ a.progressbar:hover del {
width: 16px;
height: 16px;
background: url(../images/ui/misc/toolbar.png) no-repeat;
margin-top: 2px;
}
.toolbar img.toolbar-b { background-position: 0 0 !important; }
.toolbar img.toolbar-i { background-position: -16px 0 !important; }
.toolbar img.toolbar-u { background-position: -32px 0 !important; }
.toolbar img.toolbar-s { background-position: -48px 0 !important; }
.toolbar img.toolbar-url { background-position: -64px 0 !important; }
.toolbar img.toolbar-small { background-position: -80px 0 !important; }
.toolbar img.toolbar-quote { background-position: -96px 0 !important; }
.toolbar img.toolbar-code { background-position: -112px 0 !important; }
.toolbar img.toolbar-ul { background-position: -128px 0 !important; }
.toolbar img.toolbar-ol { background-position: -144px 0 !important; }
.toolbar img.toolbar-li { background-position: -160px 0 !important; }
.toolbar img.toolbar-img { background-position: -176px 0 !important; }
.toolbar img.toolbar-thumb { background-position: -192px 0 !important; }
.toolbar img.toolbar-title { background-position: -208px 0 !important; }
.toolbar img.toolbar-pad { background-position: -224px 0 !important; }
.toolbar img.toolbar-winners { background-position: -240px 0 !important; }
.toolbar img.toolbar-prizes { background-position: -256px 0 !important; }
.toolbar img.toolbar-entryform { background-position: -272px 0 !important; }
.toolbar img.toolbar-fromhtml { background-position: -288px 0 !important; }
.toolbar img.toolbar-b { background-position: 0 0 !important; }
.toolbar img.toolbar-i { background-position: -16px 0 !important; }
.toolbar img.toolbar-u { background-position: -32px 0 !important; }
.toolbar img.toolbar-s { background-position: -48px 0 !important; }
.toolbar img.toolbar-url { background-position: -64px 0 !important; }
.toolbar img.toolbar-small { background-position: -80px 0 !important; }
.toolbar img.toolbar-quote { background-position: -96px 0 !important; }
.toolbar img.toolbar-code { background-position: -112px 0 !important; }
.toolbar img.toolbar-ul { background-position: -128px 0 !important; }
.toolbar img.toolbar-ol { background-position: -144px 0 !important; }
.toolbar img.toolbar-li { background-position: -160px 0 !important; }
.toolbar img.toolbar-img { background-position: -176px 0 !important; }
.toolbar img.toolbar-thumb { background-position: -192px 0 !important; }
.toolbar img.toolbar-title { background-position: -208px 0 !important; }
.toolbar img.toolbar-pad { background-position: -224px 0 !important; }
.toolbar img.toolbar-winners { background-position: -240px 0 !important; }
.toolbar img.toolbar-prizes { background-position: -256px 0 !important; }
.toolbar img.toolbar-entryform { background-position: -272px 0 !important; }
.toolbar img.toolbar-fromhtml { background-position: -288px 0 !important; }
.toolbar img.toolbar-minor-heading { background-position: -304px 0 !important; }
.toolbar img.toolbar-major-heading { background-position: -320px 0 !important; }
/***********/
/* CAPTCHA */

View file

@ -0,0 +1,25 @@
#editToolbar td {
padding-bottom: 5px;
}
.button {
vertical-align: middle;
font-family: Verdana, sans-serif;
padding: 1px 5px;
margin-right: 1px;
font-size: 12px;
width: auto !important;
}
#editBox, #qfBox {
margin: 0;
padding: 0;
width: 100%;
height: 500px;
font-size: 13px;
}
.menu-buttons a {
border-color: transparent;
_border-color: #000;
}

18
static/css/article.css Normal file
View file

@ -0,0 +1,18 @@
.article-header {
position: relative;
background: repeat-x;
margin-bottom: 10px;
}
.article-header, .article-header a {
height: 125px;
}
.article-header var, .article-header span, .article-header a {
background: no-repeat;
display: block;
}
.article-header var, .article-header span {
position: absolute;
}

View file

@ -143,6 +143,19 @@ a span.moneyitem, a span.moneysocketmeta, a span.moneysocketred, a span.moneysoc
.s3 { color: #ffb2eb !important } /* Whisper */
.s4 { color: #ff8040 !important } /* Emote */
/********************/
/* REPUTATION RANKS */
/********************/
.rep0, .rep-hated { color: #f00 !important }
.rep1, .rep-hostile { color: #f44 !important }
.rep2, .rep-unfirendly { color: #e62 !important }
.rep3, .rep-neutral { color: #ff0 !important }
.rep4, .rep-friendly { color: #0f0 !important }
.rep5, .rep-honored { color: #0f8 !important }
.rep6, .rep-revered { color: #0fc !important }
.rep7, .rep-exalted { color: #0ff !important }
/*****************/
/* SOCKETS ICONS */
/*****************/

View file

@ -0,0 +1,87 @@
.qq-uploader {
position:relative;
width:100%;
}
.qq-upload-button {
display:block;
width:105px;
padding:7px 0;
text-align:center;
background:#303030;
border:1px solid #404040;
color:#fff;
}
.qq-upload-button-hover {
background:#404040;
}
.qq-upload-button-focus {
outline:1px dotted black;
}
.qq-upload-drop-area {
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
min-height:70px;
z-index:2;
background:#FF9797;
text-align:center;
}
.qq-upload-drop-area span {
display:block;
position:absolute;
top:50%;
width:100%;
margin-top:-8px;
font-size:16px;
}
.qq-upload-drop-area-active {
background:#FF7171;
}
.qq-upload-list {
display:none;
margin:15px 35px;
padding:0;
list-style:disc;
}
.qq-upload-list li {
margin:0;
padding:0;
line-height:15px;
font-size:12px;
}
.qq-upload-file, .qq-upload-spinner, .qq-upload-size, .qq-upload-cancel, .qq-upload-failed-text {
margin-right:7px;
}
.qq-upload-spinner {
display:inline-block;
/* background:url("loading.gif"); */
background:url("../images/icons/ajax.gif");
width:15px;
height:15px;
vertical-align:text-bottom;
}
.qq-upload-size, .qq-upload-cancel {
font-size:11px;
}
.qq-upload-failed-text {
display:none;
}
.qq-upload-fail .qq-upload-failed-text {
display:inline;
}

View file

@ -300,6 +300,11 @@
text-decoration: underline;
}
.comment-reply-author-label {
color: #fff;
font-weight: bold;
}
.comment-blue b {
color: White !important;
}
@ -801,3 +806,91 @@ div.screenshotviewer-caption {
font-weight: bold;
padding: 5px 0 10px 0;
}
.enhanced-textarea-expander {
display:none;
}
.enhanced-textarea-wrapper {
position:relative;
}
.enhanced-textarea-wrapper textarea,
.enhanced-textarea-wrapper .enhanced-textarea-expander {
border:1px transparent solid;
box-sizing:border-box;
font:13px/1.4 "Open Sans",Arial,"Helvetica Neue",Helvetica,sans-serif;
overflow-wrap:break-word;
padding:5px 7px;
white-space:pre-wrap;
width:100% !important;
}
.enhanced-textarea-wrapper textarea,
.enhanced-textarea-wrapper textarea:hover {
transition:150ms;
}
.enhanced-textarea-wrapper.enhanced-textarea-dynamic-sizing textarea {
resize:none;
}
.enhanced-textarea-wrapper .enhanced-textarea-markup {
overflow:hidden;
}
.enhanced-textarea-wrapper .enhanced-textarea-markup-segment {
float:left;
}
.enhanced-textarea-wrapper .enhanced-textarea-markup-segment.menu-buttons {
padding:0;
}
.enhanced-textarea-text-input[type="text"] {
padding:5px 7px;
}
.enhanced-textarea-wrapper.enhanced-textarea-dark textarea,
.enhanced-textarea-text-input[type="text"],
.enhanced-textarea-text-input-dark[type="text"] {
min-height:calc(1.4em + 12px);
}
.enhanced-textarea-wrapper.enhanced-textarea-dark textarea,
.enhanced-textarea-wrapper.enhanced-textarea-dark textarea:hover,
.enhanced-textarea-text-input[type="text"],
.enhanced-textarea-text-input[type="text"]:hover,
.enhanced-textarea-text-input-dark[type="text"],
.enhanced-textarea-text-input-dark[type="text"]:hover {
background:#1c1c1c;
border-color:#3b3b3b;
color:#ddd;
outline:0;
}
.enhanced-textarea-wrapper.enhanced-textarea-focus-changes textarea,
.enhanced-textarea-text-input[type="text"] {
background:#1c1c1c;
border-color:#3b3b3b;
cursor:pointer;
min-height:calc(1.4em + 12px);
}
.enhanced-textarea-wrapper.enhanced-textarea-focus-changes textarea.focus-visible,
.enhanced-textarea-text-input[type="text"].focus-visible {
background:#181818;
border-color:#444;
box-shadow:0 0 0 1px #444;
cursor:auto;
}
.options-menu-widget {
cursor:default;
padding-right: 13px;
background: url(../images/Menu/arrow-down.gif) right center no-repeat;
}
.options-menu-widget.open {
color:#fff;
}

308
static/css/guide-edit.css Normal file
View file

@ -0,0 +1,308 @@
#guide-form .guide-form-main {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
}
#guide-form .guide-form-main th,
#guide-form .guide-form-main td {
padding: 0;
}
#guide-form .guide-form-main th {
line-height: 32px;
padding-right: 5px;
text-align: left;
vertical-align: top;
white-space: nowrap;
width: 1%;
}
#guide-form .guide-form-main td {
padding-bottom: 2px;
}
#guide-form .guide-form-main input[name="title"],
#guide-form .guide-form-main input[name="name"] {
width: calc(100% - 200px);
}
@media screen and (max-width: 799px) {
#guide-form .guide-form-main input[name="title"],
#guide-form .guide-form-main input[name="name"] {
width: 100%;
}
}
#guide-form .guide-form-main input[name="title"] {
max-width: 700px;
}
#guide-form .guide-form-main input[name="name"] {
max-width: 350px;
}
#guide-form .guide-form-main .char-warning {
display: inline-block;
margin-left: 5px;
}
#guide-form #class-guide-specialization-options,
#guide-form #class-guide-tag-options,
#guide-form #class-guide-intro,
#guide-form #class-guide-talents,
#guide-form #class-guide-pvp-talents,
#guide-form #class-guide-artifact-weapon,
#guide-form #class-guide-items,
#guide-form #class-guide-stats,
#guide-form #class-guide-gems,
#guide-form #class-guide-enchants,
#guide-form #class-guide-consumables {
display: none;
}
#guide-form[data-spec-category="true"] #class-guide-specialization-options,
#guide-form[data-spec-category="true"] #class-guide-tag-options {
display: table-row;
}
#guide-form[data-spec-category="true"] #class-guide-intro,
#guide-form[data-spec-category="true"] #class-guide-talents,
#guide-form[data-spec-category="true"] #class-guide-pvp-talents,
#guide-form[data-spec-category="true"] #class-guide-artifact-weapon,
#guide-form[data-spec-category="true"] #class-guide-items,
#guide-form[data-spec-category="true"] #class-guide-stats,
#guide-form[data-spec-category="true"] #class-guide-gems,
#guide-form[data-spec-category="true"] #class-guide-enchants,
#guide-form[data-spec-category="true"] #class-guide-consumables {
display: block;
}
#guide-tags .tags a span,
.guide-editing-closer {
background: #933
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' height='100%' width='100%'><line x1='30%' y1='30%' x2='70%' y2='70%' style='stroke:rgb(255, 255, 255);stroke-width:7.5%' /><line x1='70%' y1='30%' x2='30%' y2='70%' style='stroke:rgb(255, 255, 255);stroke-width:7.5%' /></svg>")
center no-repeat;
border-radius: 999px !important;
height: 39px;
line-height: 0;
position: absolute;
right: 7.02px;
top: 7.02px;
width: 39px;
z-index: 100;
}
#guide-tags .tags a {
background: #444 !important;
cursor: default;
height: 13px;
line-height: 13px;
margin-right: 16px;
position: relative;
}
#guide-tags .tags a span {
border: 2px solid #242424;
cursor: pointer;
height: 15px;
right: -14px;
top: 1px;
width: 15px;
}
#guide-tags > a {
margin-left: 10px;
}
.guide-edit-section {
margin: 15px 0 30px;
}
.guide-edit-section .guide-edit-box,
.guide-edit-section #editBox,
.guide-edit-section #qfBox,
.guide-edit-section #changelog {
margin: 0;
}
.class-guide-calc-wrapper[data-has-notes="true"] .class-guide-calc-notes-content .class-guide-calc-notes-note textarea,
.guide-edit-section#class-guide-items textarea {
background: #1c1c1c;
border-color: #3b3b3b;
box-sizing: border-box;
color: #fff;
overflow: hidden;
padding: 5px 7px;
resize: none;
}
.class-guide-calc-wrapper[data-has-notes="true"] .class-guide-calc-notes-content .class-guide-calc-notes-note textarea:focus,
.guide-edit-section#class-guide-items textarea:focus {
background: #181818;
border-color: #444;
}
.class-guide-calc-wrapper #viewintc-link {
display: none;
}
.class-guide-calc-wrapper > .guide-editing-closer {
display: none;
}
.class-guide-calc-wrapper[data-has-notes="true"] .class-guide-calc .guide-editing-closer {
display: none;
}
.class-guide-calc-wrapper[data-has-notes="true"] > .guide-editing-closer {
display: block;
}
.class-guide-calc-wrapper[data-has-notes="true"] .class-guide-calc-notes-content .class-guide-calc-notes-note .enhanced-textarea-markup {
display: inline;
overflow: hidden;
}
.class-guide-calc-wrapper[data-has-notes="true"] .class-guide-calc-notes-content .class-guide-calc-notes-note .enhanced-textarea-markup-wrapper {
min-height: 26px;
padding-bottom: 3px;
}
.class-guide-calc-wrapper[data-has-notes="true"] .class-guide-calc-notes-content .class-guide-calc-notes-note .enhanced-textarea-wrapper .enhanced-textarea-markup-segment {
display: inline-block;
float: none;
}
.class-guide-calc-wrapper .class-guide-calc .guide-editing-closer,
.class-guide-calc-wrapper .class-guide-calc-wrapper#guide-artifact-weapon-shell,
.class-guide-calc-wrapper#guide-artifact-weapon-shell .guide-editing-closer {
right: -19px;
top: -19px;
}
.talentcalc-controls-actions a.fa-link,
.pvptalentcalc-controls-actions a.fa-link,
.artifactcalc-controls a.fa-link {
display: none;
}
.guide-edit-section#class-guide-items textarea {
width: 100%;
}
.class-guide-stats-wrapper,
.class-guide-gems-wrapper,
.class-guide-enchants-wrapper,
.class-guide-consumables-wrapper {
margin-top: 10px;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable {
position: relative;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat .fa,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem .fa,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant .fa,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable .fa {
display: none;
font-size: 14px;
font-weight: normal;
left: 0;
position: absolute;
top: 1.4em;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat .fa-arrow-right,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem .fa-arrow-right,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant .fa-arrow-right,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable .fa-arrow-right {
left: 20px;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat .fa-balance-scale,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem .fa-balance-scale,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant .fa-balance-scale,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable .fa-balance-scale {
color: #fff;
left: 40px;
}
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant .fa-balance-scale,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable .fa-balance-scale {
display: none !important;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat .fa-times,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem .fa-times {
left: 60px;
}
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant .fa-times,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable .fa-times {
left: 40px;
}
#class-guide-items > ul > li:first-child > div:first-child .fa-arrow-up,
#class-guide-items > ul > li:last-child > div:first-child .fa-arrow-down,
.class-guide-stats-stat-wrapper:first-child .fa-arrow-left,
.class-guide-stats-stat-wrapper:last-child .fa-arrow-right,
.class-guide-gems-gem-wrapper:first-child .fa-arrow-left,
.class-guide-gems-gem-wrapper:last-child .fa-arrow-right,
.class-guide-enchants-enchant-wrapper:first-child .fa-arrow-left,
.class-guide-enchants-enchant-wrapper:last-child .fa-arrow-right,
.class-guide-consumables-consumable-wrapper:first-child .fa-arrow-left,
.class-guide-consumables-consumable-wrapper:last-child .fa-arrow-right {
pointer-events: none;
visibility: hidden;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat:hover,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem:hover,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant:hover,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable:hover {
padding-bottom: 20px;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat:hover .fa,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem:hover .fa,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant:hover .fa,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable:hover .fa {
display: block;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat:hover .fa:before,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem:hover .fa:before,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant:hover .fa:before,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable:hover .fa:before {
border-radius: 99px;
padding: 5px 2px;
}
.class-guide-stats-wrapper .class-guide-stats-stat-wrapper .class-guide-stats-stat:hover a.fa:hover:before,
.class-guide-gems-wrapper .class-guide-gems-gem-wrapper .class-guide-gems-gem:hover a.fa:hover:before,
.class-guide-enchants-wrapper .class-guide-enchants-enchant-wrapper .class-guide-enchants-enchant:hover a.fa:hover:before,
.class-guide-consumables-wrapper .class-guide-consumables-consumable-wrapper .class-guide-consumables-consumable:hover a.fa:hover:before {
background: #101010;
}
.guide-editing-closer {
right: 0 !important;
}
.guide-submission-options button {
margin: 0 20px 5px 0;
}
.guide-submission-changelog {
display: none;
}
.guide-submission[data-type] .guide-submission-changelog {
background: #333;
border-radius: 6px;
display: block;
padding: 10px;
}
.guide-submission[data-type] .guide-submission-changelog [class^="heading-size-"] {
margin-top: 0;
}
.guide-submission[data-type] .guide-submission-changelog textarea {
margin-bottom: 0 !important;
}
.guide-submission[data-type="save"] .guide-submission-options button[data-type="save"],
.guide-submission[data-type="submit"] .guide-submission-options button[data-type="submit"] {
/* background: #333 !important; */
border-radius: 6px 6px 0 0;
box-shadow: 0 15px 0 #333;
cursor: default;
text-decoration: none;
text-shadow: none !important;
}
.guide-submission .guide-submission-changelog-save,
.guide-submission .guide-submission-changelog-submit {
display: none;
}
.guide-submission[data-type="save"] .guide-submission-changelog-save,
.guide-submission[data-type="submit"] .guide-submission-changelog-submit {
display: block;
}
@media screen and (max-width: 812px) {
#class-guide-artifact-weapon .guide-editing-closer {
top: -39px !important;
}
}
@media screen and (max-width: 699px) {
.artifactcalc-controls {
right: 40px !important;
}
}
@media screen and (max-width: 675px) {
#class-guide-talents .guide-editing-closer,
#class-guide-pvp-talents .guide-editing-closer {
top: -29px !important;
}
}
@media screen and (max-width: 612px) {
.artifactcalc-controls {
right: 50px !important;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Before After
Before After

View file

@ -0,0 +1,49 @@
$WH.AdjacentPreview = new (function () {
const idx = "edit.adjacentPreview";
this.init = function () {
let cb = $WH.qs(".adjacent-preview-controls");
if (!cb) {
console.error("Can't set up adjacent guide preview support without an option to toggle it.");
return;
}
cb.style.display = "block";
if (!$WH.g_isVisible(cb)) {
return;
}
let mode = $WH.localStorage.get(idx);
if (mode === null) {
mode = $WH.localStorage.get("guide.edit.adjacentPreview");
if (mode !== null) {
$WH.localStorage.set(idx, mode);
$WH.localStorage.remove("guide.edit.adjacentPreview");
}
}
let i = $WH.qs(".adjacent-preview-checkbox");
mode = JSON.parse(mode); // read from store as literal
if (mode) {
i.checked = "checked";
}
$WH.aE(i, "change", () => {
let a = !!i.checked;
$WH.localStorage.set(idx, a);
togglePreview(a);
});
togglePreview(mode);
};
let togglePreview = function (en) {
if (en) {
window.scrollTo(0, 0);
document.body.dataset.adjacentPreview = "enabled";
$WH.qs(".adjacent-preview").style.top = $WH.g_getHeaderHeight() + "px";
$WH.ge('layout').style.maxWidth = 'initial';
$WH.ge('layout-inner').style.padding = '0px';
}
else {
document.body.dataset.adjacentPreview = "disabled";
$WH.ge('layout').style.maxWidth = '';
$WH.ge('layout-inner').style.padding = '';
}
};
})();

103
static/js/admin-article.js Normal file
View file

@ -0,0 +1,103 @@
var updateSnippetAfter = 2000;
var ICON_OK = {
url: g_staticUrl + "/images/icons/tick.png",
title: "The snippet is up to date"
};
var ICON_UPDATING = {
url: g_staticUrl + "/images/icons/ajax.gif",
title: "The snippet is being updated"
};
var ICON_OUT_OF_DATE = {
url: g_staticUrl + "/images/icons/delete.gif",
title: "The snippet is out of date"
};
$(document).ready(function () {
updateDescription();
var a = null;
$("#description").keyup(function () {
setIcon(ICON_OUT_OF_DATE);
if (a) {
clearTimeout(a);
a = null
}
updateDescription()
});
$("#editBox").keyup(function () {
setIcon(ICON_OUT_OF_DATE);
if (a) {
clearTimeout(a)
}
a = setTimeout(function () {
updateDescription();
a = null
},
updateSnippetAfter)
})
});
function setIcon(a) {
var b = supportsPlaceholder() ? $("#placeholder-icon") : $("#no-placeholder-icon");
b.html("");
if (!a) {
return
}
b.html('<img src="' + a.url + '" title="' + a.title + '" />')
}
function setInfoText(b, a) {
$("#desc-info").css("color", a).text(b)
}
var infoTexts = [
[0, "You have not entered any text. The description will be automatically generated for you.", "#FF8000"],
[99, "Your description is too short! $1 to go...", "#FF0000"],
[129, "Your description looks okay, but it could be a bit longer. Try adding $1.", "#0070DD"],
[150, "Your description is optimal. Good job!", "#1EFF00"],
[155, "Argh, your description is getting too long! But it's still acceptable.", "#0070DD"],
[1000000, "Oh noez! Your description is $1 too long! Google will most likely truncate it for you :(", "#FF0000"],
];
function supportsPlaceholder() {
var a = document.createElement("input");
return "placeholder" in a
}
function updateDescription() {
var d = $("#description").val().length;
setIcon(null);
for (var a in infoTexts) {
a = parseInt(a);
var c = infoTexts[a];
if (d > c[0]) {
continue
}
var b = 0;
if (c[0] == 1000000) {
b = d - infoTexts[a - 1][0]
} else {
b = infoTexts[a][0] - d + 1
}
if (b == 1) {
b += " character"
} else {
b += " characters"
}
setInfoText($WH.sprintf(c[1], b), c[2]);
break
}
if (d) {
$("#snippet-row").hide();
return
}
updateSnippet()
}
function updateSnippet() {
setIcon(ICON_UPDATING);
$.post("/edit=article", {
"get-description": $("#editBox").val()
},
function (a) {
setIcon(ICON_OK);
if (supportsPlaceholder()) {
$("#description").attr("placeholder", a)
} else {
$("#snippet-row").show();
$("#snippet").val(a)
}
})
};

19
static/js/admin.js Normal file
View file

@ -0,0 +1,19 @@
function ar_IsValidUrl(a) {
return a.match(/^[a-z0-9=_&\.\/\-]{2,64}$/i) != null;
}
function ar_ValidateUrl(a) {
if (ar_IsValidUrl(a)) {
return null;
}
if (a.length < 2) {
return "URL must be at least 2 characters long.";
}
else if (a.length > 64) {
return "URL must be at most 64 characters long.";
}
else {
return "You used invalid characters in your URL.\n\nYou can only use the following:\n a to z\n 0 to 9\n = _ & . / -"
}
};

View file

@ -0,0 +1,84 @@
var updatePlaceholderAfter = 2000;
$(document).ready(function () {
updateDescription();
var a = null;
$("#description").keyup(function () {
if (a) {
clearTimeout(a);
a = null;
}
updateDescription();
});
$("#editBox").keyup(function () {
if (a)
clearTimeout(a);
a = setTimeout(function () {
updateDescription();
a = null;
}, updatePlaceholderAfter);
})
});
function setInfoText(text, color) {
$("#desc-info").css("color", color).text(text);
}
var infoTexts = [
[0, LANG.descriptionlengthzero_tip, "#FF8000"],
[99, LANG.descriptionlengthshort_tip, "#FF0000"],
[129, LANG.descriptionlengthslightlyshort_tip, "#0070DD"],
[150, LANG.descriptionlengthoptimal_tip, "#1EFF00"],
[155, LANG.descriptionlengthslightlylong_tip, "#0070DD"],
[1000000, LANG.descriptionlengthlong_tip, "#FF0000"]
];
function supportsPlaceholder() {
var el = document.createElement("input");
return "placeholder" in el;
}
function updateDescription() {
var len = $("#description").val().length;
for (var i in infoTexts) {
i = parseInt(i);
var text = infoTexts[i];
if (len > text[0])
continue;
var diff = 0;
if (text[0] == 1000000)
diff = len - infoTexts[i - 1][0];
else
diff = infoTexts[i][0] - len + 1;
if (diff == 1)
diff += " character";
else
diff += " characters";
setInfoText($WH.sprintf(text[1], diff), text[2]);
break;
}
if (!len)
setInfoText('', '');
updatePlaceholder();
}
function updatePlaceholder() {
$.post("?get-description", {
description: $("#editBox").val()
},
function (data) {
if (supportsPlaceholder())
$("#description").attr("placeholder", data);
else
$("#description").text(data);
})
};

View file

@ -0,0 +1,172 @@
$(document).ready(function () {
$("#icon").keyup(function () {
var iconStr = $(this).val();
$("#iconPreview").empty();
if (!iconStr)
return;
if (iconStr.indexOf("http") == 0)
$("#iconPreview").append($("<img/>", { src: iconStr }));
else
$("#iconPreview").append($("<img/>", { src: g_staticUrl + "/images/wow/icons/large/" + iconStr.toLowerCase() + ".jpg" }));
});
});
var previewWindow;
function initToolbox() {
if (window.getSelection || document.getSelection || (document.selection && document.selection.createRange))
$WH.ge("editToolbar").style.display = "";
}
function updatePreview(a) {
if (a || $WH.ge("previewupdate").checked) {
var editor = $WH.ge("editBox");
clearTimeout(editor.timer);
editor.timer = setTimeout(function () {
var buff = Markup.toHtml($WH.ge("editBox").value, { allow: "Markup.CLASS_STAFF", preview: true });
var qfEditor;
if ((qfEditor = $WH.ge("changelogBox")) && qfEditor.value != "")
buff += Markup.toHtml("[changelog open=true]" + qfEditor.value + "[/changelog]", { allow: "Markup.CLASS_STAFF", preview: true });
if (previewWindow) {
try {
previewWindow.updatePreview(buff);
}
catch(e) {
detach($WH.ge("detachLink"));
}
}
else
$WH.ge("livePreview").innerHTML = buff;
}, 250);
}
}
function updateQfPreview(a) {
if (a || $WH.ge("previewupdate").checked) {
var b = $WH.ge("qfBox");
clearTimeout(b.timer);
b.timer = setTimeout(function () {
var d = Markup.toHtml($WH.ge("qfBox").value.replace(/[\r\n]+/g, ""), { allow: Markup.CLASS_STAFF, root: "ul", preview: true });
if (previewWindow) {
try {
previewWindow.updateQfPreview(d);
}
catch(f) {
detach($WH.ge("detachLink"));
}
}
else {
var c = $WH.ge("liveQfPreview");
if (d)
c.innerHTML = d;
c.parentNode.parentNode.parentNode.parentNode.style.display = (d ? "" : "none");
}
}, 250);
}
}
function detach(c) {
if (previewWindow) {
try {
previewWindow.close();
}
catch(a) {}
previewWindow = 0;
updatePreview(1);
updateQfPreview(1);
c.innerHTML = "Detach";
}
else {
try {
previewWindow = window.open("", "", "toolbar=0,location=0,directories=0,status=0,menubar=0,scrollbars=1,resizable=1");
previewWindow.document.open();
var b = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml">\n';
b += "<head>\n<title>Live Preview - " + document.title + '</title>\n\n<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n\n';
b += '<link rel="stylesheet" type="text/css" href="<?php echo UrlHelper::GetStaticUrl(\'/css/global.css?255\'); ?>" />\n<link rel="stylesheet" type="text/css" href="<?php echo UrlHelper::GetStaticUrl(\'/css/locale_enus.css?255\'); ?>" /><!--[if IE]>\n<link rel="stylesheet" type="text/css" href="<?php echo UrlHelper::GetStaticUrl(\'/css/global_ie.css?255\'); ?>" /><![endif]--><!--[if lte IE 6]>\n<link rel="stylesheet" type="text/css" href="<?php echo UrlHelper::GetStaticUrl(\'/css/global_ie6.css?255\'); ?>" /><![endif]-->\n\n<script src="<?php echo UrlHelper::GetStaticUrl(\'/js/locale_enus.js?255\'); ?>" type="text/javascript"><\/script>\n<script src="<?php echo UrlHelper::GetStaticUrl(\'/js/global.js?255\'); ?>" type="text/javascript"><\/script>\n\n';
b += "<script>//<![CDATA[\n\nfunction updatePreview(text)\n{\n\tvar si = $WH.g_getScroll();\n\tge('livePreview').innerHTML = text;\n\tscrollTo(si.x, si.y);\n}\n\nfunction updateQfPreview(text)\n{\n\tvar si = $WH.g_getScroll();\n\tvar qf = $WH.ge('liveQfPreview');\n\tqf.innerHTML = text;\n\tqf.parentNode.parentNode.parentNode.parentNode.style.display = (text? '': 'none');\n\tscrollTo(si.x, si.y);\n}\n\n//]]><\/script>\n\n";
b += '</head>\n\n<body>\n\n<div id="main-contents" class="main-contents text">\n\n<table class="infobox">\n<tbody><tr><th>Quick Facts</th></tr>\n<tr><td><ul id="liveQfPreview"><li style="display: none"></li></ul></td></tr>\n</tbody></table>\n\n<div id="livePreview"></div>\n\n</div>\n\n</body>\n</html>';
previewWindow.document.write(b);
previewWindow.document.close();
$WH.ge("livePreview").innerHTML = "See popup window.";
$WH.ge("liveQfPreview").parentNode.parentNode.parentNode.parentNode.style.display = "none";
updatePreview(1);
updateQfPreview(1);
c.innerHTML = "Close popup";
}
catch(a) {
previewWindow = 0;
}
}
}
function insertMapLink() {
var mapStr = prompt("Please enter the ID of the zone.\n\nYou may also import a full map by pasting a ?maps=... link.", "");
if (mapStr != null) {
var f = mapStr.match(/maps=(\d+[a-z]?)(:(\d+))?/);
if (f != null && f[1] != null) {
var g = "[map zone=" + f[1] + "]\n";
if (f[3] != null) {
var e = 0;
for (var d = 0, b = f[3].length; d < b; d += 6) {
var a = (parseFloat(f[3].substring(d, d + 3)) | 0) / 10;
var h = (parseFloat(f[3].substring(d + 3, d + 6)) | 0) / 10;
if (e++ > 0) {
g += "\n";
}
g += "[pin x=" + a + " y=" + h + " url=?npc=]" + LANG.name + "[/pin]";
}
}
g += "\n[/map]";
g_insertTag("editBox", g, "");
}
else
g_insertTag("editBox", "[map zone=" + (parseInt(mapStr) | 0) + "]\n", "\n[/map]");
}
}
function validateForm(form, _) {
var inp = form.elements.url;
if (inp) {
var err = ar_ValidateUrl(inp.value);
if (err) {
alert(err);
return false;
}
}
return true;
}
function leavePage(a) {
if (window.onbeforeunload == null)
window.onbeforeunload = function (b) { return "Are you sure you want to leave this page?"; }
if (a)
window.onbeforeunload = null;
}
$(document).ready(function () {
$("#guide-form").submit(function () {
if (!$("#title").val()) {
alert("Please enter a title.");
$("#title").focus();
return false;
}
if (!$("#category").val()) {
alert("You must choose a category.");
$("#category").focus();
return false;
}
if (!$("#editBox").val()) {
alert("Your guide contains no text!");
$("#editBox").focus();
return false;
}
return true;
});
});

View file

@ -194,6 +194,12 @@ $WH.str_replace = function(z, a, b) {
return z;
}
$WH.htmlentities = function(a) {
return a.replace(/[\u00A0-\u9999<>\&]/gim, function(b) {
return "&#" + b.charCodeAt(0) + ";"
})
};
// Encode URL for internal use (e.g. Ajax)
$WH.urlencode = function(z) {
z = encodeURIComponent(z);
@ -373,6 +379,14 @@ $WH.gE = function(z, y) {
return z.getElementsByTagName(y);
}
$WH.qs = function (y, z) {
return (z || document).querySelector(y);
};
$WH.qsa = function (y, z) {
return (z || document).querySelectorAll(y);
};
// Create element
$WH.ce = function(z, p, c) {
var a = document.createElement(z);
@ -935,24 +949,26 @@ $WH.g_getIdFromTypeName = function (typeName) {
return (lookup[typeName] ? lookup[typeName] : -1)
};
$WH.g_getIdFromTypeName.L = {
npc: 1,
object: 2,
item: 3,
itemset: 4,
quest: 5,
spell: 6,
zone: 7,
faction: 8,
pet: 9,
achievement: 10,
title: 11,
event: 12,
"class": 13,
race: 14,
skill: 15,
currency: 17,
profile: 100
npc: 1,
object: 2,
item: 3,
itemset: 4,
quest: 5,
spell: 6,
zone: 7,
faction: 8,
pet: 9,
achievement: 10,
title: 11,
event: 12,
"class": 13,
race: 14,
skill: 15,
currency: 17,
profile: 100,
guide: 300
};
@ -2315,6 +2331,23 @@ $WH.g_createButton = function(text, href, opts)
return btn;
}
$WH.g_isVisible = function (el) {
return !(el.offsetWidth === 0 && el.offsetHeight === 0);
}
$WH.g_getHeaderHeight = function () {
let el = ['header', 'toptabs', 'topbar', 'main-precontents']
let h = 0;
for (i in el) {
let e = $WH.ge(el[i]);
if (e)
h += e.getBoundingClientRect().height;
}
return h;
};
/* Aowow: end replacement */
if ($WH.isset('$WowheadPower')) {

1441
static/js/fileuploader.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -527,7 +527,8 @@ var PageTemplate = new function()
menu.push(reputation);
// Guides
var guides = ['guides', 'My Guides', '?my-guides'];
// var guides = ['guides', 'My Guides', '?my-guides'];
var guides = ['guides', LANG.myguides, '?my-guides', null, {onBeforeShow: generateGuidesSubmenu} ];
menu.push(guides);
addCharactersMenu(menu);
@ -635,6 +636,30 @@ var PageTemplate = new function()
menuItem[MENU_IDX_SUB] = submenu;
}
// aowow- custom
function generateGuidesSubmenu(menuItem)
{
var submenu = [];
// Sort by name
g_user.profiles.sort(function(a, b)
{
return $WH.strcmp(a.title, b.title);
});
$.each(g_user.guides, function(idx, guide)
{
var menuItem = [guide.id, guide.title, guide.url, [[guide.id, LANG.button_edit, '/?guide=edit&id=' + guide.id]]];
submenu.push(menuItem);
});
if (g_user.id)
submenu.push([0, LANG.createnewguide, '?guide=new']);
menuItem[MENU_IDX_SUB] = submenu;
}
function initFeedbackLink()
{
$('#toplinks-feedback')
@ -878,11 +903,11 @@ var PageTemplate = new function()
Menu.addButtons($buttons, Menu.implode(mn_news));
break;
case 6: // Guides
var entries = [ [ 1, 'List of guides', '?guides' ], [ 2, 'Write new guide', '?guide=new' ] ];
case 6: // Guides // aowow - localization added
var entries = [ [ 1, LANG.listguides, '?guides', mn_guides ], [ 2, LANG.createnewguide, '?guide=new' ] ];
if(g_user.id)
entries.push([ 3, 'My guides', '?my-guides' ]);
entries.push([ 3, LANG.myguides, '?my-guides' ]);
Menu.addButtons($buttons, entries);
break;
@ -2198,6 +2223,16 @@ function co_addYourComment() {
function co_validateForm(f) {
var ta = $WH.gE(f, 'textarea')[0];
// prevent locale comments on guide pages
var locale = Locale.getId();
// aowow - disabled
// if(locale != LOCALE_ENUS && $(f).attr('action') && ($(f).attr('action').replace(/^.*type=([0-9]*).*$/i, '$1')) == 100)
if (false)
{
alert(LANG.message_cantpostlcomment_tip);
return false;
}
if (g_user.permissions & 1) {
return true;
}
@ -4361,7 +4396,7 @@ var Favorites = new function() {
$WH.Tooltip.hide();
}).bind(null, _type, _typeId, heading.textContent.trim().replace(/(.+)<.*/, '$1')));
_favIcon.mouseover(function(r) {
_favIcon.mouseover(function(event) {
var tt = this.className.match(/\bfav-star-0\b/) ? LANG.addtofavorites : LANG.removefromfavorites;
$WH.Tooltip.show(this, tt, false, false, 'q2');
});
@ -4371,7 +4406,7 @@ var Favorites = new function() {
_favIcon.addClass('fa-star-0').click(function() {
location.href = "?account=signin";
$WH.Tooltip.hide();
}).mouseover(function(r) {
}).mouseover(function(event) {
$WH.Tooltip.show(this, LANG.favorites_login + "<div class='q2' style='margin-top:10px'>" + LANG.clicktologin + '</span>');
});
}
@ -10148,6 +10183,251 @@ Listview.templates = {
}
},
guide: {
sort: ['rating'],
searchable: 1,
filterable: 1,
columns: [
{
id: 'title',
name: LANG.types[11][0],
type: 'text',
align: 'left',
value: 'title',
compute: function(guide, td)
{
var wrapper = $('<div>')
var title = $('<a>').text(guide.title).attr('href', guide.url + (typeof guide.rev != 'undefined' ? '&rev=' + guide.rev : ''));
if(guide.description)
title.mouseover(function(event) {$WH.Tooltip.showAtCursor(event, guide.description, 0, 0, 'q');}).mousemove(function(event) {$WH.Tooltip.cursorUpdate(event)}).mouseout(function() {$WH.Tooltip.hide()});
if(guide.sticky)
title.addClass('guide-sticky');
else if(guide.nvotes < 5)
title.addClass('guide-new');
$(wrapper).append(title);
$(td).append(wrapper);
if (typeof guide.rev != 'undefined') {
wrapper.css('position', 'relative');
let revText = $('<div>', {
class: 'small',
css: { 'font-style': 'italic', position: 'absolute', right: '3px', bottom: '0px' }
}).text('rev.: ' + guide.rev);
$(wrapper).append(revText);
}
return;
},
getVisibleText: function(guide)
{
return guide.title;
}
},
{
id: 'status',
name: LANG.status,
type: 'text',
hidden: 1,
compute: function(guide, td)
{
var text = $('<span>').text(l_guide_states[guide.status]).css('color', l_guide_states_color[guide.status]);
$(td).append(text);
},
getVisibleText: function(guide)
{
return l_guide_states[guide.status];
},
sortFunc: function(a, b)
{
if(a.status == b.status)
return 0;
return a.status < b.status ? -1 : 1;
}
},
{
id: 'category',
name: LANG.category,
type: 'text',
compute: function(guide, td)
{
$(td).append($('<a>').attr('href', '?guides=' + guide.category).text(l_guide_categories[guide.category]).css('color', 'white'));
},
getVisibleText: function(guide)
{
return l_guide_categories[guide.category];
},
sortFunc: function(a, b)
{
if(a.category == b.category)
return 0;
return a.category < b.category ? -1 : 1;
}
},
{
id: 'author',
name: LANG.author,
type: 'text',
compute: function(guide, td)
{
var userLink = $('<a>').attr('href', '?user=' + guide.author).text(guide.author);
var color = g_GetStaffColorFromRoles(guide.authorroles);
if(color != '')
userLink.addClass(color);
else
userLink.css('color', 'white');
$(td).append(userLink);
},
getVisibleText: function(guide)
{
return guide.author;
},
sortFunc: function(a, b)
{
return $WH.strcmp(a.author, b.author);
}
},
{
id: 'rating',
name: LANG.rating,
type: 'range',
width: '200px',
compute: function(guide, td)
{
$(td).append(GetStars(guide.rating));
var voteText = $("<span>").css('font-size', '85%');
// aowow - localized
if(guide.rating < 0)
voteText.text($WH.sprintf((5 - guide.nvotes) == 1 ? LANG.needsvote_format : LANG.needsvotes_format, 5 - guide.nvotes));
// voteText.text($WH.sprintf(' (needs $1 more $2)', 5 - guide.nvotes, (5 - guide.nvotes) == 1 ? 'vote' : 'votes'));
else
voteText.text($WH.sprintf(guide.nvotes == 1 ? LANG.outofvote_format : LANG.outofvotes_format, GetN5(guide.nvotes)));
// voteText.text(' (out of ' + GetN5(guide.nvotes) + ' ' + (guide.nvotes == 1 ? 'vote' : 'votes') + ')');
$(td).append(voteText);
},
getMinValue: function(item)
{
return guide.rating;
},
getMaxValue: function(item)
{
return guide.rating;
},
sortFunc: function(a, b, col)
{
if(a.sticky && !b.sticky)
return -1;
else if(!a.sticky && b.sticky)
return 1;
var isANew = a.rating == -1 && a.author != 'Wowhead';
var isBNew = b.rating == -1 && b.author != 'Wowhead';
if(isANew && !isBNew)
return -1;
else if(isBNew && !isANew)
return 1;
if(a.rating == b.rating)
return 0;
return a.rating < b.rating ? 1 : -1;
}
},
{
id: 'views',
name: LANG.views,
type: 'text',
width: '120px',
compute: function(guide, td)
{
var span = $('<span>');
span.text(GetN5(guide.views));
if(guide.views >= 50000)
{
span.css('color', '#FF4040');
span.css('font-weight', 'bold');
}
else if(guide.views >= 25000)
{
span.css('color', '#FF8000');
span.css('font-weight', 'bold');
}
else if(guide.views >= 10000)
span.css('color', '#A335EE');
else if(guide.views >= 5000)
span.css('color', '#0070DD');
else if(guide.views >= 1000)
span.css('color', '#1EFF00');
$(td).append(span);
},
getVisibleText: function(guide)
{
return guide.author;
},
sortFunc: function(a, b)
{
if(a.views == b.views)
return 0;
return a.views < b.views ? -1 : 1;
}
},
{
id: 'comments',
name: LANG.comments,
type: 'text',
width: '120px',
compute: function(guide)
{
return GetN5(guide.comments);
},
sortFunc: function(a, b)
{
if(a.comments == b.comments)
return 0;
return a.comments < b.comments ? -1 : 1;
}
},
{
id: 'patch',
name: LANG.patch,
type: 'text',
width: '120px',
compute: function(guide, td)
{
var span = $("<span>").text($WH.sprintf('$1.$2.$3', Math.floor(guide.patch / 100 / 100), Math.floor(guide.patch / 100) % 100, guide.patch % 100));
var matches = g_getPatchVersion.V[g_getPatchVersion.V.length - 2].match(/([0-9]+)\.([0-9]+)\.([0-9]+)/);
var currentPatch = matches[1] * 100 * 100 + matches[2] * 100;
if(parseInt(guide.patch / 100) * 100 >= currentPatch)
span.addClass('q2');
$(td).append(span);
return;
},
sortFunc: function(a, b)
{
if(a.patch == b.patch)
return 0;
return a.patch < b.patch ? -1 : 1;
}
}
],
getItemLink: function(guide) {return guide.url + (typeof guide.rev != 'undefined' ? '&rev=' + guide.rev : '')}
},
item: {
sort: [-2],
searchable: 1,
@ -13721,6 +14001,7 @@ Listview.templates = {
for(var i = 0; i < comment.replies.length; ++i)
{
var reply = comment.replies[i];
let owner = g_pageInfo.author === reply.username;
var row = $('<tr class="comment-reply-row"><td class="reply-controls"><p class="reply-upvote">upvote</p><p class="reply-rating"></p><p class="reply-downvote">downvote</p></td><td class="reply-text"></td></tr>');
var replyBy = $('<p class="comment-reply-author"></p>');
var replyByUserLink = $('<a></a>');
@ -13744,6 +14025,13 @@ Listview.templates = {
replyByUserLink.attr('href', '?user=' + reply.username);
replyByUserLink.text(reply.username);
replyBy.append(replyByUserLink);
if (owner)
{
$WH.ae(replyBy[0], $WH.ct(' '));
$WH.ae(replyBy[0], $WH.ce('span', { className: 'comment-reply-author-label' }, $WH.ct('<' + LANG.guideAuthor + '>')));
}
replyBy.append(' ').append(replyWhen).append(' ').append($WH.sprintf(LANG.lvcomment_patch, g_getPatchVersion(creationDate)));
@ -13833,6 +14121,7 @@ Listview.templates = {
updateCommentAuthor: function(comment, container)
{
var user = g_users[comment.user];
let owner = g_pageInfo.author === comment.user;
var postedOn = new Date(comment.date);
var elapsed = (g_serverTime - postedOn) / 1000;
@ -13840,6 +14129,11 @@ Listview.templates = {
container.append(LANG.lvcomment_by);
container.append($WH.sprintf('<a href="?user=$1">$2</a>', comment.user, comment.user));
if (owner)
{
$WH.ae(container[0], $WH.ct(' '));
$WH.ae(container[0], $WH.ce('span', { className: 'comment-reply-author-label' }, $WH.ct('<' + LANG.guideAuthor + '>')));
}
container.append(g_getReputationPlusAchievementText(user.gold, user.silver, user.copper, user.reputation));
container.append($WH.sprintf(' <a class="q0" id="comments:id=$1" href="#comments:id=$2">$3</a>', comment.id, comment.id, g_formatDate(null, elapsed, postedOn)));
container.append(' ');
@ -16630,6 +16924,54 @@ Listview.templates = {
getItemLink: function(race) {
return '?race=' + race.id;
}
},
changelog: {
nItemsPerPage: 100,
sortable: false,
columns: [
{
id: "name",
name: "Name",
compute: function (changelog, td) {
var c = $(changelog.tooltip).find("b").first().text();
$(td).html(c);
td.className += " listview-cleartext";
},
},
{
id: "version",
name: "Version (mouseover to see tooltip)",
compute: function (changelog, td) {
var tt = changelog.tooltip;
$(td).mouseover(function (event, menu) { $WH.Tooltip.showAtCursor(menu, event, 0, 0); }.bind(td, tt));
$(td).mousemove(function (event) { $WH.Tooltip.cursorUpdate(event); })
.mouseout(function () { $WH.Tooltip.hide(); });
/* aowow - we dont do patches
var g = typeof g_hearthhead != "undefined" && g_hearthhead ? "hearthstone" : "wow";
if (!g_getPatchVersionObject.hasOwnProperty("parsed") || !g_getPatchVersionObject.parsed[g]) {
g_getPatchVersionObject();
}
var j = (changelog.build > 0 ? "" : "Before ") + "Build " + Math.abs(changelog.build);
if (changelog.version > 0) {
var f = parseInt(changelog.version / 10000) + "." + (parseInt(changelog.version / 100) % 100) + "." + (changelog.version % 100);
j = f + " " + j;
var c = false;
for (var b in g_gameversions[g]) {
if (g_gameversions[g][b].versionnum >= changelog.version && (!c || c.build > g_gameversions[g][b].build)) {
c = g_gameversions[g][b];
}
}
if (c) {
j = j.replace(f, f + " (" + new Date(c.timestamp).toDateString() + ")");
}
}
*/
let j = changelog.version; // aowow - tmp
$(td).html(j);
},
},
],
}
};
@ -16936,6 +17278,12 @@ var Menu = new function()
menu.splice(pos, 1);
};
self.setSubmenu = function (menuItem, submenu)
{
menuItem[MENU_IDX_SUB] = submenu;
};
/***********/
/* PRIVATE */
/***********/
@ -17779,6 +18127,93 @@ ProgressBar.prototype.getContainer = function()
return this.elements.container;
};
/* This function is to get the stars for the vote control for the guides. */
function GetStars(stars, ratable, userRating, guideId)
{
var STARS_MAX = 5;
var averageRating = stars;
if(userRating)
stars = userRating;
stars = Math.round(stars*2)/2;
var starsRounded = Math.round(stars);
var ret = $("<span>").addClass('stars').addClass('max-' + STARS_MAX).addClass('stars-' + starsRounded);
if(!g_user.id)
ratable = false;
if(ratable)
ret.addClass('ratable');
if(userRating)
ret.addClass('rated');
/* This is kinda lame but oh well */
var contents = '<span>';
// var wbr = $.browser.msie ? '' : '&#8203;'; // aowow - jQuery v1.9 deprecated
var wbr = $WH.Browser.ie ? '' : '&#8203;';
var tmp = stars;
for(var i = 1; i <= STARS_MAX; ++i)
{
if(tmp < 1 && tmp > 0)
contents += '<b class="half">';
else
contents += '<b>';
--tmp;
contents += '<i class="clickable">' + wbr + '<i></i></i>';
}
for(var i = 1; i <= STARS_MAX; ++i)
contents += '</b>';
contents += '</span>';
ret.append(contents);
if(ratable)
{
var starNumber = 0;
ret.find('i.clickable').each(function() { var starId = ++starNumber; $(this).click(function() { VoteGuide(guideId, averageRating, starId); }); })
}
if(userRating)
{
var clear = $("<span>").addClass('clear').click(function() { VoteGuide(guideId, averageRating, 0); });
ret.append(clear);
}
if(stars >= 0)
ret.mouseover(function(event) {$WH.Tooltip.showAtCursor(event, 'Rating:&nbsp;' + stars + '&nbsp;/&nbsp;' + STARS_MAX, 0, 0, 'q');}).mousemove(function(event) {$WH.Tooltip.cursorUpdate(event)}).mouseout(function() {$WH.Tooltip.hide()});
return ret;
}
function VoteGuide(guideId, oldRating, newRating)
{
// Update stars display
$('#guiderating').html(GetStars(oldRating, true, newRating, guideId));
// Vote
$.ajax({cache: false, url: '?guide=vote', type: 'POST',
error: function() {
$('#guiderating').html(GetStars(oldRating, true, 0, guideId));
alert('Voting failed. Try again later.');
},
success: function(json) {
var data = eval('(' + json + ')');
$('#guiderating-value').text(data.rating);
$('#guiderating-votes').text(GetN5(data.nvotes));
},
data: { id: guideId, rating: newRating }
});
}
var Icon = {
sizes: ['small', 'medium', 'large'],
sizes2: [18, 36, 56],
@ -22109,6 +22544,37 @@ $WH.aE(window, 'load', function () {
}
});
$(document).ready((function () {
$('input').each((function () {
var maxLen = $(this).attr('maxlength');
var elemId = $(this).attr('data-charwarning');
var container = elemId ? $('#' + elemId) : null;
if (!maxLen || !container)
return;
var _hide = function () { container.hide() };
var _show = function (len) {
var chars = maxLen - len;
var usePct = len / maxLen;
var r = parseInt(usePct >= 0.5 ? 255 : usePct * 2 * 255).toString(16);
var g = parseInt(usePct < 0.5 ? 255 : 255 - (usePct - 0.5) * 2 * 255).toString(16);
if (r.length == 1)
r = '0' + r;
if (g.length == 1)
g = '0' + g;
container.text($WH.sprintf(LANG.compose_remaining, chars));
container.show();
container.css('color', '#' + r + g + '00')
};
$(this).focus((function () { _show($(this).val().length)}))
.blur((function () { _hide() }))
.keyup((function () { _show($(this).val().length) }))
}))
}));
function GetN5(num)
{
@ -22394,6 +22860,275 @@ function g_modifyUrl(url, params, opt) {
return url + hash;
}
function g_enhanceTextarea (ta, opt) {
if (!(ta instanceof jQuery)) {
ta = $(ta);
}
if (ta.data("wh-enhanced") || ta.prop("tagName") != "TEXTAREA") {
return;
}
if (typeof opt != "object") {
opt = {};
}
var canResize = (function(el) {
if (!el.dynamicResizeOption)
return true;
if ($WH.localStorage.get("dynamic-textarea-resizing") === "true")
return true;
if ($WH.localStorage.get("dynamic-textarea-resizing") === "false")
return false;
return !el.hasOwnProperty("dynamicSizing") || el.dynamicSizing;
}).bind(null, opt);
var height = ta.height() || 500;
var wrapper = $("<div/>", { "class": "enhanced-textarea-wrapper" }).insertBefore(ta).append(ta);
if (!opt.hasOwnProperty("color"))
wrapper.addClass("enhanced-textarea-dark")
else if (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())
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")
};
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")
};
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.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);
if (opt.markup == "inline")
ar_AddInlineToolbar(ta.get(0), z.get(0), k.get(0));
else
ar_AddToolbar(ta.get(0), z.get(0), k.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);
}
else {
D.removeClass("enhanced-textarea-dynamic-sizing");
H.css("height", F + "px");
}
}).bind(A, opt, wrapper, ta, canResize, height, n));
$("<span/>", { text: LANG.autoresizetextbox }).appendTo(C);
}
if (opt.scrollingMarkup) {
if (g_enhanceTextarea.scrollerCount)
g_enhanceTextarea.scrollerCount++;
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 color = el.css("backgroundColor");
if (color == "rgba(0, 0, 0, 0)" || color == "transparent")
return setBGColor(el.parent());
else
return color;
};
var r = setBGColor(y);
for (var m, l = 0;
(m = window.document.styleSheets[l]) && m.href; l++) {}
if (!m) {
window.document.head.appendChild(document.createElement("style"));
m = window.document.styleSheets[l];
}
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)
$("body").addClass(cssClass);
else
$("body").removeClass(cssClass);
};
$(window).scroll(s.bind(window, w, wrapper, o, 0));
s.call(window, w, wrapper, o, 0);
var setSize = (function(D, E) {
E.css("width", D.width() + "px");
D.css("height", E.height() + "px");
}).bind(null, w, y);
setSize();
$(window).on("resize", setSize);
$(function() { setTimeout(setSize, 2000) })
}
}
ta.data("wh-enhanced", true);
};
$WH.createOptionsMenuWidget = function (id, txt, opt) {
var chevron = $WH.createOptionsMenuWidget.chevron;
if (opt.noChevron)
chevron = '';
var container = $WH.ce('span');
container.id = 'options-menu-widget-' + id;
container.className = 'options-menu-widget ' + container.id;
container.innerHTML = txt + chevron;
if (opt.id)
container.id = opt.id;
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) {
case 'string':
$.data(container, 'options-menu-widget-class', d[MENU_IDX_SUB].className);
container.className += ' ' + d[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
}
}
}
if (d[MENU_IDX_URL]) {
menu.push(function (chevron, container, i, opt) {
switch (typeof i[MENU_IDX_URL]) {
case 'string':
window.location = i[MENU_IDX_URL];
break;
case 'function':
if (typeof opt.updateWidgetText == 'undefined' || opt.updateWidgetText) {
container.innerHTML = i[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) {
case 'string':
$.data(container, 'options-menu-widget-class', i[MENU_IDX_SUB].className);
container.className += ' ' + i[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);
break;
}
}
}
i[MENU_IDX_URL](container, i);
break;
}
}.bind(null, chevron, Menu.add, d, opt))
}
else if (!d[MENU_IDX_SUB] || !d[MENU_IDX_SUB].menu)
menu[0] = null;
menu[MENU_IDX_OPT] = {};
if (d[MENU_IDX_SUB]) {
switch (typeof d[MENU_IDX_SUB].className) {
case 'string':
menu[MENU_IDX_OPT].className = d[MENU_IDX_SUB].className;
break;
case 'function':
menu[MENU_IDX_OPT].className = d[MENU_IDX_SUB].className.bind(null, d, false);
break;
}
switch (typeof d[MENU_IDX_SUB].column) {
case 'number':
case 'string':
menu[MENU_IDX_OPT].column = d[MENU_IDX_SUB].column;
break;
case 'function':
menu[MENU_IDX_OPT].column = d[MENU_IDX_SUB].column.bind(null, d);
break;
}
switch (typeof d[MENU_IDX_SUB].tinyIcon) {
case 'string':
menu[MENU_IDX_OPT].tinyIcon = d[MENU_IDX_SUB].tinyIcon;
break;
case 'function':
menu[MENU_IDX_OPT].tinyIcon = d[MENU_IDX_SUB].tinyIcon.bind(null, d);
break;
}
switch (typeof d[MENU_IDX_SUB].fontIcon) {
case 'string':
menu[MENU_IDX_OPT].fontIcon = d[MENU_IDX_SUB].fontIcon;
break;
case 'function':
menu[MENU_IDX_OPT].fontIcon = d[MENU_IDX_SUB].fontIcon.bind(null, d);
break;
}
if (typeof d[MENU_IDX_SUB].isChecked == 'function')
menu[MENU_IDX_OPT].checkedFunc = d[MENU_IDX_SUB].isChecked.bind(null, d);
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. !
}
c.push(menu);
}
container.menu = c;
if (opt.menuOnClick) {
container.onmousedown = $WH.rf;
Menu.add(container, c, { showAtElement: true });
}
else
Menu.add(container, c);
}
if (opt.target)
$(opt.target).append(container);
else
return container;
};
$WH.createOptionsMenuWidget.chevron = ' <i class="fa fa-chevron-down fa-color-gray">~</i>';
/*
Global WoW data
@ -22413,16 +23148,31 @@ var g_file_races = {
};
var g_file_classes = {
1: 'warrior',
2: 'paladin',
3: 'hunter',
4: 'rogue',
5: 'priest',
6: 'deathknight',
7: 'shaman',
8: 'mage',
9: 'warlock',
11: 'druid'
1: 'warrior',
2: 'paladin',
3: 'hunter',
4: 'rogue',
5: 'priest',
6: 'deathknight',
7: 'shaman',
8: 'mage',
9: 'warlock',
11: 'druid'
};
var g_file_specs = {
"-1": 'inv_misc_questionmark',
0: 'spell_nature_elementalabsorption',
6: ['spell_deathknight_bloodpresence', 'spell_deathknight_frostpresence', 'spell_deathknight_unholypresence' ],
11: ['spell_nature_starfall', 'ability_racial_bearform', 'spell_nature_healingtouch' ],
3: ['ability_hunter_beasttaming', 'ability_marksmanship', 'ability_hunter_swiftstrike' ],
8: ['spell_holy_magicalsentry', 'spell_fire_firebolt02', 'spell_frost_frostbolt02' ],
2: ['spell_holy_holybolt', 'spell_holy_devotionaura', 'spell_holy_auraoflight' ],
5: ['spell_holy_wordfortitude', 'spell_holy_holybolt', 'spell_shadow_shadowwordpain' ],
4: ['ability_rogue_eviscerate', 'ability_backstab', 'ability_stealth' ],
7: ['spell_nature_lightning', 'spell_nature_lightningshield', 'spell_nature_magicimmunity' ],
9: ['spell_shadow_deathcoil', 'spell_shadow_metamorphosis', 'spell_shadow_rainoffire' ],
1: ['ability_rogue_eviscerate', 'ability_warrior_innerrage', 'ability_warrior_defensivestance' ]
};
var g_file_genders = {

View file

@ -0,0 +1,34 @@
$(document).ready(function () {
var uploadBar = {};
var a = new qq.FileUploader({
element: $("#image-upload")[0],
action: "?edit=image",
params: { guide: 1 },
template: '<div class="qq-uploader"><div class="qq-upload-drop-area"><span>Drop files here to upload</span></div><div class="qq-upload-button">Upload an image</div><ul class="qq-upload-list"></ul></div>',
onSubmit: function (id, fileName) {
uploadBar[id] = new ProgressBar({text: "0%", hoverText: "0%"});
var c = $("#upload-progress");
// c.empty();
c.append(uploadBar[id].getContainer())
},
onProgress: function (id, fileName, loaded, total) {
var pct = Math.round(loaded / total * 100);
if (uploadBar[id]) {
uploadBar[id].setText(pct + "%");
uploadBar[id].setHoverText(pct + "%");
uploadBar[id].setProgress(pct);
}
},
onComplete: function (id, fileName, rspJSON) {
uploadBar[id] = null;
if (!rspJSON.success) {
$("#upload-result").append('<span id="'+id+'" class="q10">Upload failed (' + rspJSON.error + ")</span>")
}
else {
$("#upload-result").append($WH.sprintf('<span id="'+id+'" class="q2">Upload of <b>$1</b> complete: <input id="'+id+'" type="text" /></span>', rspJSON.name));
// $("#upload-result").find("input").val("[img src=http://wowimg.zamimg.com/uploads/guide/images/" + rspJSON.id + "." + (rspJSON.type == 3 ? "png" : "jpg") + "]").focus(function () {
$("#upload-result").find("input#"+id).val("[img src=" + g_staticUrl + "/uploads/guide/images/" + rspJSON.id + "." + (rspJSON.type == 3 ? "png" : "jpg") + "]").focus(function () { this.select() })
}
}
})
});

View file

@ -20,6 +20,37 @@ var l_reputation_names = [
"Suspendierung durch Moderator"
];
var l_guide_categories = [
'', // 0
"Klassen", // 1
"Berufe", // 2
"Weltereignisse", // 3
"Neue Spieler & Stufenfortschritt", // 4
"Schlachtzüge & Bosskämpfe", // 5
"Wirtschaft & Währung", // 6
"Erfolge", // 7
"Gegenstände, Haus- & Reittiere", // 8
"Anderes" // 9
];
var l_guide_states = [
'',
"Entwurf",
"Zulassung ausstehend",
"Zugelassen",
"Abgelehnt",
"Archiviert"
];
var l_guide_states_color = [
'',
'#71D5FF',
'#FFFF00',
'#1EFF00',
'#FF4040',
'#FFD100'
];
var mn_classes = [
[6,"Todesritter",,,{className:"c6",tinyIcon:"class_deathknight"}],
[11,"Druide",,,{className:"c11",tinyIcon:"class_druid"}],
@ -921,6 +952,30 @@ var mn_database = [
[102, 'Areatrigger', '?areatriggers', mn_areatrigger, {requiredAccess: 1726}], // aowow - custom
[103, 'Briefe', '?mails'] // aowow - custom
];
var mn_guides = [
[2, "Berufe", '?guides=2'],
[7, "Erfolge", '?guides=7'],
[8, "Gegenstände, Haus- & Reittiere", '?guides=8'],
[1, "Klassen", '?guides=1'],
[4, "Neue Spieler & Stufenfortschritt", '?guides=4'],
[5, "Schlachtzüge & Bosskämpfe", '?guides=5'],
[3, "Weltereignisse", '?guides=3', [
[, "Aowow Leitfäden"],
["lunar-festival","Mondfest","?guide=lunar-festival"],
["love-is-in-the-air","Liebe liegt in der Luft","?guide=love-is-in-the-air"],
["noblegarden","Nobelgartenfest","?guide=noblegarden"],
["childrens-week","Kinderwoche","?guide=childrens-week"],
["midsummer-fire-festival","Sonnenwendfest","?guide=midsummer-fire-festival"],
["brewfest","Braufest","?guide=brewfest"],
["hallows-end","Schlotternächte","?guide=hallows-end"],
["pilgrims-bounty","Pilgerfreudenfest","?guide=pilgrims-bounty"],
["winter-veil","Winterhauchfest","?guide=winter-veil"]
]],
[6, "Wirtschaft & Währung", '?guides=6'],
[9, "Anderes", '?guides=9']
];
var mn_tools = [
[0,"Talentrechner","?talent",mn_talentCalc],
[2,"Begleiterrechner","?petcalc",mn_petCalc],
@ -933,22 +988,10 @@ var mn_tools = [
]],
[1,"Karten","?maps"],
[,"Anderes"],
[6,"Leitfäden","",[
[,"Weltereignisse"],
["lunar-festival","Mondfest","?guide=lunar-festival"],
["love-is-in-the-air","Liebe liegt in der Luft","?guide=love-is-in-the-air"],
["noblegarden","Nobelgartenfest","?guide=noblegarden"],
["childrens-week","Kinderwoche","?guide=childrens-week"],
["midsummer-fire-festival","Sonnenwendfest","?guide=midsummer-fire-festival"],
["brewfest","Braufest","?guide=brewfest"],
["hallows-end","Schlotternächte","?guide=hallows-end"],
["pilgrims-bounty","Pilgerfreudenfest","?guide=pilgrims-bounty"],
["winter-veil","Winterhauchfest","?guide=winter-veil"]
]],
[8,"Hilfsmittel",,[
[,"Datenbank"],
[0,"Neueste Ergänzungen","?latest-additions"],
[1,"Neueste Artikel","?latest-articles"],
// [0,"Neueste Ergänzungen","?latest-additions"],
// [1,"Neueste Artikel","?latest-articles"],
[2,"Neueste Kommentare","?latest-comments"],
[3,"Neueste Screenshots","?latest-screenshots"],
[11,"Neueste Videos","?latest-videos"],
@ -1010,11 +1053,13 @@ var mn_more = [
[8,"Such-Plugins","?searchplugins"],
[10,"Tooltips","?tooltips"]
];
var mn_path = [
[0,"Datenbank",,mn_database],
[1,"Extras",,mn_tools],
[3,"Community","",mn_community],
[2,"Weiteres",,mn_more]
[0, "Datenbank", null, mn_database ],
[1, "Extras", null, mn_tools ],
[3, "Community", null, mn_community],
[6, "Leitfäden", '?guides', mn_guides ],
[2, "Weiteres", null, mn_more ]
];
var g_contact_reasons = {
@ -2856,6 +2901,7 @@ var LANG = {
message_cantdeletecomment: "Dieser Kommentar wurde aufgrund seiner negativen Wertung automatisch bereinigt und kann nicht gelöscht werden.",
message_cantdetachcomment: "Dieser Kommentar wurde bereits abgetrennt.",
message_codenotentered: "Ihr habt den Code nicht eingegeben.",
message_cantpostlcomment_tip: "Ihr könnt nicht auf diesen Leitfaden kommentieren, nur englische Kommentare sind erlaubt.",
message_commentdetached: "Dieser Kommentar ist ab sofort abgetrennt.",
message_commenttooshort: "Euer Kommentar muss mindestens 10 Zeichen umfassen. Bitte führt ihn noch weiter aus.",
message_descriptiontooshort: "Eure Beschreibung muss mindestens 10 Zeichen umfassen. Bitte erweitert sie noch ein wenig.",
@ -3360,6 +3406,7 @@ var LANG = {
17: ["Währung", "Währung", "Währungen", "Währungen"],
19: ["Klang", "Klang", "Klänge", "Klänge"],
29: ["Icon", "Icon", "Icons", "Icons"],
300: ["Leitfaden", "Leitfaden", "Leitfäden", "Leitfäden"],
501: ["Emote", "Emote", "Emotes", "Emotes"],
502: ["Verzauberung", "Verzauberung", "Verzauberungen", "Verzauberungen"],
503: ["Areatrigger", "Areatrigger", "Areatrigger", "Areatrigger"],
@ -4751,6 +4798,7 @@ var LANG = {
build: "Version",
calculators: "Rechner",
patch: "Patch",
status: "Status",
sound_activities: {
greeting: "Begrüßung",
@ -4801,6 +4849,25 @@ var LANG = {
},
/* AoWoW: start custom */
// Guide
myguides: 'Meine Leitfäden',
listguides: 'Leitfäden auflisten',
createnewguide: 'Leitfaden erstellen',
needsvotes_format: '(benötigt $1 weitere Stimmen)',
needsvote_format: '(benötigt $1 weitere Stimme)',
outofvotes_format: '(aus $1 Stimmen)',
outofvote_format: '(aus $1 Stimme)',
guideAuthor: 'Leitfadenautor',
autoresizetextbox: 'Textfeld automatisch anpassen',
descriptionlengthlong_tip: 'Oh nein! Deine Beschreibung ist zu lang bei $1. Es wird wahrscheinlich gekürzt werden.',
descriptionlengthoptimal_tip: 'Ihre Beschreibung hat eine gute Länge. Gut gemacht! Sie können sicher bis zu $1 hinzufügen, wenn nötig.',
descriptionlengthshort_tip: 'Ihre Beschreibung ist zu kurz! $1 fehlen noch ...',
descriptionlengthslightlylong_tip: 'Deine Beschreibung ist ein bißchen lang! Aber es ist immer noch akzeptabel.',
descriptionlengthslightlyshort_tip: 'Ihre Beschreibung sieht okay aus, aber es könnte ein bisschen länger sein. Wenn es hilft die Seite zu beschreiben, versuche $1 hinzuzufügen.',
descriptionlengthzero_tip: 'Du hast keinen Text eingegeben. Die Beschreibung wird für dich automatisch generiert werden.',
// Conditions
note_condition: "Jede einzelne, der hier aufgeführte Bedingungen, muss erfüllt sein um die Gesamtbedingung zu erfüllen.",
note_condition_group: "Eine beliebige, der hier aufgeführte Gruppen, muss vollständig erfüllt sein um die Gesamtbedingung zu erfüllen.",

View file

@ -20,6 +20,37 @@ var l_reputation_names = [
"Moderator Suspension"
];
var l_guide_categories = [
'', // 0
"Classes", // 1
"Professions", // 2
"World Events", // 3
"New Players & Leveling", // 4
"Raid & Boss Fights", // 5
"Economy & Money", // 6
"Achievements", // 7
"Vanity Items, Pets & Mounts", // 8
"Other" // 9
];
var l_guide_states = [
'',
"Draft",
"Waiting for Approval",
"Approved",
"Rejected",
"Archived"
];
var l_guide_states_color = [
'',
'#71D5FF',
'#FFFF00',
'#1EFF00',
'#FF4040',
'#FFD100'
];
var mn_classes = [
[6,"Death Knight",,,{className:"c6",tinyIcon:"class_deathknight"}],
[11,"Druid",,,{className:"c11",tinyIcon:"class_druid"}],
@ -967,6 +998,30 @@ var mn_database = [
[102, 'Areatrigger', '?areatriggers', mn_areatrigger, {requiredAccess: 1726}], // aowow - custom
[103, 'Mails', '?mails'] // aowow - custom
];
var mn_guides = [
[7, "Achievements", '?guides=7'],
[1, "Classes", '?guides=1'],
[6, "Economy & Money", '?guides=6'],
[4, "New Players & Leveling", '?guides=4'],
[2, "Professions", '?guides=2'],
[5, "Raid & Boss Fights", '?guides=5'],
[8, "Vanity Items, Pets & Mounts", '?guides=8'],
[3, "World Events", '?guides=3', [
[,"Aowow Guides"],
["lunar-festival","Lunar Festival","?guide=lunar-festival"],
["love-is-in-the-air","Love is in the Air","?guide=love-is-in-the-air"],
["noblegarden","Noblegarden","?guide=noblegarden"],
["childrens-week","Childrens Week","?guide=childrens-week"],
["midsummer-fire-festival","Midsummer Fire Festival","?guide=midsummer-fire-festival"],
["brewfest","Brewfest","?guide=brewfest"],
["hallows-end","Hallow's End","?guide=hallows-end"],
["pilgrims-bounty","Pilgrim's Bounty","?guide=pilgrims-bounty"],
["winter-veil","Feast of Winter Veil","?guide=winter-veil"]
]],
[9, "Other", '?guides=9']
];
var mn_tools = [
[0,"Talent Calculator","?talent",mn_talentCalc],
[2,"Hunter Pet Calculator","?petcalc",mn_petCalc],
@ -979,22 +1034,10 @@ var mn_tools = [
]],
[1,"Maps","?maps"],
[,"Other"],
[6,"Guides","",[
[,"World Events"],
["lunar-festival","Lunar Festival","?guide=lunar-festival"],
["love-is-in-the-air","Love is in the Air","?guide=love-is-in-the-air"],
["noblegarden","Noblegarden","?guide=noblegarden"],
["childrens-week","Childrens Week","?guide=childrens-week"],
["midsummer-fire-festival","Midsummer Fire Festival","?guide=midsummer-fire-festival"],
["brewfest","Brewfest","?guide=brewfest"],
["hallows-end","Hallow's End","?guide=hallows-end"],
["pilgrims-bounty","Pilgrim's Bounty","?guide=pilgrims-bounty"],
["winter-veil","Feast of Winter Veil","?guide=winter-veil"]
]],
[8,"Utilities",,[
[,"Database"],
[0,"Latest Additions","?latest-additions"],
[1,"Latest Articles","?latest-articles"],
// [0,"Latest Additions","?latest-additions"],
// [1,"Latest Articles","?latest-articles"],
[2,"Latest Comments","?latest-comments"],
[3,"Latest Screenshots","?latest-screenshots"],
[11,"Latest Videos","?latest-videos"],
@ -1056,11 +1099,14 @@ var mn_more = [
[8,"Search Plugins (FF, IE7, ...)","?searchplugins"],
[10,"Tooltips","?tooltips"]
];
var mn_path = [
[0,"Database",,mn_database],
[1,"Tools",,mn_tools],
[3,"Community","",mn_community],
[2,"More",,mn_more]
[0, "Database", null , mn_database ],
[1, "Tools", null , mn_tools ],
[3, "Community", null , mn_community],
[6, "Guides", '?guides', mn_guides ],
[2, "More", null , mn_more ]
/* Note: ID 4 is used by the Staff menu - Skip it. It's added by staff.js */
];
var g_contact_reasons = {
@ -2904,6 +2950,7 @@ var LANG = {
message_cantdeletecomment: "This comment has been automatically purged due to a negative rating. It cannot be deleted.",
message_cantdetachcomment: "This comment has already been detached.",
message_codenotentered: "You did not enter the code.",
message_cantpostlcomment_tip: "You cannot comment this guide, only English comments are allowed.",
message_commentdetached: "This comment is now detached.",
message_commenttooshort: "Your comment must be at least 10 characters long.\n\nPlease elaborate a little.",
message_descriptiontooshort: "Your description must be at least 10 characters long.\n\nPlease elaborate a little.",
@ -3408,6 +3455,7 @@ var LANG = {
17: ["Currency", "currency", "Currencies", "currencies"],
19: ["Sound", "sound", "Sounds", "sounds"],
29: ["Icon", "icon", "Icons", "icons"],
300: ["Guide", "guide", "Guides", "guides"],
501: ["Emote", "emote", "Emotes", "emotes"],
502: ["Enchantment", "enchantment", "Enchantments", "enchantments"],
503: ["Areatrigger", "areatrigger", "Areatriggers", "areatriggers"],
@ -4798,6 +4846,7 @@ var LANG = {
build: "Build",
calculators: "Calculators",
patch: "Patch",
status: "Status",
sound_activities: {
greeting: "Greeting",
@ -4848,27 +4897,46 @@ var LANG = {
},
/* AoWoW: start custom */
// Guide (wasn't localized at the time of capture)
myguides: 'My Guides',
listguides: 'List of guides',
createnewguide: 'Create New Guide',
needsvotes_format: '(needs $1 more votes)',
needsvote_format: '(needs $1 more vote)',
outofvotes_format: '(out of $1 votes)',
outofvote_format: '(out of $1 vote)',
guideAuthor: 'Guide Author',
autoresizetextbox: 'Auto-Resize Text Box',
descriptionlengthlong_tip: 'Oh no! Your description is $1 too long! It will most likely be truncated.',
descriptionlengthoptimal_tip: 'Your description is a good length. Good job! You can safely add up to $1 if needed.',
descriptionlengthshort_tip: 'Your description is too short! $1 to go...',
descriptionlengthslightlylong_tip: 'Your description is getting a bit too long! But it\'s still acceptable.',
descriptionlengthslightlyshort_tip: 'Your description looks okay, but it could be a bit longer. If it would help describe the page try adding $1.',
descriptionlengthzero_tip: 'You have not entered any text. The description will be automatically generated for you.',
// Conditions
note_condition: "Every one of these conditions must be met to satisfy the requirement.",
note_condition_group: "Any one of these groups must be met in full to satisfy the requirement.",
note_condition: 'Every one of these conditions must be met to satisfy the requirement.',
note_condition_group: 'Any one of these groups must be met in full to satisfy the requirement.',
// Aura Stack Rules
asr_behaviour: "Behaviour",
asr_coexist: "coexist",
asr_exclusive: "exclusive",
asr_same_owner: "(from same caster)",
asr_strongest_effect: "(strongest effect is applied)",
asr_behaviour: 'Behaviour',
asr_coexist: 'coexist',
asr_exclusive: 'exclusive',
asr_same_owner: '(from same caster)',
asr_strongest_effect: '(strongest effect is applied)',
// Linked Spells
ls_trigger: "Triggers",
ls_self: "This",
ls_effects: "Effects",
ls_onCast: "Spell is cast",
ls_onAuraRemove: "Aura is removed",
ls_onAuraApply: "Spells Aura is applied or removed",
ls_onSpellHit: "Spell hits the target(s)",
ls_onTrigger: "Spell is triggered",
ls_onImmune: "Immunity against Spell is applied or cleared",
ls_trigger: 'Triggers',
ls_self: 'This',
ls_effects: 'Effects',
ls_onCast: 'Spell is cast',
ls_onAuraRemove: 'Aura is removed',
ls_onAuraApply: 'Spells Aura is applied or removed',
ls_onSpellHit: 'Spell hits the target(s)',
ls_onTrigger: 'Spell is triggered',
ls_onImmune: 'Immunity against Spell is applied or cleared',
/* AoWoW: end custom */
};

View file

@ -20,6 +20,37 @@ var l_reputation_names = [
"Suspensión por moderador"
];
var l_guide_categories = [
'', // 0
"Clases", // 1
"Profesiones", // 2
"Eventos del mundo", // 3
"Nuevos Jugadores y Leveling", // 4
"Combates de Bandas y Jefes", // 5
"Economía y Dinero", // 6
"Logros", // 7
"Objetos de vanidad, Mascotas y Monturas", // 8
"Otros" // 9
];
var l_guide_states = [
'',
"Borrador",
"Esperando aprobación",
"Aprobado",
"Rechazado",
"Archivada"
];
var l_guide_states_color = [
'',
'#71D5FF',
'#FFFF00',
'#1EFF00',
'#FF4040',
'#FFD100'
];
var mn_classes = [
[6,"Caballero de la muerte",,,{className:"c6",tinyIcon:"class_deathknight"}],
[11,"Druida",,,{className:"c11",tinyIcon:"class_druid"}],
@ -921,6 +952,30 @@ var mn_database = [
[102, 'Areatrigger', '?areatriggers', mn_areatrigger, {requiredAccess: 1726}], // aowow - custom
[103, 'Mails', '?mails'] // aowow - custom
];
var mn_guides = [
[1, "Clases", '?guides=1'],
[5, "Combates de Bandas y Jefes", '?guides=5'],
[6, "Economía y Dinero", '?guides=6'],
[3, "Eventos del mundo", '?guides=3', [
[,"Aowow Guías"],
["lunar-festival","Festival Lunar","?guide=lunar-festival"],
["love-is-in-the-air","Amor en el aire","?guide=love-is-in-the-air"],
["noblegarden","Jardín Noble","?guide=noblegarden"],
["childrens-week","Los Niños","?guide=childrens-week"],
["midsummer-fire-festival","Festival de Fuego del Solsticio de Verano","?guide=midsummer-fire-festival"],
["brewfest","El festín del Festival de Invierno","?guide=brewfest"],
["hallows-end","Halloween","?guide=hallows-end"],
["pilgrims-bounty","Generosidad","?guide=pilgrims-bounty"],
["winter-veil","Festival de Invierno","?guide=winter-veil"]
]],
[7, "Logros", '?guides=7'],
[4, "Nuevos Jugadores y Leveling", '?guides=4'],
[8, "Objetos de vanidad, Mascotas y Monturas", '?guides=8'],
[2, "Profesiones", '?guides=2'],
[9, "Otros", '?guides=9']
];
var mn_tools = [
[0,"Calculadora de talentos","?talent",mn_talentCalc],
[2,"Calculadora de mascotas","?petcalc",mn_petCalc],
@ -933,22 +988,10 @@ var mn_tools = [
]],
[1,"Mapas","?maps"],
[,"Otros"],
[6,"Guías","",[
[,"Eventos del mundo"],
["lunar-festival","Festival Lunar","?guide=lunar-festival"],
["love-is-in-the-air","Amor en el aire","?guide=love-is-in-the-air"],
["noblegarden","Jardín Noble","?guide=noblegarden"],
["childrens-week","Los Niños","?guide=childrens-week"],
["midsummer-fire-festival","Festival de Fuego del Solsticio de Verano","?guide=midsummer-fire-festival"],
["brewfest","El festín del Festival de Invierno","?guide=brewfest"],
["hallows-end","Halloween","?guide=hallows-end"],
["pilgrims-bounty","Generosidad","?guide=pilgrims-bounty"],
["winter-veil","Festival de Invierno","?guide=winter-veil"],
]],
[8,"Utilidades",,[
[,"Base de datos"],
[0,"Últimas adiciones","?latest-additions"],
[1,"Últimos artículos","?latest-articles"],
// [0,"Últimas adiciones","?latest-additions"],
// [1,"Últimos artículos","?latest-articles"],
[2,"Últimos comentarios","?latest-comments"],
[3,"Últimas capturas de pantalla","?latest-screenshots"],
[11,"Últimos vídeos","?latest-videos"],
@ -1010,11 +1053,13 @@ var mn_more = [
[8,"Extensiones de búsqueda","?searchplugins"],
[10,"Tooltips","?tooltips"]
];
var mn_path = [
[0,"Base de datos",,mn_database],
[1,"Herramientas",,mn_tools],
[3,"Comunidad",,mn_community],
[2,"Más",,mn_more]
[0, "Base de datos", null, mn_database ],
[1, "Herramientas", null, mn_tools ],
[3, "Comunidad", null, mn_community],
[6, "Guías", '?guides', mn_guides ],
[2, "Más", null, mn_more ]
];
var g_contact_reasons = {
@ -2857,6 +2902,7 @@ var LANG = {
message_cantdeletecomment: "Este comentario fue automaticamente eliminado debido a que tiene una valoración negativa. No puede ser borrado.",
message_cantdetachcomment: "Este comentario ya fue separado.",
message_codenotentered: "No introdujo el código.",
message_cantpostlcomment_tip: "No puedes hacer comentarios en esta guía. Solo se permiten comentarios en inglés.",
message_commentdetached: "Este comentario ahora está separado.",
message_commenttooshort: "Tu mensaje no puede estar vacío.",
message_descriptiontooshort: "Tu decripción debe de tener por lo menos 10 caracteres.\n\nPor favor escriba uno más elaborado.",
@ -3361,6 +3407,7 @@ var LANG = {
17: ["Monedas", "monedas", "Monedas", "monedas"],
19: ["Sonido", "sonido", "Sonidos", "sonidos"],
29: ["Icono", "icono", "Iconos", "íconos"],
300: ["Guía", "guía", "Guías", "guías"],
501: ["Emoción", "emoción", "Emociones", "emociones"],
502: ["Encantamiento", "encantamiento", "Encantamientos", "encantamientos"],
503: ["Areatrigger", "areatrigger", "Areatriggers", "areatriggers"],
@ -4754,6 +4801,7 @@ var LANG = {
build: "Versión",
calculators: "Calculadoras",
patch: "Parche",
status: "Estado",
sound_activities: {
greeting: "Saludo",
@ -4804,6 +4852,25 @@ var LANG = {
},
/* AoWoW: start custom */
// Guide
myguides: 'Mis Guías',
listguides: '[List of guides]',
createnewguide: 'Crear Nueva Guía',
needsvotes_format: '(necesita $1 votaciones más)',
needsvote_format: '(necesita $1 votación más)',
outofvotes_format: '(de $1 votaciones)',
outofvote_format: '(de $1 votación)',
guideAuthor: '[Guide Author]',
autoresizetextbox: 'Redimensionar automáticamente el cuadro de texto',
descriptionlengthlong_tip: '¡Oh, no! Tu descripción es demasido larga por $1. Es muy posible que sea cortada',
descriptionlengthoptimal_tip: 'Tu descripción es de la longitud óptima. ¡Buen trabajo! Si es necesario, puedes agregar hasta $1.',
descriptionlengthshort_tip: '¡Tu descripción es demasiado corta! Te faltan $1...',
descriptionlengthslightlylong_tip: 'Tu descripción es un poco larga. Pero aun así es aceptable.',
descriptionlengthslightlyshort_tip: 'Tu descripción está bien, pero podría ser un poco mas larga. Prueba a añadir $1 para describir la página.',
descriptionlengthzero_tip: 'No has escrito ningún texto. La descripción será añadida automáticamente por ti.',
// Conditions
note_condition: "Cada una de estas condiciones se deben cumplir para satisfacer el requerimiento",
note_condition_group: "Cualquiera de estos grupos de cumplir en totalidad para satisfacer el requerimiento",

View file

@ -20,6 +20,37 @@ var l_reputation_names = [
"Suspension par un modérateur"
];
var l_guide_categories = [
'', // 0
"Classes", // 1
"Métiers", // 2
"Évènements mondiaux", // 3
"Nouveaux Joueurs & Montée en niveau", // 4
"Raids & Combats contre des boss", // 5
"Economie et Argent", // 6
"Hauts faits", // 7
"Objets tape-à-l'oeil, Compagnons et Montures", // 8
"Autre" // 9
];
var l_guide_states = [
'',
"Brouillon",
"Attente d'approbation",
"Approuvé",
"Rejeter",
"Archivé"
];
var l_guide_states_color = [
'',
'#71D5FF',
'#FFFF00',
'#1EFF00',
'#FF4040',
'#FFD100'
];
var mn_classes = [
[6,"Chevalier de la mort",,,{className:"c6",tinyIcon:"class_deathknight"}],
[11,"Druide",,,{className:"c11",tinyIcon:"class_druid"}],
@ -921,6 +952,30 @@ var mn_database = [
[102, 'Areatrigger', '?areatriggers', mn_areatrigger, {requiredAccess: 1726}], // aowow - custom
[103, 'Mails', '?mails'] // aowow - custom
];
var mn_guides = [
[1, "Classes", '?guides=1'],
[6, "Economie et Argent", '?guides=6'],
[3, "Évènements mondiaux", '?guides=3', [
[,"Aowow Guides"],
["lunar-festival","Fête lunaire","?guide=lunar-festival"],
["love-is-in-the-air","De l'amour dans l'air","?guide=love-is-in-the-air"],
["noblegarden","Jardin des nobles","?guide=noblegarden"],
["childrens-week","Semaine des enfants","?guide=childrens-week"],
["midsummer-fire-festival","Fête du Feu du solstice d'été","?guide=midsummer-fire-festival"],
["brewfest","Voile d'hiver","?guide=brewfest"],
["hallows-end","Sanssaint","?guide=hallows-end"],
["pilgrims-bounty","Bienfaits du pèlerin","?guide=pilgrims-bounty"],
["winter-veil","Voile d'hiver","?guide=winter-veil"]
]],
[7, "Hauts faits", '?guides=7'],
[4, "Nouveaux Joueurs & Montée en niveau", '?guides=4'],
[2, "Métiers", '?guides=2'],
[8, "Objets tape-à-l'oeil, Compagnons et Montures", '?guides=8'],
[5, "Raids & Combats contre des boss", '?guides=5'],
[9, "Autre", '?guides=9']
];
var mn_tools = [
[0,"Calculateur de talents","?talent",mn_talentCalc],
[2,"Calculateur de familiers","?petcalc",mn_petCalc],
@ -933,22 +988,10 @@ var mn_tools = [
]],
[1,"Cartes","?maps"],
[,"Autre"],
[6,"Guides","",[
[,"Évènements mondiaux"],
["lunar-festival","Fête lunaire","?guide=lunar-festival"],
["love-is-in-the-air","De l'amour dans l'air","?guide=love-is-in-the-air"],
["noblegarden","Jardin des nobles","?guide=noblegarden"],
["childrens-week","Semaine des enfants","?guide=childrens-week"],
["midsummer-fire-festival","Fête du Feu du solstice d'été","?guide=midsummer-fire-festival"],
["brewfest","Voile d'hiver","?guide=brewfest"],
["hallows-end","Sanssaint","?guide=hallows-end"],
["pilgrims-bounty","Bienfaits du pèlerin","?guide=pilgrims-bounty"],
["winter-veil","Voile d'hiver","?guide=winter-veil"]
]],
[8,"Utilitaires",,[
[,"Base de données"],
[0,"Derniers ajouts","?latest-additions"],
[1,"Derniers articles","?latest-articles"],
// [0,"Derniers ajouts","?latest-additions"],
// [1,"Derniers articles","?latest-articles"],
[2,"Derniers commentaires","?latest-comments"],
[3,"Dernières captures d'écran","?latest-screenshots"],
[11,"Derniers vidéos","?latest-videos"],
@ -1010,11 +1053,13 @@ var mn_more = [
[8,"Plug-ins de recherche","?searchplugins"],
[10,"Tooltips","?tooltips"]
];
var mn_path = [
[0,"Base de données",,mn_database],
[1,"Outils",,mn_tools],
[3,"Communauté",,mn_community],
[2,"Plus",,mn_more]
[0, "Base de données", null, mn_database ],
[1, "Outils", null, mn_tools ],
[3, "Communauté", null, mn_community],
[6, "Guides", '?guides', mn_guides ],
[2, "Plus", null, mn_more ]
];
var g_contact_reasons = {
@ -2857,6 +2902,7 @@ var LANG = {
message_cantdeletecomment: "Ce commentaire a été automatiquement effacé à cause d'une note négative. Il ne peut être supprimé.",
message_cantdetachcomment: "Ce commentaire a déjà été détaché.",
message_codenotentered: "Vous n'avez pas écrit le CAPTCHA.",
message_cantpostlcomment_tip: "Vous ne pouvez pas commenter ce guide, seuls les commentaires rédigés en anglais sont autorisés.",
message_commentdetached: "Ce commentaire a été détaché.",
message_commenttooshort: "Votre message ne doit pas être vide.",
message_descriptiontooshort: "Votre description doit faire au moins 10 caractères de long.\nVeuillez élaborer un peu.",
@ -3361,6 +3407,7 @@ var LANG = {
17: ["Monnaies", "monnaie", "Monnaies", "monnaies"],
19: ["Son", "Son", "Sons", "Sons"],
29: ["Icône", "icône", "Icônes", "icônes"],
300: ["Guide", "guide", "Guides", "guides"],
501: ["Emote", "emote", "Emotes", "emotes"],
502: ["Enchantement", "enchantement", "Enchantements", "enchantements"],
503: ["Areatrigger", "areatrigger", "Areatriggers", "areatriggers"],
@ -4753,6 +4800,7 @@ var LANG = {
build: "Version",
calculators: "Calculateurs",
patch: "Patch",
status: "Statut",
sound_activities: {
greeting: "Salutation",
@ -4803,6 +4851,25 @@ var LANG = {
},
/* AoWoW: start custom */
// Guide
myguides: 'Mes guides',
listguides: '[List of guides]',
createnewguide: 'Créer un nouveau Guide',
needsvotes_format: '(requiert $1 votes supplémentaires)',
needsvote_format: '(requiert $1 vote supplémentaire)',
outofvotes_format: '(sur $1 votes)',
outofvote_format: '(sur $1 vote)',
guideAuthor: 'Auteur du guide',
autoresizetextbox: 'Redimensionner automatiquement le champ texte',
descriptionlengthlong_tip: 'Fichtre ! Votre description $1 est trop longue ! Elle sera probablement tronquée.',
descriptionlengthoptimal_tip: 'Votre description est de longueur appropriée. Bien joué ! Vous pouvez sans problème ajouter jusqu\'à $1 si besoin.',
descriptionlengthshort_tip: 'Votre description est trop courte ! Encore $1...',
descriptionlengthslightlylong_tip: 'Votre description devient un peu longue ! Mais elle est toujours acceptable.',
descriptionlengthslightlyshort_tip: 'Votre description a l\'air sympa, mais elle pourrait être plus longue. Si cela aide à décrire la page, essayez d\'ajouter $1.',
descriptionlengthzero_tip: 'Vous n\'avez pas entré de texte. La description sera générée automatiquement.',
// Conditions
note_condition: "Every one of these conditions must be met to satisfy the requirement.",
note_condition_group: "Any one of these groups must be met in full to satisfy the requirement.",

View file

@ -20,6 +20,37 @@ var l_reputation_names = [
"[Moderator Suspension]"
];
var l_guide_categories = [
'', // 0
"Классы", // 1
"Профессии", // 2
"Игровые события", // 3
"Новые игроки", // 4
"Подземелья и рейды", // 5
"Экономика и деньги", // 6
"Достижения", // 7
"Забавные предметы", // 8
"Разное" // 9
]
var l_guide_states = [
"",
"Черновик",
"Ожидание проверки",
"Принято",
"Отклонено",
"Архивирован"
];
var l_guide_states_color = [
"",
"#71D5FF",
"#FFFF00",
"#1EFF00",
"#FF4040",
"#FFD100"
];
var mn_classes = [
[6,"Рыцарь смерти",,,{className:"c6",tinyIcon:"class_deathknight"}],
[11,"Друид",,,{className:"c11",tinyIcon:"class_druid"}],
@ -921,6 +952,30 @@ var mn_database = [
[102, 'Areatrigger', '?areatriggers', mn_areatrigger, {requiredAccess: 1726}], // aowow - custom
[103, 'Mails', '?mails'] // aowow - custom
];
var mn_guides = [
[7, "Достижения", '?guides=7'],
[1, "Классы", '?guides=1'],
[6, "Экономика и деньги", '?guides=6'],
[4, "Новые игроки", '?guides=4'],
[2, "Профессии", '?guides=2'],
[5, "Подземелья и рейды", '?guides=5'],
[8, "Забавные предметы", '?guides=8'],
[3, "Игровые события", '?guides=3', [
[,"Aowow Гайды"],
["lunar-festival","Лунный фестиваль","?guide=lunar-festival"],
["love-is-in-the-air","Любовная лихорадка","?guide=love-is-in-the-air"],
["noblegarden","Сад чудес","?guide=noblegarden"],
["childrens-week","Детская неделя","?guide=childrens-week"],
["winter-veil","Зимний Покров","?guide=winter-veil"],
["hallows-end","Тыквовин","?guide=hallows-end"],
["midsummer-fire-festival","Огненный солнцеворот","?guide=midsummer-fire-festival"],
["winter-veil","Зимний Покров","?guide=winter-veil"],
["pilgrims-bounty","Пиршество странников","?guide=pilgrims-bounty"]
]],
[9, "Разное", '?guides=9']
];
var mn_tools = [
[0,"Расчёт талантов","?talent",mn_talentCalc],
[2,"Расчёт умений питомцев","?petcalc",mn_petCalc],
@ -933,22 +988,10 @@ var mn_tools = [
]],
[1,"Карты","?maps"],
[,"Другое"],
[6,"Гайды","",[
[,"Игровые события"],
["lunar-festival","Лунный фестиваль","?guide=lunar-festival"],
["love-is-in-the-air","Любовная лихорадка","?guide=love-is-in-the-air"],
["noblegarden","Сад чудес","?guide=noblegarden"],
["childrens-week","Детская неделя","?guide=childrens-week"],
["winter-veil","Зимний Покров","?guide=winter-veil"],
["hallows-end","Тыквовин","?guide=hallows-end"],
["midsummer-fire-festival","Огненный солнцеворот","?guide=midsummer-fire-festival"],
["winter-veil","Зимний Покров","?guide=winter-veil"],
["pilgrims-bounty","Пиршество странников","?guide=pilgrims-bounty"]
]],
[8,"Дополнительно",,[
[,"База данных"],
[0,"Последние добавления","?latest-additions"],
[1,"Новые статьи","?latest-articles"],
// [0,"Последние добавления","?latest-additions"],
// [1,"Новые статьи","?latest-articles"],
[2,"Последние комментарии","?latest-comments"],
[3,"Последние изображения","?latest-screenshots"],
[11,"Последние видео","?latest-videos"],
@ -1010,11 +1053,13 @@ var mn_more = [
[16,"Окно поиска","?searchbox"],
[10,"Всплывающие подсказки","?tooltips"]
];
var mn_path = [
[0,"База данных",,mn_database],
[1,"Инструменты",,mn_tools],
[3,"Сообщество",,mn_community],
[2,"Дополнительно",,mn_more]
[0, "База данных", null, mn_database],
[1, "Инструменты", null, mn_tools],
[3, "Сообщество", null, mn_community],
[6, "Гайды", '?guides', mn_guides],
[2, "Дополнительно", null, mn_more]
];
var g_contact_reasons = {
@ -2857,6 +2902,7 @@ var LANG = {
message_cantdeletecomment: "Этот комментарий был автоматически удален из-за негативного рейтинга.",
message_cantdetachcomment: "Этот коментарий уже откреплен.",
message_codenotentered: "Вы не ввели CAPTCHA код.",
message_cantpostlcomment_tip: "Вы не можете комментировать этот гайд, доступны только английские комментарии.",
message_commentdetached: "Комментарий откреплен.",
message_commenttooshort: "Ваше сообщение не должно быть пустым.",
message_descriptiontooshort: "Ваше описание должен содержать не менее 10 символов.",
@ -3361,6 +3407,7 @@ var LANG = {
17: ["Валюта", "валюта", "Валюта", "валюта"],
19: ["Звук", "звук", "Звуки", "звуки"],
29: ["Иконка", "иконка", "Иконки", "иконки"],
300: ["Гайд", "гайд", "Гайды", "гайды"],
501: ["Эмоция", "эмоция", "Эмоции", "эмоции"],
502: ["Улучшение", "улучшение", "Улучшения", "улучшения"],
503: ["Areatrigger", "areatrigger", "Areatriggers", "areatriggers"],
@ -4755,6 +4802,7 @@ var LANG = {
build: "Версия",
calculators: "Калькуляторы",
patch: "Обновление",
status: "Статус",
sound_activities: {
greeting: "Привет",
@ -4805,6 +4853,25 @@ var LANG = {
},
/* AoWoW: start custom */
// Guide
myguides: 'Мои руководства',
listguides: '[List of guides]',
createnewguide: 'Написать новое руководство',
needsvotes_format: '(нужны еще голоса: $1)',
needsvote_format: '(нужен еще голос: $1)',
outofvotes_format: '(голоса: $1)',
outofvote_format: '(голос: $1)',
guideAuthor: 'Автор руководства',
autoresizetextbox: 'Автоматически изменять размер поля с текстом',
descriptionlengthlong_tip: 'Не может быть! Ваше описание $1 слишком велико! Вероятнее всего, оно будет сокращено.',
descriptionlengthoptimal_tip: 'Ваше описание имеет оптимальную длину. Отлично! Если необходимо, вы можете добавить ещё $1 символов.',
descriptionlengthshort_tip: 'Ваше описание слишком короткое! $1 чтобы',
descriptionlengthslightlylong_tip: 'Похоже, что описание становится слишком длинным! Но это все еще приемлимо.',
descriptionlengthslightlyshort_tip: 'Ваше описание выглядит неплохо, но могло бы быть более объемным. Попробуйте добавить ещё $1, чтобы точнее описать страницу.',
descriptionlengthzero_tip: 'Вы не ввели никакой текст. Описание будет создано автоматически.',
// Conditions
note_condition: "Every one of these conditions must be met to satisfy the requirement.",
note_condition_group: "Any one of these groups must be met in full to satisfy the requirement.",

View file

@ -20,6 +20,37 @@ var l_reputation_names = [
"管理员封号"
];
var l_guide_categories = [
'', // 0
"职业", // 1
"专业", // 2
"世界事件", // 3
"新玩家", // 4
"地下城与团队副本", // 5
"经济与金钱", // 6
"成就", // 7
"华丽收藏", // 8
"杂项" // 9
];
var l_guide_states = [
"",
"草稿",
"等待审批",
"同意",
"拒绝",
"已归档"
];
var l_guide_states_color = [
"",
"#71D5FF",
"#FFFF00",
"#1EFF00",
"#FF4040",
"#FFD100"
];
var mn_classes = [
[6,"死亡骑士",,,{className:"c6",tinyIcon:"class_deathknight"}],
[11,"德鲁伊",,,{className:"c11",tinyIcon:"class_druid"}],
@ -967,6 +998,30 @@ var mn_database = [
[102, 'Areatrigger', '?areatriggers', mn_areatrigger, {requiredAccess: 1726}], // aowow - custom
[103, 'Mails', '?mails'] // aowow - custom
];
var mn_guides = [
[7, "成就", '?guides=7'],
[1, "职业", '?guides=1'],
[6, "经济与金钱", '?guides=6'],
[4, "新玩家", '?guides=4'],
[2, "专业", '?guides=2'],
[5, "地下城与团队副本", '?guides=5'],
[8, "华丽收藏", '?guides=8'],
[3, "世界事件", '?guides=3', [
[,"Aowow 指南"],
["lunar-festival","春节","?guide=lunar-festival"],
["love-is-in-the-air","情人节","?guide=love-is-in-the-air"],
["noblegarden","复活节","?guide=noblegarden"],
["childrens-week","儿童周","?guide=childrens-week"],
["midsummer-fire-festival","仲夏火焰节","?guide=midsummer-fire-festival"],
["brewfest","美酒节","?guide=brewfest"],
["hallows-end","万圣节","?guide=hallows-end"],
["pilgrims-bounty","感恩节","?guide=pilgrims-bounty"],
["winter-veil","冬幕节","?guide=winter-veil"]
]],
[9, "杂项", '?guides=9']
];
var mn_tools = [
[0,"天赋模拟器","?talent",mn_talentCalc],
[2,"猎人宠物模拟器","?petcalc",mn_petCalc],
@ -979,22 +1034,10 @@ var mn_tools = [
]],
[1,"地图","?maps"],
[,"其他"],
[6,"指南","",[
[,"世界事件"],
["lunar-festival","春节","?guide=lunar-festival"],
["love-is-in-the-air","情人节","?guide=love-is-in-the-air"],
["noblegarden","复活节","?guide=noblegarden"],
["childrens-week","儿童周","?guide=childrens-week"],
["midsummer-fire-festival","仲夏火焰节","?guide=midsummer-fire-festival"],
["brewfest","美酒节","?guide=brewfest"],
["hallows-end","万圣节","?guide=hallows-end"],
["pilgrims-bounty","感恩节","?guide=pilgrims-bounty"],
["winter-veil","冬幕节","?guide=winter-veil"]
]],
[8,"Utilities",,[
[,"数据库"],
[0,"最新插件","?latest-additions"],
[1,"最新文章","?latest-articles"],
// [0,"最新插件","?latest-additions"],
// [1,"最新文章","?latest-articles"],
[2,"最新评论","?latest-comments"],
[3,"最新截屏","?latest-screenshots"],
[11,"最新视频","?latest-videos"],
@ -1056,11 +1099,13 @@ var mn_more = [
[8,"搜索插件","?searchplugins"],
[10,"工具提示","?tooltips"]
];
var mn_path = [
[0,"数据库",,mn_database],
[1,"工具",,mn_tools],
[3,"社区","",mn_community],
[2,"更多",,mn_more]
[0, "数据库", null, mn_database ],
[1, "工具", null, mn_tools ],
[3, "社区", null, mn_community],
[6, "指南", '?guides', mn_guides ],
[2, "更多", null, mn_more ]
];
var g_contact_reasons = {
@ -2904,6 +2949,7 @@ var LANG = {
message_cantdeletecomment: "此评论由于负分评价已被自动清除,无法删除。",
message_cantdetachcomment: "此评论已分离。",
message_codenotentered: "您没有输入验证码。",
message_cantpostlcomment_tip: "您无法评论此指南,只允许英文评论。",
message_commentdetached: "此评论已被分离。",
message_commenttooshort: "消息不可为空。",
message_descriptiontooshort: "您的描述至少要10个字符请多写一些。",
@ -3408,6 +3454,7 @@ var LANG = {
17: ["货币", "货币", "货币", "货币"],
19: ["声音", "音效", "声音", "声音"],
29: ["图标", "图标", "图标", "图标"],
300: ["指南", "指南", "指南", "指南"],
501: ["表情", "表情", "表情", "表情"],
502: ["附魔", "附魔", "附魔", "附魔"],
503: ["Areatrigger", "areatrigger", "Areatriggers", "areatriggers"],
@ -4778,6 +4825,7 @@ var LANG = {
build: "版本",
calculators: "模拟器",
patch: "补丁",
status: "状态",
sound_activities: {
greeting: "问候",
@ -4828,6 +4876,25 @@ var LANG = {
},
/* AoWoW: start custom */
// Guide
myguides: '我的指南',
listguides: '[List of guides]',
createnewguide: '创建新指南',
needsvotes_format: '(需要 $1 个投票)',
needsvote_format: '(需要 $1 个投票)',
outofvotes_format: '[(out of $1 votes)]',
outofvote_format: '[(out of $1 vote)]',
guideAuthor: '[Guide Author]',
autoresizetextbox: '自动缩放文字框',
descriptionlengthlong_tip: '欧漏,你的描述超出了$1个字可能会被删减哦。',
descriptionlengthoptimal_tip: '你的注释已经达到了合理的长度。干的漂亮!',
descriptionlengthshort_tip: '你的注释太短了!请再输入$1$个字。',
descriptionlengthslightlylong_tip: '不妙,你的描述超出了$1个字可能会被删减哦。',
descriptionlengthslightlyshort_tip: '你的描述看上去差不多了,但还能再长点。试着再增加 $1 个字。',
descriptionlengthzero_tip: '你没有输入文本,系统将自动生成描述。',
// Conditions
note_condition: "每一个条件必须满足要求。",
note_condition_group: "Any one of these groups must be met in full to satisfy the requirement.",

View file

@ -1,7 +1,7 @@
var mn_content = [
// [22, 'Achievements', '?admin=achievements', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_DEV | U_GROUP_BUREAU}],
[3, 'Announcements', '?admin=announcements', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU}],
// [25, 'Guides Awaiting Approval', '?admin=guides', null, {requiredAccess: U_GROUP_STAFF}],
[25, 'Guides Awaiting Approval', '?admin=guides', null, {requiredAccess: U_GROUP_STAFF}],
// [20, 'Global Images & Headers', '?admin=headers', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU}],
// [21, 'Modelviewer', '?admin=modelviewer', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU}],
[23, 'Out of Date Comments', '?admin=out-of-date', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD}],
@ -15,8 +15,8 @@ var mn_content = [
// [15, 'Skins', '?admin=home-skins', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SALESAGENT, breadcrumb: 'Homepage Skins'}],
[16, 'Titles', '?admin=home-titles', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU, breadcrumb: 'Homepage Titles'}],
// [, 'Articles'],
// [8, 'List', '?admin=articles', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_DEV | U_GROUP_EDITOR | U_GROUP_LOCALIZER, breadcrumb: 'List of Articles'}],
[, 'Articles'],
[8, 'List', '?admin=articles', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_DEV | U_GROUP_EDITOR | U_GROUP_LOCALIZER, breadcrumb: 'List of Articles'}],
// [9, 'Editors\' Lounge', '?admin=editors-lounge', null, {requiredAccess: U_GROUP_EMPLOYEE | U_GROUP_EDITOR | U_GROUP_LOCALIZER}],
// [23, 'Related Links', '?admin=related-links', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU}],
@ -25,7 +25,7 @@ var mn_content = [
// [11, 'Content Corner', '?admin=content-corner', null, {requiredAccess: U_GROUP_EMPLOYEE | U_GROUP_BLOGGER}],
// [12, 'Tags', '?admin=newstag', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_DEV | U_GROUP_BLOGGER, breadcrumb: 'News Tags'}],
// [24, 'Patch Updates', '?admin=patch-updates', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU}],
// [26, 'Featured Guides', '?admin=featuredguides', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU, breadcrumb: 'Featured Guides'}],
[26, 'Featured Guides', '?admin=featuredguides', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU, breadcrumb: 'Featured Guides'}],
// [, 'Community'],
// [4, 'Contests', '?admin=contests', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SALESAGENT}],
@ -170,13 +170,13 @@ $(document).ready(function () {
if ($WH.isset('g_pageInfo')) {
if (g_pageInfo.type && g_pageInfo.typeId) {
mn_staff.push([, 'DB Entry']);
// mn_staff.push([1001, 'Edit Article', '?edit=article&type=' + g_pageInfo.type + '&typeid=' + g_pageInfo.typeId, null, {requiredAccess: articleAccess}]);
mn_staff.push([1001, 'Edit Article', '?edit=article&type=' + g_pageInfo.type + '&typeid=' + g_pageInfo.typeId, null, {requiredAccess: articleAccess}]);
mn_staff.push([1000, 'Manage Screenshots', '?admin=screenshots&type=' + g_pageInfo.type + '&typeid=' + g_pageInfo.typeId, null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT}]);
mn_staff.push([1000, 'Manage Videos', '?admin=videos&type=' + g_pageInfo.type + '&typeid=' + g_pageInfo.typeId, null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO}])
}
if (g_pageInfo.articleUrl) {
mn_staff.push([, 'Article']);
mn_staff.push([1002, 'Edit', '?edit=article&' + g_pageInfo.articleUrl, null, {requiredAccess: (g_pageInfo.editAccess ? g_pageInfo.editAccess: articleAccess)}]);
mn_staff.push([1002, 'Edit', '?edit=article&' + g_pageInfo.articleUrl, null, {requiredAccess: (g_pageInfo.editAccess ? g_pageInfo.editAccess : articleAccess)}]);
mn_staff.push([1003, 'Options', '?edit=article-options&url=' + g_pageInfo.articleUrl, null, {requiredAccess: articleAccess}])
}
}

241
static/js/toolbar.js Normal file
View file

@ -0,0 +1,241 @@
var TB_BLOG = 1;
var TB_ARTICLE = 2;
var TB_QUICKFACTS = 4;
var TB_CONTEST = 8;
var TB_CONTEST_SUMMARY = 16;
var TB_INLINE = 32;
var TB_GROUP_ALL = TB_BLOG | TB_ARTICLE | TB_QUICKFACTS | TB_CONTEST | TB_CONTEST_SUMMARY | TB_INLINE;
var TB_GROUP_MAIN = TB_BLOG | TB_ARTICLE | TB_CONTEST;
var TB_GROUP_COMMON = TB_BLOG | TB_ARTICLE | TB_QUICKFACTS | TB_CONTEST;
function __AddToolbar(mode, ta, tbParent, mnParent) {
var a = function (typeStr, tag) {
var id = prompt('Please enter the ID of the ' + typeStr + '.', '');
if (id != null) {
g_insertTag(ta, '[' + tag + '=' + (parseInt(id) || 0) + ']', '');
}
};
var buttons = [
{ name: 'major-heading', icon: 'header', mode: TB_GROUP_MAIN, title: 'Major Heading: [h2]Text[/h2]', onclick: g_insertTag.bind(null, ta, '[h2]', '[/h2]') },
{ name: 'minor-heading', icon: 'header fa-size-s',mode: TB_GROUP_MAIN, title: 'Minor Heading: [h3]Text[/h3]', onclick: g_insertTag.bind(null, ta, '[h3]', '[/h3]') },
{ name: 'b', icon: 'bold', mode: TB_GROUP_ALL, title: 'Bold: [b]Text[/b]', onclick: g_insertTag.bind(null, ta, '[b]', '[/b]') },
{ name: 'i', icon: 'italic', mode: TB_GROUP_ALL, title: 'Italic: [i]Text[/i]', onclick: g_insertTag.bind(null, ta, '[i]', '[/i]') },
{ name: 'u', icon: 'underline', mode: TB_GROUP_ALL, title: 'Underline: [u]Text[/u]', onclick: g_insertTag.bind(null, ta, '[u]', '[/u]') },
{ name: 's', icon: 'strikethrough', mode: TB_GROUP_ALL, title: 'Strikethrough: [s]Text[/s]', onclick: g_insertTag.bind(null, ta, '[s]', '[/s]') },
{ name: 'small', icon: 'text-height', mode: TB_GROUP_MAIN, title: 'Small: [small]Text[/small]', onclick: g_insertTag.bind(null, ta, '[small]', '[/small]') },
{ name: 'url', icon: 'link', mode: TB_GROUP_ALL, title: 'URL: [url=...]Text[/url]', onclick: function () { var e = prompt('Please enter a URL (e.g. /item=1234).', ''); if (e != null) { g_insertTag(ta, '[url=' + $WH.trim(e) + ']', '[/url]') } } },
{ name: 'quote', icon: 'quote-left', mode: TB_GROUP_MAIN, title: 'Quote: [quote]Text[/quote]', onclick: g_insertTag.bind(null, ta, '[quote]', '[/quote]') },
{ name: 'code', icon: 'code', mode: TB_GROUP_MAIN, title: 'Code: [code]Text[/code]', onclick: g_insertTag.bind(null, ta, '[code]', '[/code]') },
{ name: 'ul', icon: 'list-ul', mode: TB_GROUP_MAIN, title: 'Unordered list (bullets)', onclick: g_insertTag.bind(null, ta, '[ul][li]', '[/li][/ul]') },
{ name: 'ol', icon: 'list-ol', mode: TB_GROUP_MAIN, title: 'Ordered list (numbers)', onclick: g_insertTag.bind(null, ta, '[ol][li]', '[/li][/ol]') },
{ name: 'li', icon: 'circle', mode: TB_GROUP_COMMON, title: 'List item', onclick: g_insertTag.bind(null, ta, '[li]', '[/li]') },
{ name: 'img', icon: 'picture-o', mode: TB_GROUP_MAIN, title: 'Image: [img src=... width=# height=# float=left|right]', onclick: function () { var e = prompt('Please enter a URL to the image.', ''); if (e != null) { g_insertTag(ta, '[img src=' + $WH.trim(e) + ']', '') } } },
{ name: 'pad', icon: 'square-o', mode: TB_GROUP_MAIN, title: 'Padding: [pad]', onclick: g_insertTag.bind(null, ta, '[pad]', '') },
{ name: 'winners', icon: 'star', mode: TB_CONTEST, title: 'Winners', onclick: g_insertTag.bind(null, ta, '[winners]', '') },
{ name: 'prizes', icon: 'gift', mode: TB_CONTEST, title: 'Prizes', onclick: g_insertTag.bind(null, ta, '[prizes]', '') },
{ name: 'entryform', icon: 'check', mode: TB_CONTEST, title: 'Entry Form', onclick: g_insertTag.bind(null, ta, '[entryform]', '') },
{ name: 'fromhtml', icon: 'html5', mode: TB_BLOG | TB_ARTICLE, title: 'Convert HTML', onclick: function () { $(ta).val(Markup.fromHtml($(ta).val())).change() } }
];
var e = LANG.ellipsis;
var menu = [
[0, 'Color', , [
[0, LANG.types[3][2], , [
[0, 'Poor', g_insertTag.bind(null, ta, '[color=q0]', '[/color]'), null, {className: 'q0'}],
[1, 'Common', g_insertTag.bind(null, ta, '[color=q1]', '[/color]'), null, {className: 'q1'}],
[2, 'Uncommon', g_insertTag.bind(null, ta, '[color=q2]', '[/color]'), null, {className: 'q2'}],
[3, 'Rare', g_insertTag.bind(null, ta, '[color=q3]', '[/color]'), null, {className: 'q3'}],
[4, 'Epic', g_insertTag.bind(null, ta, '[color=q4]', '[/color]'), null, {className: 'q4'}],
[5, 'Legendary', g_insertTag.bind(null, ta, '[color=q5]', '[/color]'), null, {className: 'q5'}],
[7, 'Heirloom', g_insertTag.bind(null, ta, '[color=q7]', '[/color]'), null, {className: 'q7'}]
// [8, 'WoW Token', g_insertTag.bind(null, ta, '[color=q8]', '[/color]'), null, {className: 'q8'}]
]],
[1, LANG.types[13][2], , [
[ 6, g_chr_classes[6], g_insertTag.bind(null, ta, '[color=c6]', '[/color]'), null, {className: 'c6'}],
// [12, g_chr_classes[12], g_insertTag.bind(null, ta, '[color=c12]', '[/color]'), null, {className: 'c12'}],
[11, g_chr_classes[11], g_insertTag.bind(null, ta, '[color=c11]', '[/color]'), null, {className: 'c11'}],
[ 3, g_chr_classes[3], g_insertTag.bind(null, ta, '[color=c3]', '[/color]'), null, {className: 'c3'}],
[ 8, g_chr_classes[8], g_insertTag.bind(null, ta, '[color=c8]', '[/color]'), null, {className: 'c8'}],
// [10, g_chr_classes[10], g_insertTag.bind(null, ta, '[color=c10]', '[/color]'), null, {className: 'c10'}],
[ 2, g_chr_classes[2], g_insertTag.bind(null, ta, '[color=c2]', '[/color]'), null, {className: 'c2'}],
[ 5, g_chr_classes[5], g_insertTag.bind(null, ta, '[color=c5]', '[/color]'), null, {className: 'c5'}],
[ 4, g_chr_classes[4], g_insertTag.bind(null, ta, '[color=c4]', '[/color]'), null, {className: 'c4'}],
[ 7, g_chr_classes[7], g_insertTag.bind(null, ta, '[color=c7]', '[/color]'), null, {className: 'c7'}],
[ 9, g_chr_classes[9], g_insertTag.bind(null, ta, '[color=c9]', '[/color]'), null, {className: 'c9'}],
[ 1, g_chr_classes[1], g_insertTag.bind(null, ta, '[color=c1]', '[/color]'), null, {className: 'c1'}],
]],
// gems
[2, LANG.gems, , [
[ 1, g_gem_colors[1], g_insertTag.bind(null, ta, '[color=meta-gem]', '[/color]'), null, {className: 'gem1'}],
[ 2, g_gem_colors[2], g_insertTag.bind(null, ta, '[color=red-gem]', '[/color]'), null, {className: 'gem2'}],
[ 4, g_gem_colors[4], g_insertTag.bind(null, ta, '[color=yellow-gem]', '[/color]'), null, {className: 'gem4'}],
[ 8, g_gem_colors[8], g_insertTag.bind(null, ta, '[color=blue-gem]', '[/color]'), null, {className: 'gem8'}],
[ 6, g_gem_colors[6], g_insertTag.bind(null, ta, '[color=orange-gem]', '[/color]'), null, {className: 'gem6'}],
[10, g_gem_colors[10], g_insertTag.bind(null, ta, '[color=purple-gem]', '[/color]'), null, {className: 'gem10'}],
[12, g_gem_colors[12], g_insertTag.bind(null, ta, '[color=green-gem]', '[/color]'), null, {className: 'gem12'}],
[14, g_gem_colors[14], g_insertTag.bind(null, ta, '[color=prismatic-gem]', '[/color]'), null, {className: 'gem14'}]
]],
// npcs
[3, LANG.types[1][2], , [
[1, 'Yell', g_insertTag.bind(null, ta, '[color=yell]', '[/color]'), null, {className: 's1'}],
[2, 'Say', g_insertTag.bind(null, ta, '[color=say]', '[/color]'), null, {className: 's2'}],
[3, 'Whisper', g_insertTag.bind(null, ta, '[color=whisper]', '[/color]'), null, {className: 's3'}],
[4, 'Emote', g_insertTag.bind(null, ta, '[color=emote]', '[/color]'), null, {className: 's4'}]
]],
[4, LANG.reputation, , [
[0, g_reputation_standings[0], g_insertTag.bind(null, ta, '[color=hated]', '[/color]'), null, {className: 'rep-hated'}],
[1, g_reputation_standings[2], g_insertTag.bind(null, ta, '[color=hostile]', '[/color]'), null, {className: 'rep-hostile'}],
[2, g_reputation_standings[2], g_insertTag.bind(null, ta, '[color=unfriendly]', '[/color]'), null, {className: 'rep-unfriendly'}],
[3, g_reputation_standings[3], g_insertTag.bind(null, ta, '[color=neutral]', '[/color]'), null, {className: 'rep-neutral'}],
[4, g_reputation_standings[4], g_insertTag.bind(null, ta, '[color=friendly]', '[/color]'), null, {className: 'rep-friendly'}],
[5, g_reputation_standings[5], g_insertTag.bind(null, ta, '[color=honored]', '[/color]'), null, {className: 'rep-honored'}],
[6, g_reputation_standings[6], g_insertTag.bind(null, ta, '[color=revered]', '[/color]'), null, {className: 'rep-revered'}],
[7, g_reputation_standings[7], g_insertTag.bind(null, ta, '[color=exalted]', '[/color]'), null, {className: 'rep-exalted'}],
]],
[5, LANG.types[15][2], , [
[10, g_gem_colors[2], g_insertTag.bind(null, ta, '[color=q10]', '[/color]'), null, {className: 'q10'}],
[1, g_gem_colors[6], g_insertTag.bind(null, ta, '[color=r1]', '[/color]'), null, {className: 'r1'}],
[2, g_gem_colors[4], g_insertTag.bind(null, ta, '[color=r2]', '[/color]'), null, {className: 'r2'}],
[3, g_gem_colors[12], g_insertTag.bind(null, ta, '[color=r3]', '[/color]'), null, {className: 'r3'}],
[4, 'Gray', g_insertTag.bind(null, ta, '[color=r4]', '[/color]'), null, {className: 'r4'}],
]]
]],
[1, LANG.icon, , [
[0, LANG.su_note_other + LANG.ellipsis, function () {
var e = prompt('Please enter the name of the icon.', '');
if (e != null) {
g_insertTag('editBox', '[icon name=' + e + ']', '[/icon]')
}
}],
[1, LANG.classes, , [
[ 6, g_chr_classes[6], g_insertTag.bind(null, ta, '[icon name=class_deathknight]', '[/icon]'), null, {className: 'c6', tinyIcon: 'class_deathknight'}],
// [12, g_chr_classes[12], g_insertTag.bind(null, ta, '[icon name=class_demonhunter]', '[/icon]'), null, {className: 'c12' tinyIcon: 'class_demonhunter'}],
[11, g_chr_classes[11], g_insertTag.bind(null, ta, '[icon name=class_druid]', '[/icon]'), null, {className: 'c11', tinyIcon: 'class_druid'}],
[ 3, g_chr_classes[3], g_insertTag.bind(null, ta, '[icon name=class_hunter]', '[/icon]'), null, {className: 'c3', tinyIcon: 'class_hunter'}],
[ 8, g_chr_classes[8], g_insertTag.bind(null, ta, '[icon name=class_mage]', '[/icon]'), null, {className: 'c8', tinyIcon: 'class_mage'}],
// [10, g_chr_classes[10], g_insertTag.bind(null, ta, '[icon name=class_monk]', '[/icon]'), null, {className: 'c10', tinyIcon: 'class_monk'}],
[ 2, g_chr_classes[2], g_insertTag.bind(null, ta, '[icon name=class_paladin]', '[/icon]'), null, {className: 'c2', tinyIcon: 'class_paladin'}],
[ 5, g_chr_classes[5], g_insertTag.bind(null, ta, '[icon name=class_priest]', '[/icon]'), null, {className: 'c5', tinyIcon: 'class_priest'}],
[ 4, g_chr_classes[4], g_insertTag.bind(null, ta, '[icon name=class_rogue]', '[/icon]'), null, {className: 'c4', tinyIcon: 'class_rogue'}],
[ 7, g_chr_classes[7], g_insertTag.bind(null, ta, '[icon name=class_shaman]', '[/icon]'), null, {className: 'c7', tinyIcon: 'class_shaman'}],
[ 8, g_chr_classes[8], g_insertTag.bind(null, ta, '[icon name=class_warlock]', '[/icon]'), null, {className: 'c9', tinyIcon: 'class_warlock'}],
[ 1, g_chr_classes[1], g_insertTag.bind(null, ta, '[icon name=class_warrior]', '[/icon]'), null, {className: 'c1', tinyIcon: 'class_warrior'}]
]],
[2, LANG.races, , [
[, LANG.male],
[10, g_chr_races[10], g_insertTag.bind(null, ta, '[icon name=race_bloodelf_male]', '[/icon]'), null, {tinyIcon: 'race_bloodelf_male'}],
[11, g_chr_races[11], g_insertTag.bind(null, ta, '[icon name=race_draenei_male]', '[/icon]'), null, {tinyIcon: 'race_draenei_male'}],
[ 3, g_chr_races[3], g_insertTag.bind(null, ta, '[icon name=race_dwarf_male]', '[/icon]'), null, {tinyIcon: 'race_dwarf_male'}],
[ 7, g_chr_races[7], g_insertTag.bind(null, ta, '[icon name=race_gnome_male]', '[/icon]'), null, {tinyIcon: 'race_gnome_male'}],
// [ 9, g_chr_races[9], g_insertTag.bind(null, ta, '[icon name=race_goblin_male]', '[/icon]'), null, {tinyIcon: 'race_goblin_male'}],
[ 1, g_chr_races[1], g_insertTag.bind(null, ta, '[icon name=race_human_male]', '[/icon]'), null, {tinyIcon: 'race_human_male'}],
[ 4, g_chr_races[4], g_insertTag.bind(null, ta, '[icon name=race_nightelf_male]', '[/icon]'), null, {tinyIcon: 'race_nightelf_male'}],
[ 2, g_chr_races[2], g_insertTag.bind(null, ta, '[icon name=race_orc_male]', '[/icon]'), null, {tinyIcon: 'race_orc_male'}],
// [24, g_chr_races[24], g_insertTag.bind(null, ta, '[icon name=race_pandaren_male]', '[/icon]'), null, {tinyIcon: 'race_pandaren_male'}],
[ 6, g_chr_races[6], g_insertTag.bind(null, ta, '[icon name=race_tauren_male]', '[/icon]'), null, {tinyIcon: 'race_tauren_male'}],
[ 8, g_chr_races[8], g_insertTag.bind(null, ta, '[icon name=race_troll_male]', '[/icon]'), null, {tinyIcon: 'race_troll_male'}],
[ 5, g_chr_races[5], g_insertTag.bind(null, ta, '[icon name=race_scourge_male]', '[/icon]'), null, {tinyIcon: 'race_scourge_male'}],
// [22, g_chr_races[22], g_insertTag.bind(null, ta, '[icon name=race_worgen_male]', '[/icon]'), null, {tinyIcon: 'race_worgen_male'}],
[, LANG.female],
[10, g_chr_races[10], g_insertTag.bind(null, ta, '[icon name=race_bloodelf_female]', '[/icon]'), null, {tinyIcon: 'race_bloodelf_female'}],
[11, g_chr_races[11], g_insertTag.bind(null, ta, '[icon name=race_draenei_female]', '[/icon]'), null, {tinyIcon: 'race_draenei_female'}],
[ 3, g_chr_races[3], g_insertTag.bind(null, ta, '[icon name=race_dwarf_female]', '[/icon]'), null, {tinyIcon: 'race_dwarf_female'}],
[ 7, g_chr_races[7], g_insertTag.bind(null, ta, '[icon name=race_gnome_female]', '[/icon]'), null, {tinyIcon: 'race_gnome_female'}],
// [ 9, g_chr_races[9], g_insertTag.bind(null, ta, '[icon name=race_goblin_female]', '[/icon]'), null, {tinyIcon: 'race_goblin_female'}],
[ 1, g_chr_races[1], g_insertTag.bind(null, ta, '[icon name=race_human_female]', '[/icon]'), null, {tinyIcon: 'race_human_female'}],
[ 4, g_chr_races[4], g_insertTag.bind(null, ta, '[icon name=race_nightelf_female]', '[/icon]'), null, {tinyIcon: 'race_nightelf_female'}],
[ 2, g_chr_races[2], g_insertTag.bind(null, ta, '[icon name=race_orc_female]', '[/icon]'), null, {tinyIcon: 'race_orc_female'}],
// [24, g_chr_races[24], g_insertTag.bind(null, ta, '[icon name=race_pandaren_female]', '[/icon]'), null, {tinyIcon: 'race_pandaren_female'}],
[ 6, g_chr_races[6], g_insertTag.bind(null, ta, '[icon name=race_tauren_female]', '[/icon]'), null, {tinyIcon: 'race_tauren_female'}],
[ 8, g_chr_races[8], g_insertTag.bind(null, ta, '[icon name=race_troll_female]', '[/icon]'), null, {tinyIcon: 'race_troll_female'}],
[ 5, g_chr_races[5], g_insertTag.bind(null, ta, '[icon name=race_scourge_female]', '[/icon]'), null, {tinyIcon: 'race_scourge_female'}],
// [22, g_chr_races[22], g_insertTag.bind(null, ta, '[icon name=race_worgen_female]', '[/icon]'), null, {tinyIcon: 'race_worgen_female'}]
]],
[3, LANG.tab_factions, , [
[1, g_sides[1], g_insertTag.bind(null, ta, '[icon name=side_alliance]', '[/icon]'), null, {tinyIcon: 'side_alliance'}],
[2, g_sides[2], g_insertTag.bind(null, ta, '[icon name=side_horde]', '[/icon]'), null, {tinyIcon: 'side_horde'}]
]],
[4, g_skill_categories[11], , [
[171, g_spell_skills[171], g_insertTag.bind(null, ta, '[icon name=trade_alchemy]', '[/icon]'), null, {tinyIcon: 'trade_alchemy'}],
[164, g_spell_skills[164], g_insertTag.bind(null, ta, '[icon name=trade_blacksmithing]', '[/icon]'), null, {tinyIcon: 'trade_blacksmithing'}],
[333, g_spell_skills[333], g_insertTag.bind(null, ta, '[icon name=trade_engraving]', '[/icon]'), null, {tinyIcon: 'trade_engraving'}],
[202, g_spell_skills[202], g_insertTag.bind(null, ta, '[icon name=trade_engineering]', '[/icon]'), null, {tinyIcon: 'trade_engineering'}],
[182, g_spell_skills[182], g_insertTag.bind(null, ta, '[icon name=spell_nature_naturetouchgrow]', '[/icon]'), null, {tinyIcon: 'spell_nature_naturetouchgrow'}],
[773, g_spell_skills[773], g_insertTag.bind(null, ta, '[icon name=inv_inscription_tradeskill01]', '[/icon]'), null, {tinyIcon: 'inv_inscription_tradeskill01'}],
[755, g_spell_skills[755], g_insertTag.bind(null, ta, '[icon name=inv_misc_gem_01]', '[/icon]'), null, {tinyIcon: 'inv_misc_gem_01'}],
[165, g_spell_skills[165], g_insertTag.bind(null, ta, '[icon name=inv_misc_armorkit_17]', '[/icon]'), null, {tinyIcon: 'inv_misc_armorkit_17'}],
[186, g_spell_skills[186], g_insertTag.bind(null, ta, '[icon name=trade_mining]', '[/icon]'), null, {tinyIcon: 'trade_mining'}],
[393, g_spell_skills[393], g_insertTag.bind(null, ta, '[icon name=inv_misc_pelt_wolf_01]', '[/icon]'), null, {tinyIcon: 'inv_misc_pelt_wolf_01'}],
[197, g_spell_skills[197], g_insertTag.bind(null, ta, '[icon name=trade_tailoring]', '[/icon]'), null, {tinyIcon: 'trade_tailoring'}]
]],
[5, g_skill_categories[9], , [
// [794, g_spell_skills[794], g_insertTag.bind(null, ta, '[icon name=trade_archaeology]', '[/icon]'), null, {tinyIcon: 'trade_archaeology'}],
[185, g_spell_skills[185], g_insertTag.bind(null, ta, '[icon name=inv_misc_food_15]', '[/icon]'), null, {tinyIcon: 'inv_misc_food_15'}],
[129, g_spell_skills[129], g_insertTag.bind(null, ta, '[icon name=spell_holy_sealofsacrifice]', '[/icon]'), null, {tinyIcon: 'spell_holy_sealofsacrifice'}],
[356, g_spell_skills[356], g_insertTag.bind(null, ta, '[icon name=trade_fishing]', '[/icon]'), null, {tinyIcon: 'trade_fishing'}],
[762, g_spell_skills[762], g_insertTag.bind(null, ta, '[icon name=spell_nature_swiftness]', '[/icon]'), null, {tinyIcon: 'spell_nature_swiftness'}]
]],
[6, LANG.sockets, , [
[ 1, g_gem_colors[1], g_insertTag.bind(null, ta, '[span class=socket-meta]', '[/span]'), null, {className: 'socket-meta'}],
[ 2, g_gem_colors[2], g_insertTag.bind(null, ta, '[span class=socket-red]', '[/span]'), null, {className: 'socket-red'}],
[ 4, g_gem_colors[4], g_insertTag.bind(null, ta, '[span class=socket-yellow]', '[/span]'), null, {className: 'socket-yellow'}],
[ 8, g_gem_colors[8], g_insertTag.bind(null, ta, '[span class=socket-blue]', '[/span]'), null, {className: 'socket-blue'}],
[14, g_gem_colors[14], g_insertTag.bind(null, ta, '[span class=socket-prismatic]', '[/span]'), null, {className: 'socket-prismatic'}]
]]
]],
[2, LANG.markup_links, , [
[9, LANG.types[10][0] + e, a.bind(null, LANG.types[10][1], "achievement")],
[11, LANG.types[13][0] + e, a.bind(null, LANG.types[13][1], "class")],
[7, LANG.types[8][0] + e, a.bind(null, LANG.types[8][1], "faction")],
[0, LANG.types[3][0] + e, a.bind(null, LANG.types[3][1], "item")],
[1, LANG.types[4][0] + e, a.bind(null, LANG.types[4][1], "itemset")],
[2, LANG.types[1][0] + e, a.bind(null, LANG.types[1][1], "npc")],
[3, LANG.types[2][0] + e, a.bind(null, LANG.types[2][1], "object")],
[8, LANG.types[9][0] + e, a.bind(null, LANG.types[9][1], "pet")],
[4, LANG.types[5][0] + e, a.bind(null, LANG.types[5][1], "quest")],
[12, LANG.types[14][0] + e, a.bind(null, LANG.types[14][1], "race")],
[13, LANG.types[15][0] + e, a.bind(null, LANG.types[15][1], "skill")],
[5, LANG.types[6][0] + e, a.bind(null, LANG.types[6][1], "spell")],
[6, LANG.types[7][0] + e, a.bind(null, LANG.types[7][1], "zone")],
[10, LANG.types[12][0] + e, a.bind(null, LANG.types[12][1], "event")],
[14, LANG.types[16][0] + e, a.bind(null, LANG.types[16][1], 'statistic')]
]]
];
if (tbParent) {
var btn;
tbParent.className += ' toolbar';
for (var i in buttons) {
if (buttons[i].mode & mode) {
$WH.ae(tbParent, btn = $WH.ce('button', { title: buttons[i].title, onclick: buttons[i].onclick },
[$WH.ce('img', { className: 'toolbar-' + buttons[i].name, src: g_staticUrl + '/images/deprecated/pixel.gif' })]
));
btn.setAttribute('type', 'button');
}
}
}
if (mnParent && ((TB_BLOG | TB_ARTICLE | TB_INLINE) & mode)) {
if (mode == TB_ARTICLE) {
menu[2][3] = menu[2][3].concat([
[, 'Maps'],
[10, 'Map...', insertMapLink],
[11, 'Pin', g_insertTag.bind(null, ta, '[pin x=0 y=0 url=?]', '[/pin]')]
]);
}
mnParent.className += ' menu-buttons';
Menu.addButtons(mnParent, menu);
}
}
bl_AddToolbar = __AddToolbar.bind(null, TB_BLOG);
ar_AddToolbar = __AddToolbar.bind(null, TB_ARTICLE);
ar_AddQuickfactToolbar = __AddToolbar.bind(null, TB_QUICKFACTS);
ar_AddInlineToolbar = __AddToolbar.bind(null, TB_INLINE);
cn_AddToolbar = __AddToolbar.bind(null, TB_CONTEST);
cn_AddSummaryToolbar = __AddToolbar.bind(null, TB_CONTEST_SUMMARY);

View file

@ -80,3 +80,39 @@ if (isset($this->redButtons[BUTTON_RESYNC])):
echo '<a href="javascript:;" class="button-red button-red-disabled"><em><b><i>'.Lang::profiler('resync').'</i></b><span>'.Lang::profiler('resync').'</span></em></a>';
endif;
endif;
// report guide
if (isset($this->redButtons[BUTTON_GUIDE_REPORT])):
if ($this->redButtons[BUTTON_GUIDE_REPORT]):
echo '<a href="javascript:;" class="button-red" onclick="a = ContactTool.show.bind(ContactTool, {mode: 6, guide: '.$this->typeId.'}); a();"><em><b><i>'.Lang::main('report').'</i></b><span>'.Lang::main('report').'</span></em></a>';
else:
echo '<a href="javascript:;" class="button-red button-red-disabled"><em><b><i>'.Lang::main('report').'</i></b><span>'.Lang::main('report').'</span></em></a>';
endif;
endif;
// show guide changelog
if (isset($this->redButtons[BUTTON_GUIDE_LOG])):
if ($this->redButtons[BUTTON_GUIDE_LOG]):
echo '<a href="?guide=changelog&id='.$this->typeId.'" class="button-red"><em><b><i>'.Lang::main('changelog').'</i></b><span>'.Lang::main('changelog').'</span></em></a>';
else:
echo '<a href="javascript:;" class="button-red button-red-disabled"><em><b><i>'.Lang::main('changelog').'</i></b><span>'.Lang::main('changelog').'</span></em></a>';
endif;
endif;
// edit existing guide
if (isset($this->redButtons[BUTTON_GUIDE_EDIT])):
if ($this->redButtons[BUTTON_GUIDE_EDIT]):
echo '<a href="?guide=edit&id='.$this->typeId.'" class="button-red"><em><b><i>'.Lang::main('edit').'</i></b><span>'.Lang::main('edit').'</span></em></a>';
else:
echo '<a href="javascript:;" class="button-red button-red-disabled"><em><b><i>'.Lang::main('edit').'</i></b><span>'.Lang::main('edit').'</span></em></a>';
endif;
endif;
// create new guide
if (isset($this->redButtons[BUTTON_GUIDE_NEW])):
if ($this->redButtons[BUTTON_GUIDE_NEW]):
echo '<a href="?guide=new" class="button-red"><em><b><i>'.Lang::main('writeGuide').'</i></b><span>'.Lang::main('writeGuide').'</span></em></a>';
else:
echo '<a href="javascript:;" class="button-red button-red-disabled"><em><b><i>'.Lang::main('writeGuide').'</i></b><span>'.Lang::main('writeGuide').'</span></em></a>';
endif;
endif;

View file

@ -0,0 +1,84 @@
var _ = [
{
id: 'description',
name: LANG.ct_dialog_description,
type: 'text',
align: 'left',
value: 'description',
after: 'title',
width: '50%',
compute: function(guide, td, tr) {
td.innerText = guide.description;
},
sortFunc: function(a, b, col) {
return $WH.strcmp(a.description, b.description);
},
getVisibleText: function(guide) {
return guide.description;
}
},
{
id: 'manage',
name: 'Manage',
type: 'text',
align: 'center',
value: 'subject',
sortable: false,
compute: function(guide, td, tr) {
let wrapper = $WH.ce('div');
let send = function (el, id, status)
{
let message = '';
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
$WH.de(el.parentNode);
},
data: { id: id, status: status, msg: message }
})
return true;
};
let a = $WH.ce('a');
a.style.fontFamily = 'Verdana, sans-serif';
a.style.marginLeft = '10px';
a.href = '#';
_ = a.cloneNode();
_.className = 'icon-edit';
_.href = '?guide=edit&id=' + guide.id;
g_addTooltip(_, 'Edit');
$WH.ae(wrapper, _);
_ = a.cloneNode();
_.className = 'icon-tick';
_.onclick = send.bind(this, td, guide.id, 3);
g_addTooltip(_, 'Approve');
$WH.ae(wrapper, _);
_ = a.cloneNode();
_.className = 'icon-delete';
_.onclick = send.bind(this, td, guide.id, 4);
g_addTooltip(_, 'Reject');
$WH.ae(wrapper, _);
$WH.ae(td, wrapper);
}
}
];

View file

@ -0,0 +1,308 @@
<?php $this->brick('header'); ?>
<div class="main" id="main">
<div class="main-precontents" id="main-precontents"></div>
<div class="main-contents" id="main-contents">
<?php
$this->brick('announcement');
$this->brick('pageTemplate');
?>
<div class="text">
<h1><?=$this->name; ?></h1>
<?php
$this->brick('article');
?>
</div>
<div class="pad"></div>
<!-- start insert -->
<div class="adjacent-preview">
<div class="adjacent-preview-edit">
<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>
</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');?>"
placeholder="<?=Lang::guide('editor', 'fullTitleTip');?>"
data-charwarning="title-char-warning">
<small id="title-char-warning" class="char-warning"></small>
</td>
</tr>
<tr>
<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');?>"
placeholder="<?=Lang::guide('editor', 'nameTip');?>"
data-charwarning="name-char-warning">
<small id="name-char-warning" class="char-warning"></small>
</td>
</tr>
<tr>
<th><label for="locale"><?=Lang::main('language');?></label></th>
<td><select name="locale" id="locale" required="required" size="1">
<?php
foreach (Lang::locales() as $i => $l):
if (CFG_LOCALES & (1 << $i))
echo ' <option value="'.$i.'"'.($this->editorFields('locale', true) == $i ? ' selected="selected"' : '').'>'.$l."</option>\n";
endforeach;
?>
</select></td>
</tr>
<tr>
<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";
endforeach;
?>
</select>
<script>
(function() {
var specCategoryIds = [1];
var setCategoryId = function() {
var $this = $(this);
$this.closest('form').attr('data-category', $this.val())
.attr('data-spec-category', $WH.in_array(specCategoryIds, $this.val()) >= 0 ? 'true' : 'false');
};
var $categorySelect = $('#category');
$categorySelect.change(setCategoryId);
setCategoryId.call($categorySelect.get(0));
setTimeout(setCategoryId.bind($categorySelect.get(0)), 500);
})();
</script>
</td>
</tr>
<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');?>">
<script>
setTimeout(function() {
// const PC = WH.Wow.PlayerClass;
// const Spec = WH.Wow.PlayerClass.Specialization;
let classes = [];
$.each(g_chr_classes, function (classId, className) {
classes.push({id: classId, name: className});
});
let specOptionsMenu = [
[0, LANG.finone, setClassSpec.bind(null, 0, -1), {
isChecked: function() {
return $WH.ge('specId').value == -1;
}
}]
];
/**
* Set the guide as being for the given class and spec.
*
* @param {number} classId
* @param {number} [specId]
* @param {boolean} [initialSetup]
*/
function setClassSpec(classId, specId, initialSetup) {
if (typeof specId !== 'number') {
specId = -1;
}
$WH.ge('specId').value = specId;
$WH.ge('classId').value = classId;
// Update the widget text.
let widget = $WH.ge('options-menu-widget-spec-id');
$WH.ee(widget);
$WH.st(
widget,
(
specId > -1 && g_chr_specs[classId][specId] ||
classId && g_chr_classes[classId] ||
LANG.finone
) + ' '
);
$WH.ae(widget, $WH.ce('i', {className: 'q0'}));
widget.className = 'options-menu-widget options-menu-widget-spec-id c' + classId;
// Add the spec/class icon.
let iconName = specId > -1 ? g_file_specs[classId][specId] : (classId ? 'class_' + g_file_classes[classId] : 'inv_misc_questionmark');
$WH.aef(widget, $WH.ce('span', { style: { display: 'inline-block', marginRight: '3px', verticalAlign: 'middle' }
}, Icon.create(iconName, 0, null, null, null, null, null, null, true)));
}
for (var y = 0, classs; classs = classes[y]; y++) {
var specMenu = [];
var specIds = [];
$.each(g_chr_specs[classs.id], function (classSpecId, classSpecName) {
specIds.push(classSpecId);
specMenu.push([classSpecId, classSpecName, setClassSpec.bind(null, classs.id, classSpecId), null, {
tinyIcon: g_file_specs[classs.id][classSpecId],
checkedFunc: (function(specId) {
return $WH.ge('specId').value == specId;
}).bind(null, classSpecId)
}]);
});
specOptionsMenu.push([classs.id, classs.name, setClassSpec.bind(null, classs.id), {
tinyIcon: 'class_' + g_file_classes[classs.id],
className: 'c' + classs.id,
menu: specMenu,
isChecked: (function(specIds) {
return specIds.indexOf($WH.ge('specId').value) > -1;
}).bind(null, specIds)
}]);
}
$WH.createOptionsMenuWidget('spec-id', "None", {
target: $('#class-guide-specialization-options td:last-child'),
options: specOptionsMenu,
noChevron: true
});
setTimeout(function() {
let specId = parseInt($WH.ge('specId').value) || 0;
let classId = parseInt($WH.ge('classId').value) || 0;
if (specId) {
// classId = PC.getBySpec(specId);
}
if (classId) {
setClassSpec(classId, specId, true);
}
}, 500);
}, 5);
</script>
</td>
</tr>
<tr>
<th><label for="description">
<dfn title="<?=Lang::guide('editor', 'descriptionTip');?>"><?=Lang::guide('editor', 'description');?></dfn></label></th>
<td colspan="3">
<textarea rows="1" name="description" cols="100" id="description" style="height:69px"
placeholder="<?=Lang::guide('editor', 'descriptionTip');?>"
><?=$this->editorFields('description');?></textarea>
<script>g_enhanceTextarea('#description')</script>
</td>
</tr>
<tr>
<td></td>
<td colspan="3"><span id="desc-info"></span></td>
</tr>
<?php
/*
<tr>
<th>
<label for="comment-emails">
<dfn title="<?=Lang::guide('editor', 'commentEmailTip');?>"><?=Lang::guide('editor', 'commentEmail');?></dfn>
</label>
</th>
<td colspan="3">
<input type="radio" name="comment-emails" value="0" checked> <?=Lang::main('no');?><input type="radio" name="comment-emails" value="1"> <?=Lang::main('yes');?></td>
</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>
<?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";
endif;
?>
</td>
</tr>
<tr>
<th><?=Lang::guide('editor', 'images');?></th>
<td colspan="3"><div id="image-upload"></div><div id="upload-progress" style="width:110px"></div><div id="upload-result"></div></td>
</tr>
</table>
<div class="adjacent-preview-controls">
<label><input class="adjacent-preview-checkbox" type="checkbox"> <?=Lang::guide('editor', 'showAdjPrev');?></label>
</div>
<div class="guide-edit-section">
<textarea
name="body"
id="editBox"
class="guide-edit-box"
onclick="leavePage()"
onkeydown="updatePreview(false, this)"
onkeyup="updatePreview(false, this)"
onchange="updatePreview(false, this)"
rows="8"
cols="40"
style="width:95%"><?=$this->editorFields('text');?></textarea>
<script>
g_enhanceTextarea('#editBox', {
markup: true,
scrollingMarkup: true,
dynamicSizing: false,
dynamicResizeOption: true
});
</script>
</div>
<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>
<button type="button" class="btn btn-site" data-type="submit" onclick="$('.guide-submission').attr('data-type', 'submit'); $('#changelog').focus();"><?=Lang::guide('editor', 'submit');?></button>
</div>
<div class="guide-submission-changelog">
<h2 class="heading-size-4"><?=Lang::guide('editor', 'changelog');?></h2>
<textarea name="changelog" id="changelog" onclick="leavePage()" onkeydown="updatePreview(false, this)" onkeyup="updatePreview(false, this)" onchange="updatePreview(false, this)" rows="6" cols="40" style="min-height:52px; width:95%" placeholder="<?=Lang::guide('editor', 'changelogTip');?>" required></textarea>
<script>g_enhanceTextarea('#changelog');</script>
<button type="submit" name="save" class="guide-submission-changelog-save"><?=Lang::guide('editor', 'save');?></button>
<button type="submit" name="submit" class="guide-submission-changelog-submit"><?=Lang::guide('editor', 'submit');?></button>
</div>
</div>
<img src="<?=STATIC_URL;?>/images/icons/ajax.gif" style="display:none" class="spinning-circle">
<span id="save-status"></span>
</form>
</div>
<div class="adjacent-preview-preview">
<h2 class="heading-size-2"><?=Lang::guide('editor', 'preview');?> &nbsp; <label style="font-size:75%"><input id="previewupdate" type="checkbox" checked="checked" onchange="setTimeout((function() {
if (this.checked) {
updatePreview(true);
}
updateQfPreview();
}).bind(this), 50)"><?=Lang::guide('editor', 'autoupdate');?></label></h2>
<div id="guide-body"><div id="livePreview" style="margin-right:10px"></div></div>
<script>updatePreview(true);</script>
</div>
</div>
<script>$WH.AdjacentPreview.init()</script>
<!-- end insert -->
</div><!-- main-contents -->
</div><!-- main -->
<?php $this->brick('footer'); ?>

View file

@ -21,6 +21,8 @@
?>
<div class="text">
<?php
$this->brick('redButtons');
if (!empty($this->h1Links)):
echo ' <div class="h1-links">'.$this->h1Links.'</div>';
endif;