mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
- implemented screenshot handling, inclding
* editing after upload * reputation gain for approved uploads * moderator interface (albeit a bit wonky) I still do not speak French, Spanish or Russian, so translations are appreciated
This commit is contained in:
@@ -17,7 +17,9 @@ AddDefaultCharset utf8
|
||||
CharsetRecodeMultipartForms Off
|
||||
</IfModule>
|
||||
|
||||
# 5MB should be enough for the largest screenshots in the land
|
||||
php_value default_charset UTF-8
|
||||
php_value upload_max_filesize 5M
|
||||
|
||||
RewriteEngine on
|
||||
# RewriteBase /~user/localPath/ # enable if the rules do not work, when they should
|
||||
|
||||
@@ -640,7 +640,28 @@ class AjaxHandler
|
||||
if (empty($this->get['action']) || !$this->params)
|
||||
return null;
|
||||
|
||||
if ($this->params[0] == 'siteconfig')
|
||||
if ($this->params[0] == 'screenshots')
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_STAFF | U_GROUP_SCREENSHOT)) // comment_mod, handleSSmod, vi_mod ?
|
||||
return null;
|
||||
|
||||
switch ($this->get['action'])
|
||||
{
|
||||
case 'list': // get all => null (optional)
|
||||
case 'manage': // get: [type => type, typeId => typeId] || [user => username]
|
||||
case 'editalt': // get: id => ssId; post: alt => caption
|
||||
case 'approve': // get: id => ssId || ,-separated id-list
|
||||
case 'sticky': // get: id => ssId || ,-separated id-list
|
||||
case 'delete': // get: id => ssId || ,-separated id-list
|
||||
case 'relocate': // get: id => ssId, typeid => typeId (but not type..?)
|
||||
$fn = 'admin_handleSS'.ucfirst($this->get['action']);
|
||||
return $this->$fn();
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if ($this->params[0] == 'siteconfig')
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
return null;
|
||||
@@ -651,7 +672,7 @@ class AjaxHandler
|
||||
if (empty($this->get['id']))
|
||||
return 'invalid configuration option given';
|
||||
|
||||
if (DB::Aowow()->query('DELETE FROM ?_config WHERE `key` = ? AND (`flags` & ?d) = 0', $this->get['id'], CON_FLAG_PERSISTANT))
|
||||
if (DB::Aowow()->query('DELETE FROM ?_config WHERE `key` = ? AND (`flags` & ?d) = 0', $this->get['id'], CON_FLAG_PERSISTENT))
|
||||
return '';
|
||||
else
|
||||
return 'option name is either protected or was not found';
|
||||
@@ -1073,6 +1094,198 @@ class AjaxHandler
|
||||
// hey, still here? you're not a Tauren/Nelf as bear or cat, are you?
|
||||
return DB::Aowow()->selectCell('SELECT IF(?d == 1, IFNULL(displayIdA, displayIdH), IFNULL(displayIdH, displayIdA)) FROM ?_shapeshiftform WHERE id = ?d', Util::sideByRaceMask(1 << ($char['race'] - 1)), $form);
|
||||
}
|
||||
|
||||
// get all => null (optional)
|
||||
// evaled response .. UNK
|
||||
private function admin_handleSSList()
|
||||
{
|
||||
// ssm_screenshotPages
|
||||
// ssm_numPagesFound
|
||||
|
||||
$pages = CommunityContent::getScreenshotPagesForManager(isset($this->get['all']), $nPages);
|
||||
$buff = 'ssm_screenshotPages = '.json_encode($pages, JSON_NUMERIC_CHECK).";\n";
|
||||
$buff .= 'ssm_numPagesFound = '.$nPages.';';
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// get: [type => type, typeId => typeId] || [user => username]
|
||||
// evaled response .. UNK
|
||||
private function admin_handleSSManage()
|
||||
{
|
||||
$res = [];
|
||||
|
||||
if (!empty($this->get['type']) && intVal($this->get['type']) && !empty($this->get['typeid']) && intVal($this->get['typeid']))
|
||||
$res = CommunityContent::getScreenshotsForManager($this->get['type'], $this->get['typeid']);
|
||||
else if (!empty($this->get['user']) && strlen(urldecode($this->get['user'])) > 2)
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE displayName = ?', strtolower(urldecode($this->get['user']))))
|
||||
$res = CommunityContent::getScreenshotsForManager(0, 0, $uId);
|
||||
|
||||
return 'ssm_screenshotData = '.json_encode($res, JSON_NUMERIC_CHECK);
|
||||
}
|
||||
|
||||
// get: id => SSid
|
||||
// resp: ''
|
||||
private function admin_handleSSEditalt()
|
||||
{
|
||||
if (empty($_GET['id']) || empty($this->post['alt']))
|
||||
return '';
|
||||
|
||||
// doesn't need to be htmlEscaped, ths javascript does that
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET caption = ? WHERE id = ?d', $this->post['alt'], $_GET['id']);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
private function admin_handleSSApprove($override = [])
|
||||
{
|
||||
if (empty($_GET['id']))
|
||||
return '';
|
||||
|
||||
$ids = $override ?: array_map('intval', explode(',', $_GET['id']));
|
||||
|
||||
// create resized and thumb version of screenshot
|
||||
$resized = [772, 618];
|
||||
$thumb = [150, 150];
|
||||
$path = 'static/uploads/screenshots/%s/%d.jpg';
|
||||
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
// must not be already approved
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT uploader FROM ?_screenshots WHERE (status & ?d) = 0 AND id = ?d', CC_FLAG_APPROVED, $id))
|
||||
{
|
||||
// should also error-log
|
||||
if (!file_exists(sprintf($path, 'pending', $id)))
|
||||
continue;
|
||||
|
||||
$srcImg = imagecreatefromjpeg(sprintf($path, 'pending', $id));
|
||||
$srcW = imagesx($srcImg);
|
||||
$srcH = imagesy($srcImg);
|
||||
|
||||
// write thumb
|
||||
$scale = min(1.0, min($thumb[0] / $srcW, $thumb[1] / $srcH));
|
||||
$destW = $srcW * $scale;
|
||||
$destH = $srcH * $scale;
|
||||
$destImg = imagecreatetruecolor($destW, $destH);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopyresampled($destImg, $srcImg, 0, 0, 0, 0, $destW, $destH, $srcW, $srcH);
|
||||
|
||||
imagejpeg($destImg, sprintf($path, 'thumb', $id), 100);
|
||||
|
||||
// write resized (only if required)
|
||||
if ($srcW > $resized[0] || $srcH > $resized[1])
|
||||
{
|
||||
$scale = min(1.0, min($resized[0] / $srcW, $resized[1] / $srcH));
|
||||
$destW = $srcW * $scale;
|
||||
$destH = $srcH * $scale;
|
||||
$destImg = imagecreatetruecolor($destW, $destH);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopyresampled($destImg, $srcImg, 0, 0, 0, 0, $destW, $destH, $srcW, $srcH);
|
||||
|
||||
imagejpeg($destImg, sprintf($path, 'resized', $id), 100);
|
||||
}
|
||||
|
||||
imagedestroy($srcImg);
|
||||
|
||||
// move screenshot from pending to normal
|
||||
rename(sprintf($path, 'pending', $id), sprintf($path, 'normal', $id));
|
||||
|
||||
// set as approved in DB and gain rep (once!)
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET status = ?d, approvedBy = ?d WHERE id = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
Util::gainSiteReputation($_, SITEREP_ACTION_UPLOAD, ['id' => $id, 'what' => 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
private function admin_handleSSSticky()
|
||||
{
|
||||
if (empty($_GET['id']))
|
||||
return '';
|
||||
|
||||
// this one is a bit strange: as far as i've seen, the only thing a 'sticky' screenshot does is show up in the infobox
|
||||
// this also means, that only one screenshot per page should be sticky
|
||||
// so, handle it one by one and the last one affecting one particular type/typId-key gets the cake
|
||||
$ids = array_map('intval', explode(',', $_GET['id']));
|
||||
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
// reset all others
|
||||
DB::Aowow()->query('UPDATE ?_screenshots a, ?_screenshots b SET a.status = a.status & ~?d WHERE a.type = b.type AND a.typeId = b.typeId AND a.id <> b.id AND b.id = ?d', CC_FLAG_STICKY, $id);
|
||||
|
||||
// approve this one (if not already)
|
||||
$this->admin_handleSSApprove([$id]);
|
||||
|
||||
// toggle sticky status
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = IF(`status` & ?d, `status` & ~?d, `status` | ?d) WHERE id = ?d AND `status` & ?d', CC_FLAG_STICKY, CC_FLAG_STICKY, CC_FLAG_STICKY, $id, CC_FLAG_APPROVED);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
// 2 steps: 1) remove from sight, 2) remove from disk
|
||||
private function admin_handleSSDelete()
|
||||
{
|
||||
if (empty($_GET['id']))
|
||||
return '';
|
||||
|
||||
$path = 'static/uploads/screenshots/%s/%d.jpg';
|
||||
$ids = array_map('intval', explode(',', $_GET['id']));
|
||||
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
// irrevocably remove already deleted files
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_screenshots WHERE status & ?d AND id = ?d', CC_FLAG_DELETED, $id))
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_screenshots WHERE id = ?d', $id);
|
||||
if (file_exists(sprintf($path, 'pending', $id)))
|
||||
unlink(sprintf($path, 'pending', $id));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// move pending or normal to pending
|
||||
if (file_exists(sprintf($path, 'normal', $id)))
|
||||
rename(sprintf($path, 'normal', $id), sprintf($path, 'pending', $id));
|
||||
|
||||
// remove resized and thumb
|
||||
if (file_exists(sprintf($path, 'thumb', $id)))
|
||||
unlink(sprintf($path, 'thumb', $id));
|
||||
|
||||
if (file_exists(sprintf($path, 'resized', $id)))
|
||||
unlink(sprintf($path, 'resized', $id));
|
||||
}
|
||||
|
||||
// flag as deleted if not aready
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET status = ?d, deletedBy = ?d WHERE id IN (?a)', CC_FLAG_DELETED, User::$id, $ids);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// get: id => ssId, typeid => typeId (but not type..?)
|
||||
// resp: ''
|
||||
private function admin_handleSSRelocate()
|
||||
{
|
||||
if (empty($this->get['id']) || empty($this->get['typeid']))
|
||||
return '';
|
||||
|
||||
$type = DB::Aowow()->selectCell('SELECT type FROM ?_screenshots WHERE id = ?d', $this->get['id']);
|
||||
$typeId = (int)$this->get['typeid'];
|
||||
|
||||
if (!(new Util::$typeClasses[$type]([['id', $typeId]]))->error)
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET typeId = ?d WHERE id = ?d', $typeId, $this->get['id']);
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -218,6 +218,128 @@ class CommunityContent
|
||||
return $replies;
|
||||
}
|
||||
|
||||
public static function getScreenshotsForManager($type, $typeId, $userId = 0)
|
||||
{
|
||||
$screenshots = DB::Aowow()->select('
|
||||
SELECT s.id, a.displayName AS user, s.date, s.width, s.height, s.type, s.typeId, s.caption, s.status, s.status AS "flags"
|
||||
FROM ?_screenshots s, ?_account a
|
||||
WHERE
|
||||
s.uploader = a.id AND
|
||||
{ s.type = ?d}
|
||||
{ AND s.typeId = ?d}
|
||||
{ s.uploader = ?d}
|
||||
LIMIT 100',
|
||||
$userId ? DBSIMPLE_SKIP : $type,
|
||||
$userId ? DBSIMPLE_SKIP : $typeId,
|
||||
$userId ? $userId : DBSIMPLE_SKIP
|
||||
);
|
||||
|
||||
$num = [];
|
||||
foreach ($screenshots as $s)
|
||||
{
|
||||
if (empty($num[$s['type']][$s['typeId']]))
|
||||
$num[$s['type']][$s['typeId']] = 1;
|
||||
else
|
||||
$num[$s['type']][$s['typeId']]++;
|
||||
}
|
||||
|
||||
// format data to meet requirements of the js
|
||||
foreach ($screenshots as $idx => &$s)
|
||||
{
|
||||
$s['date'] = date(Util::$dateFormatInternal, $s['date']);
|
||||
|
||||
$s['name'] = "Screenshot #".$s['id']; // what should we REALLY name it?
|
||||
|
||||
if (isset($screenshots[$idx - 1]))
|
||||
$s['prev'] = $idx - 1;
|
||||
|
||||
if (isset($screenshots[$idx + 1]))
|
||||
$s['next'] = $idx + 1;
|
||||
|
||||
// order gives priority for 'status'
|
||||
if (!($s['flags'] & CC_FLAG_APPROVED))
|
||||
{
|
||||
$s['pending'] = 1;
|
||||
$s['status'] = 0;
|
||||
}
|
||||
else
|
||||
$s['status'] = 100;
|
||||
|
||||
if ($s['flags'] & CC_FLAG_STICKY)
|
||||
{
|
||||
$s['sticky'] = 1;
|
||||
$s['status'] = 105;
|
||||
}
|
||||
|
||||
if ($s['flags'] & CC_FLAG_DELETED)
|
||||
{
|
||||
$s['deleted'] = 1;
|
||||
$s['status'] = 999;
|
||||
}
|
||||
|
||||
// something todo with massSelect .. am i doing this right?
|
||||
if ($num[$s['type']][$s['typeId']] == 1)
|
||||
$s['unique'] = 1;
|
||||
}
|
||||
|
||||
return $screenshots;
|
||||
}
|
||||
|
||||
public static function getScreenshotPagesForManager($all, &$nFound)
|
||||
{
|
||||
// i GUESS .. ss_getALL ? everything : unapproved
|
||||
$nFound = 0;
|
||||
$pages = DB::Aowow()->select('
|
||||
SELECT s.`type`, s.`typeId`, count(1) AS "count", MIN(s.`date`) AS "date"
|
||||
FROM ?_screenshots s
|
||||
{WHERE (s.status & ?d) = 0}
|
||||
GROUP BY s.`type`, s.`typeId`',
|
||||
$all ? DBSIMPLE_SKIP : CC_FLAG_APPROVED
|
||||
);
|
||||
|
||||
if ($pages)
|
||||
{
|
||||
// limit to one actually existing type each
|
||||
$types = array_intersect(array_unique(array_column($pages, 'type')), array_keys(Util::$typeClasses));
|
||||
foreach ($types as $t)
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($pages as $row)
|
||||
if ($row['type'] == $t)
|
||||
$ids[] = $row['typeId'];
|
||||
|
||||
if (!$ids)
|
||||
continue;
|
||||
|
||||
$cnd = [['id', $ids]];
|
||||
if ($t == TYPE_WORLDEVENT) // FKIN HOLIDAYS
|
||||
array_push($cnd, ['holidayId', $ids], 'OR');
|
||||
|
||||
$tClass = new Util::$typeClasses[$t]($cnd);
|
||||
foreach ($pages as &$p)
|
||||
if ($p['type'] == $t)
|
||||
if ($tClass->getEntry($p['typeId']))
|
||||
$p['name'] = $tClass->getField('name', true);
|
||||
}
|
||||
|
||||
foreach ($pages as &$p)
|
||||
{
|
||||
if (empty($p['name']))
|
||||
{
|
||||
Util::addNote(U_GROUP_STAFF | U_GROUP_SCREENSHOT, 'AdminPage::handleScreenshots() - Screenshot linked to nonexistant type/typeId combination '.$p['type'].'/'.$p['typeId']);
|
||||
unset($p);
|
||||
}
|
||||
else
|
||||
{
|
||||
$nFound += $p['count'];
|
||||
$p['date'] = date(Util::$dateFormatInternal, $p['date']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
private static function getComments($type, $typeId)
|
||||
{
|
||||
|
||||
@@ -300,11 +422,14 @@ class CommunityContent
|
||||
private static function getScreenshots($type, $typeId)
|
||||
{
|
||||
$screenshots = DB::Aowow()->Query("
|
||||
SELECT s.id, a.displayName AS user, s.date, s.width, s.height, s.type, s.typeId, s.caption, IF(s.status & 0x4, 1, 0) AS 'sticky'
|
||||
SELECT s.id, a.displayName AS user, s.date, s.width, s.height, s.type, s.typeId, s.caption, IF(s.status & ?d, 1, 0) AS 'sticky'
|
||||
FROM ?_screenshots s, ?_account a
|
||||
WHERE s.type = ? AND s.typeId = ? AND s.status & 0x2 AND s.uploader = a.id",
|
||||
WHERE s.type = ? AND s.typeId = ? AND s.status & ?d AND (s.status & ?d) = 0 AND s.uploader = a.id",
|
||||
CC_FLAG_STICKY,
|
||||
$type,
|
||||
$typeId
|
||||
$typeId,
|
||||
CC_FLAG_APPROVED,
|
||||
CC_FLAG_DELETED
|
||||
);
|
||||
|
||||
// format data to meet requirements of the js
|
||||
|
||||
@@ -91,7 +91,7 @@ define('CON_FLAG_TYPE_STRING', 0x08); //
|
||||
define('CON_FLAG_OPT_LIST', 0x10); // single option
|
||||
define('CON_FLAG_BITMASK', 0x20); // multiple options
|
||||
define('CON_FLAG_PHP', 0x40); // applied with ini_set() [restrictions apply!]
|
||||
define('CON_FLAG_PERSISTANT', 0x80); // can not be deleted
|
||||
define('CON_FLAG_PERSISTENT', 0x80); // can not be deleted
|
||||
|
||||
// Auth Result
|
||||
define('AUTH_OK', 0);
|
||||
|
||||
@@ -1479,7 +1479,7 @@ class Util
|
||||
$x['sourceB'] = $miscData['voterId'];
|
||||
$x['amount'] = $action == SITEREP_ACTION_UPVOTED ? CFG_REP_REWARD_UPVOTED : CFG_REP_REWARD_DOWNVOTED;
|
||||
break;
|
||||
case SITEREP_ACTION_UPLOAD: // NYI
|
||||
case SITEREP_ACTION_UPLOAD:
|
||||
if (empty($miscData['id']) || empty($miscData['what']))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ switch ($pageCall)
|
||||
case 'quests':
|
||||
case 'race':
|
||||
case 'races':
|
||||
case 'screenshot': // prepare uploaded screenshots
|
||||
case 'search': // tool: searches
|
||||
case 'skill':
|
||||
case 'skills':
|
||||
|
||||
@@ -50,6 +50,7 @@ $lang = array(
|
||||
'aboutUs' => "Über Aowow",
|
||||
'and' => " und ",
|
||||
'or' => " oder ",
|
||||
'back' => "Zurück",
|
||||
|
||||
// filter
|
||||
'extSearch' => "Erweiterte Suche",
|
||||
@@ -136,9 +137,36 @@ $lang = array(
|
||||
'dateFmtLong' => "d.m.Y \u\m H:i",
|
||||
|
||||
// error
|
||||
'intError' => "Ein interner Fehler ist aufgetreten.",
|
||||
'intError2' => "Ein interner Fehler ist aufgetreten. (%s)",
|
||||
'genericError' => "Ein Fehler trat auf; aktualisiert die Seite und versucht es nochmal. Wenn der Fehler bestehen bleibt, bitte meldet es bei <a href='#contact'>feedback</a>", # LANG.genericerror
|
||||
'bannedRating' => "Ihr wurdet davon gesperrt, Kommentare zu bewerten.", # LANG.tooltip_banned_rating
|
||||
'tooManyVotes' => "Ihr habt die tägliche Grenze für erlaubte Bewertungen erreicht. Kommt morgen mal wieder!" # LANG.tooltip_too_many_votes
|
||||
'tooManyVotes' => "Ihr habt die tägliche Grenze für erlaubte Bewertungen erreicht. Kommt morgen mal wieder!", # LANG.tooltip_too_many_votes
|
||||
|
||||
// screenshots
|
||||
'prepError' => "Bei der Aufbereitung eures Screenshots ist ein Fehler aufgetreten",
|
||||
'cropHint' => "Schneidet das Bild zu, indem ihr die Auswahl verschiebt.<br>Bitte beachtet <a href=\"?help=screenshots-tips-tricks\">Screenshots: Tipps & Tricks</a> für eine optimale Darstellung.",
|
||||
'caption' => "Kurzbeschreibung",
|
||||
'originalSize' => "Originalgröße",
|
||||
'targetSize' => "Zielgröße",
|
||||
'minSize' => "Mindestgröße",
|
||||
'displayOn' => "Hochgeladen für: %s[br][%s=%d]",
|
||||
'ssEdit' => "Screenshot bearbeiten",
|
||||
'ssUpload' => "Screenshot hochladen",
|
||||
'ssSubmit' => "Screenshot einsenden",
|
||||
'ssErrors' => array(
|
||||
'noUpload' => "Die Datei wurde nicht hochgeladen!",
|
||||
'maxSize' => "Die Datei überschreitet die max. Größe von %s!",
|
||||
'interrupted' => "Der Vorgang wurde unterbrochen!",
|
||||
'noFile' => "Es wurde keine Datei empfangen!",
|
||||
'noDest' => "Die Seite auf welcher der Screenshot angezeigt werden sollte existiert nicht!",
|
||||
'notAllowed' => "Es ist euch nicht erlaubt einen Screenshot hochzuladen!",
|
||||
'noImage' => "Die hochgeladene Datei ist kein Bild!",
|
||||
'wrongFormat' => "Das Bild muss im PNG oder JPG-Format sein!",
|
||||
'load' => "Das Bild konnte nicht geladen werden!",
|
||||
'tooSmall' => "Die Abmessungen sind zu klein! (kleiner als %d x %d)",
|
||||
'tooLarge' => "Die Abmessungen sind zu groß! (größer als %d x %d)"
|
||||
)
|
||||
),
|
||||
'game' => array(
|
||||
'achievement' => "Erfolg",
|
||||
@@ -333,8 +361,6 @@ $lang = array(
|
||||
'passMismatch' => "Die eingegebenen Kennworte stimmen nicht überein.",
|
||||
'nameInUse' => "Es existiert bereits ein Konto mit diesem Namen.",
|
||||
'mailInUse' => "Diese E-Mail-Adresse ist bereits mit einem Konto verbunden.",
|
||||
'intError' => "Ein interner Fehler ist aufgetreten.",
|
||||
'intError2' => "Ein interner Fehler ist aufgetreten. (%s)",
|
||||
'isRecovering' => "Dieses Konto wird bereits wiederhergestellt. Folgt den Anweisungen in der Nachricht oder wartet %s bis das Token verfällt.",
|
||||
'passCheckFail' => "Die Kennwörter stimmen nicht überein.", // message_passwordsdonotmatch
|
||||
'newPassDiff' => "Euer neues Kennwort muss sich von eurem alten Kennwort unterscheiden." // message_newpassdifferent
|
||||
|
||||
@@ -45,6 +45,7 @@ $lang = array(
|
||||
'aboutUs' => "About us & contact",
|
||||
'and' => " and ",
|
||||
'or' => " or ",
|
||||
'back' => "Back",
|
||||
|
||||
// filter
|
||||
'extSearch' => "Extended search",
|
||||
@@ -131,9 +132,36 @@ $lang = array(
|
||||
'dateFmtLong' => "Y/m/d \a\\t H:i",
|
||||
|
||||
// error
|
||||
'intError' => "An internal error has occurred.",
|
||||
'intError2' => "An internal error has occurred. (%s)",
|
||||
'genericError' => "An error has occurred; refresh the page and try again. If the error persists email <a href=\"#contact\">feedback</a>", # LANG.genericerror
|
||||
'bannedRating' => "You have been banned from rating comments.", # LANG.tooltip_banned_rating
|
||||
'tooManyVotes' => "You have reached the daily voting cap. Come back tomorrow!" # LANG.tooltip_too_many_votes
|
||||
'tooManyVotes' => "You have reached the daily voting cap. Come back tomorrow!", # LANG.tooltip_too_many_votes
|
||||
|
||||
// screenshots
|
||||
'prepError' => "An error occured preparing your screenshot",
|
||||
'cropHint' => "Crop the image by dragging the selection.<br>Please refer to <a href=\"?help=screenshots-tips-tricks\">Screenshots: Tips & Tricks</a> for an optimal layout.",
|
||||
'caption' => "Caption",
|
||||
'originalSize' => "Original size",
|
||||
'targetSize' => "Target size",
|
||||
'minSize' => "Minimum size",
|
||||
'displayOn' => "Displayed on: %s[br][%s=%d]",
|
||||
'ssEdit' => "Edit uploaded screenshot",
|
||||
'ssUpload' => "Screenshot Upload",
|
||||
'ssSubmit' => "Submit Screenshot",
|
||||
'ssErrors' => array(
|
||||
'noUpload' => "The file was not uploaded!",
|
||||
'maxSize' => "The file exceeds the maximum size of %s!",
|
||||
'interrupted' => "The upload process was interrupted!",
|
||||
'noFile' => "The file was not received!",
|
||||
'noDest' => "The page this screenshot should be displayed on, does not exist!",
|
||||
'notAllowed' => "You are not allowed to upload screenshots!",
|
||||
'noImage' => "The uploaded file is not an image file!",
|
||||
'wrongFormat' => "The image file must be a png or jpg!",
|
||||
'load' => "The image file could not be loaded!",
|
||||
'tooSmall' => "The image size is too small! (lower than %d x %d)",
|
||||
'tooLarge' => "The image size is too large! (greater than %d x %d)"
|
||||
)
|
||||
),
|
||||
'game' => array(
|
||||
'achievement' => "achievement",
|
||||
@@ -328,8 +356,6 @@ $lang = array(
|
||||
'passMismatch' => "The passwords you entered do not match.",
|
||||
'nameInUse' => "That username is already taken.",
|
||||
'mailInUse' => "That email is already registered to an account.",
|
||||
'intError' => "An internal error occured.",
|
||||
'intError2' => "An internal error occured. (%s)",
|
||||
'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.",
|
||||
'passCheckFail' => "Passwords do not match.", // message_passwordsdonotmatch
|
||||
'newPassDiff' => "Your new password must be different than your previous one." // message_newpassdifferent
|
||||
|
||||
@@ -50,6 +50,7 @@ $lang = array(
|
||||
'aboutUs' => "Sobre Aowow",
|
||||
'and' => " y ",
|
||||
'or' => " o ",
|
||||
'back' => "Arrière",
|
||||
|
||||
// filter
|
||||
'extSearch' => "Extender búsqueda",
|
||||
@@ -136,9 +137,36 @@ $lang = array(
|
||||
'dateFmtLong' => "d/m/Y \a \l\a\s H:i",
|
||||
|
||||
// error
|
||||
'intError' => "[An internal error occured.]",
|
||||
'intError2' => "[An internal error occured. (%s)]",
|
||||
'genericError' => "Ha ocurrido un error; refresca la página e inténtalo de nuevo. Si el error persiste manda un correo a <a href='#contact'>feedback</a>", # LANG.genericerror
|
||||
'bannedRating' => "Has sido baneado y no podrás valorar comentarios.", # LANG.tooltip_banned_rating
|
||||
'tooManyVotes' => "Has alcanzado el límite diario de votos. Vuelve mañana." # LANG.tooltip_too_many_votes
|
||||
'tooManyVotes' => "Has alcanzado el límite diario de votos. Vuelve mañana.", # LANG.tooltip_too_many_votes
|
||||
|
||||
// screenshots
|
||||
'prepError' => "[An error occured preparing your screenshot]",
|
||||
'cropHint' => "[Crop the image by dragging the selection.<br>Please refer to <a href=\"?help=screenshots-tips-tricks\">Screenshots: Tips & Tricks</a> for an optimal layout.]",
|
||||
'caption' => "[Caption]",
|
||||
'originalSize' => "[Original size]",
|
||||
'targetSize' => "[Target size]",
|
||||
'minSize' => "[Minimum size]",
|
||||
'displayOn' => "[Displayed on: %s[br][%s=%d]]",
|
||||
'ssEdit' => "[Edit uploaded screenshot]",
|
||||
'ssUpload' => "[Screenshot Upload]",
|
||||
'ssSubmit' => "[Submit Screenshot]",
|
||||
'ssErrors' => array(
|
||||
'noUpload' => "[The file was not uploaded!]",
|
||||
'maxSize' => "[The file exceeds the maximum size of %s!]",
|
||||
'interrupted' => "[The upload process was interrupted!]",
|
||||
'noFile' => "[The file was not received!]",
|
||||
'noDest' => "[The page this screenshot should be displayed on, does not exist!]",
|
||||
'notAllowed' => "[You are not allowed to upload screenshots!]",
|
||||
'noImage' => "[The uploaded file is not an image file!]",
|
||||
'wrongFormat' => "[The image file must be a png or jpg!]",
|
||||
'load' => "[The image file could not be loaded!]",
|
||||
'tooSmall' => "[The image size is too small! (lower than %d x %d)]",
|
||||
'tooLarge' => "[The image size is too large! (greater than %d x %d)]"
|
||||
)
|
||||
),
|
||||
'game' => array(
|
||||
'achievement' => "logro",
|
||||
@@ -334,8 +362,6 @@ $lang = array(
|
||||
'passMismatch' => "The passwords you entered do not match.",
|
||||
'nameInUse' => "That username is already taken.",
|
||||
'mailInUse' => "That email is already registered to an account.",
|
||||
'intError' => "An internal error occured.",
|
||||
'intError2' => "An internal error occured. (%s)",
|
||||
'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.",
|
||||
'passCheckFail' => "Las contraseñas no son iguales.", // message_passwordsdonotmatch
|
||||
'newPassDiff' => "Su nueva contraseña tiene que ser diferente a Su contraseña anterior." // message_newpassdifferent
|
||||
|
||||
@@ -50,6 +50,7 @@ $lang = array(
|
||||
'aboutUs' => "À propos de Aowow",
|
||||
'and' => " et ",
|
||||
'or' => " ou ",
|
||||
'back' => "Redro",
|
||||
|
||||
// filter
|
||||
'extSearch' => "Recherche avancée",
|
||||
@@ -136,9 +137,36 @@ $lang = array(
|
||||
'dateFmtLong' => "Y-m-d à H:i",
|
||||
|
||||
// error
|
||||
'intError' => "[An internal error occured.]",
|
||||
'intError2' => "[An internal error occured. (%s)]",
|
||||
'genericError' => "Une erreur est survenue; Actualisez la page et essayez à nouveau. Si l'erreur persiste, envoyez un email à <a href='#contact'>feedback</a>", # LANG.genericerror
|
||||
'bannedRating' => "Vous avez été banni du score des commentaires.", # LANG.tooltip_banned_rating
|
||||
'tooManyVotes' => "Vous avez voté trop souvent aujourd'hui! Revenez demain." # LANG.tooltip_too_many_votes
|
||||
'tooManyVotes' => "Vous avez voté trop souvent aujourd'hui! Revenez demain.", # LANG.tooltip_too_many_votes
|
||||
|
||||
// screenshots
|
||||
'prepError' => "[An error occured preparing your screenshot]",
|
||||
'cropHint' => "[Crop the image by dragging the selection.<br>Please refer to <a href=\"?help=screenshots-tips-tricks\">Screenshots: Tips & Tricks</a> for an optimal layout.]",
|
||||
'caption' => "[Caption]",
|
||||
'originalSize' => "[Original size]",
|
||||
'targetSize' => "[Target size]",
|
||||
'minSize' => "[Minimum size]",
|
||||
'displayOn' => "[Displayed on: %s[br][%s=%d]]",
|
||||
'ssEdit' => "[Edit uploaded screenshot]",
|
||||
'ssUpload' => "[Screenshot Upload]",
|
||||
'ssSubmit' => "[Submit Screenshot]",
|
||||
'ssErrors' => array(
|
||||
'noUpload' => "[The file was not uploaded!]",
|
||||
'maxSize' => "[The file exceeds the maximum size of %s!]",
|
||||
'interrupted' => "[The upload process was interrupted!]",
|
||||
'noFile' => "[The file was not received!]",
|
||||
'noDest' => "[The page this screenshot should be displayed on, does not exist!]",
|
||||
'notAllowed' => "[You are not allowed to upload screenshots!]",
|
||||
'noImage' => "[The uploaded file is not an image file!]",
|
||||
'wrongFormat' => "[The image file must be a png or jpg!]",
|
||||
'load' => "[The image file could not be loaded!]",
|
||||
'tooSmall' => "[The image size is too small! (lower than %d x %d)]",
|
||||
'tooLarge' => "[The image size is too large! (greater than %d x %d)]"
|
||||
)
|
||||
),
|
||||
'game' => array(
|
||||
'achievement' => "haut fait",
|
||||
@@ -333,8 +361,6 @@ $lang = array(
|
||||
'passMismatch' => "The passwords you entered do not match.",
|
||||
'nameInUse' => "That username is already taken.",
|
||||
'mailInUse' => "That email is already registered to an account.",
|
||||
'intError' => "An internal error occured.",
|
||||
'intError2' => "An internal error occured. (%s)",
|
||||
'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.",
|
||||
'passCheckFail' => "Les mots de passe ne correspondent pas.", // message_passwordsdonotmatch
|
||||
'newPassDiff' => "Votre nouveau mot de passe doit être différent de l'ancien." // message_newpassdifferent
|
||||
|
||||
@@ -50,6 +50,7 @@ $lang = array(
|
||||
'aboutUs' => "О Aowow",
|
||||
'and' => " и ",
|
||||
'or' => " или ",
|
||||
'back' => "Назад",
|
||||
|
||||
// filter
|
||||
'extSearch' => "Расширенный поиск",
|
||||
@@ -136,9 +137,36 @@ $lang = array(
|
||||
'dateFmtLong' => "Y-m-d в H:i",
|
||||
|
||||
// error
|
||||
'intError' => "[An internal error occured.]",
|
||||
'intError2' => "[An internal error occured. (%s)]",
|
||||
'genericError' => "Произошла ошибка; обновите страницу и попробуйте снова. Если ситуация повторяется, отправьте сообщение на <a href='#contact'>feedback</a>", # LANG.genericerror
|
||||
'bannedRating' => "Вам была заблокирована возможность оценивать комментарии.", # LANG.tooltip_banned_rating
|
||||
'tooManyVotes' => "Вы сегодня проголосовали слишком много раз! Вы сможете продолжить завтра." # LANG.tooltip_too_many_votes
|
||||
'tooManyVotes' => "Вы сегодня проголосовали слишком много раз! Вы сможете продолжить завтра.", # LANG.tooltip_too_many_votes
|
||||
|
||||
// screenshots
|
||||
'prepError' => "[An error occured preparing your screenshot]",
|
||||
'cropHint' => "[Crop the image by dragging the selection.<br>Please refer to <a href=\"?help=screenshots-tips-tricks\">Screenshots: Tips & Tricks</a> for an optimal layout.]",
|
||||
'caption' => "[Caption]",
|
||||
'originalSize' => "[Original size]",
|
||||
'targetSize' => "[Target size]",
|
||||
'minSize' => "[Minimum size]",
|
||||
'displayOn' => "[Displayed on: %s[br][%s=%d]]",
|
||||
'ssEdit' => "[Edit uploaded screenshot]",
|
||||
'ssUpload' => "[Screenshot Upload]",
|
||||
'ssSubmit' => "[Submit Screenshot]",
|
||||
'ssErrors' => array(
|
||||
'noUpload' => "[The file was not uploaded!]",
|
||||
'maxSize' => "[The file exceeds the maximum size of %s!]",
|
||||
'interrupted' => "[The upload process was interrupted!]",
|
||||
'noFile' => "[The file was not received!]",
|
||||
'noDest' => "[The page this screenshot should be displayed on, does not exist!]",
|
||||
'notAllowed' => "[You are not allowed to upload screenshots!]",
|
||||
'noImage' => "[The uploaded file is not an image file!]",
|
||||
'wrongFormat' => "[The image file must be a png or jpg!]",
|
||||
'load' => "[The image file could not be loaded!]",
|
||||
'tooSmall' => "[The image size is too small! (lower than %d x %d)]",
|
||||
'tooLarge' => "[The image size is too large! (greater than %d x %d)]"
|
||||
)
|
||||
),
|
||||
'game' => array(
|
||||
'achievement' => "достижение",
|
||||
@@ -333,8 +361,6 @@ $lang = array(
|
||||
'passMismatch' => "The passwords you entered do not match.",
|
||||
'nameInUse' => "That username is already taken.",
|
||||
'mailInUse' => "That email is already registered to an account.",
|
||||
'intError' => "An internal error occured.",
|
||||
'intError2' => "An internal error occured. (%s)",
|
||||
'isRecovering' => "This account is already recovering. Follow the instructions in your email or wait %s for the token to expire.",
|
||||
'passCheckFail' => "Пароли не совпадают.", // message_passwordsdonotmatch
|
||||
'newPassDiff' => "Прежний и новый пароли не должны совпадать." // message_newpassdifferent
|
||||
|
||||
@@ -323,7 +323,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
{
|
||||
case AUTH_OK:
|
||||
if (!User::$ip)
|
||||
return Lang::$account['intError'];
|
||||
return Lang::$main['intError'];
|
||||
|
||||
// reset account status, update expiration
|
||||
DB::Aowow()->query('UPDATE ?_account SET prevIP = IF(curIp = ?, prevIP, curIP), curIP = IF(curIp = ?, curIP, ?), allowExpire = ?d, status = 0, statusTimer = 0, token = "" WHERE user = ?',
|
||||
@@ -354,7 +354,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
return sprintf(Lang::$account['loginExceeded'], Util::formatTime(CFG_FAILED_AUTH_EXCLUSION * 1000));
|
||||
case AUTH_INTERNAL_ERR:
|
||||
User::destroy();
|
||||
return Lang::$account['intError'];
|
||||
return Lang::$main['intError'];
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@@ -391,7 +391,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
|
||||
// check ip
|
||||
if (!User::$ip)
|
||||
return Lang::$account['intError'];
|
||||
return Lang::$main['intError'];
|
||||
|
||||
// limit account creation
|
||||
$ip = DB::Aowow()->selectRow('SELECT ip, count, unbanDate FROM ?_account_bannedips WHERE type = 1 AND ip = ?', User::$ip);
|
||||
@@ -420,7 +420,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
$token
|
||||
);
|
||||
if (!$id) // something went wrong
|
||||
return Lang::$account['intError'];
|
||||
return Lang::$main['intError'];
|
||||
else if ($_ = $this->sendMail($email, Lang::$mail['accConfirm'][0], sprintf(Lang::$mail['accConfirm'][1], $token), CFG_ACCOUNT_CREATE_SAVE_DECAY))
|
||||
{
|
||||
// success:: update ip-bans
|
||||
@@ -460,7 +460,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
return Lang::$account['newPassDiff'];
|
||||
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET passHash = ?, status = ?d WHERE id = ?d', User::hashcrypt($newPass), ACC_STATUS_OK, $uRow['id']))
|
||||
return Lang::$account['intError'];
|
||||
return Lang::$main['intError'];
|
||||
}
|
||||
|
||||
private function doRecoverUser($target)
|
||||
@@ -475,7 +475,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
private function initRecovery($type, $target, $delay, &$token)
|
||||
{
|
||||
if (!$type)
|
||||
return Lang::$account['intError'];
|
||||
return Lang::$main['intError'];
|
||||
|
||||
// check if already processing
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT statusTimer - UNIX_TIMESTAMP() FROM ?_account WHERE email = ? AND status <> ?d AND statusTimer > UNIX_TIMESTAMP()', $target, ACC_STATUS_OK))
|
||||
@@ -484,7 +484,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
// create new token and write to db
|
||||
$token = Util::createHash();
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET token = ?, status = ?d, statusTimer = UNIX_TIMESTAMP() + ?d WHERE email = ?', $token, $type, $delay, $target))
|
||||
return Lang::$account['intError'];
|
||||
return Lang::$main['intError'];
|
||||
}
|
||||
|
||||
private function sendMail($target, $subj, $msg, $delay = 300)
|
||||
@@ -497,7 +497,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
'X-Mailer: PHP/' . phpversion();
|
||||
|
||||
if (!mail($target, $subj, $msg, $header))
|
||||
return sprintf(Lang::$account['intError2'], 'send mail');
|
||||
return sprintf(Lang::$main['intError2'], 'send mail');
|
||||
}
|
||||
|
||||
private function getNext($forHeader = false)
|
||||
|
||||
@@ -19,6 +19,14 @@ class AdminPage extends GenericPage
|
||||
{
|
||||
switch ($pageParam)
|
||||
{
|
||||
case 'screenshots':
|
||||
$this->reqUGroup = U_GROUP_STAFF | U_GROUP_SCREENSHOT;
|
||||
$this->generator = 'handleScreenshots';
|
||||
$this->tpl = 'admin/screenshots';
|
||||
|
||||
array_push($this->path, 1, 5);
|
||||
$this->name = 'Screenshot Manager';
|
||||
break;
|
||||
case 'phpinfo':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_DEV;
|
||||
$this->generator = 'handlePhpInfo';
|
||||
@@ -439,6 +447,45 @@ class AdminPage extends GenericPage
|
||||
}
|
||||
}
|
||||
|
||||
private function handleScreenshots()
|
||||
{
|
||||
$this->addJS('screenshot.js');
|
||||
$this->addCSS(array(
|
||||
['string' => '.layout {margin: 0px 25px; max-width: inherit; min-width: 1200px; }'],
|
||||
['string' => '#highlightedRow { background-color: #322C1C; }']
|
||||
));
|
||||
|
||||
$ssGetAll = isset($_GET['all']) && empty($_GET['all']);
|
||||
$ssPages = [];
|
||||
$ssData = [];
|
||||
$nMatches = 0;
|
||||
|
||||
if (!empty($_GET['type']) && !empty($_GET['typeid']))
|
||||
{
|
||||
$ssData = CommunityContent::getScreenshotsForManager(intVal($_GET['type']), intVal($_GET['typeid']));
|
||||
$nMatches = count($ssData);
|
||||
}
|
||||
else if (!empty($_GET['user']))
|
||||
{
|
||||
$name = urldecode($_GET['user']);
|
||||
if (strlen($name) > 3)
|
||||
{
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE displayName = ?', ucFirst($name)))
|
||||
{
|
||||
$ssData = CommunityContent::getScreenshotsForManager(0, 0, $uId);
|
||||
$nMatches = count($ssData);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
$ssPages = CommunityContent::getScreenshotPagesForManager($ssGetAll, $nMatches);
|
||||
|
||||
$this->getAll = $ssGetAll;
|
||||
$this->ssPages = $ssPages;
|
||||
$this->ssData = $ssData;
|
||||
$this->ssNFound = $nMatches; // ssm_numPagesFound
|
||||
}
|
||||
|
||||
private function configAddRow($r)
|
||||
{
|
||||
$buff = '<tr>';
|
||||
@@ -487,7 +534,7 @@ class AdminPage extends GenericPage
|
||||
else
|
||||
$buff .= '|<a class="icon-refresh tip disabled"></a>';
|
||||
|
||||
if (!($r['flags'] & CON_FLAG_PERSISTANT))
|
||||
if (!($r['flags'] & CON_FLAG_PERSISTENT))
|
||||
$buff .= '|<a class="icon-delete tip" onclick="cfg_remove.bind(this, \''.$key.'\')()" onmouseover="$WH.Tooltip.showAtCursor(event, \'Remove Setting\', 0, 0, \'q\')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"></a>';
|
||||
|
||||
$buff .= '<span class="status"></span></td></tr>';
|
||||
|
||||
301
pages/screenshot.php
Normal file
301
pages/screenshot.php
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
// filename: Username-type-typeId-<hash>[_original].jpg
|
||||
|
||||
class ScreenshotPage extends GenericPage
|
||||
{
|
||||
protected $tpl = 'screenshot';
|
||||
protected $js = ['Cropper.js'];
|
||||
protected $css = [['path' => 'Cropper.css']];
|
||||
protected $reqAuth = true;
|
||||
|
||||
private $tmpPath = 'static/uploads/temp/';
|
||||
private $pendingPath = 'static/uploads/screenshots/pending/';
|
||||
private $destination = null;
|
||||
protected $destType = 0;
|
||||
protected $destTypeId = 0;
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
$this->name = Lang::$main['ssEdit'];
|
||||
$this->caption = @$_POST['screenshotcaption']; // do not htmlEscape. It's applied as textnode
|
||||
|
||||
// what are its other uses..? (finalize is custom)
|
||||
if ($pageParam == 'finalize')
|
||||
{
|
||||
if (!$this->handleFinalize())
|
||||
$this->error();
|
||||
}
|
||||
else if ($pageParam != 'add')
|
||||
$this->error();
|
||||
|
||||
// get screenshot destination
|
||||
foreach ($_GET as $k => $v)
|
||||
{
|
||||
if ($v) // taret delivered as empty type.typeId key
|
||||
continue;
|
||||
|
||||
$x = explode('_', $k); // . => _ as array key
|
||||
if (count($x) != 2)
|
||||
continue;
|
||||
|
||||
// no such type
|
||||
if (empty(Util::$typeClasses[$x[0]]))
|
||||
continue;
|
||||
|
||||
$t = Util::$typeClasses[$x[0]];
|
||||
$c = [['id', intVal($x[1])]];
|
||||
if ($x[0] == TYPE_WORLDEVENT) // ohforfsake..
|
||||
$c = array_merge($c, ['OR', ['holidayId', intVal($x[1])]]);
|
||||
|
||||
$this->destination = new $t($c);
|
||||
|
||||
// no such typeId
|
||||
if ($this->destination->error)
|
||||
continue;
|
||||
|
||||
$this->destType = intVal($x[0]);
|
||||
$this->destTypeId = intVal($x[1]);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleFinalize()
|
||||
{
|
||||
if (empty($_SESSION['ssUpload']))
|
||||
return false;
|
||||
|
||||
// as its saved in session it should be valid
|
||||
$file = $_SESSION['ssUpload']['file'];
|
||||
|
||||
// check tmp file
|
||||
$fullPath = $this->tmpPath.$file.'_original.jpg';
|
||||
if (!file_exists($fullPath))
|
||||
return false;
|
||||
|
||||
// check post data
|
||||
if (empty($_POST) || empty($_POST['selection']))
|
||||
return false;
|
||||
|
||||
$dims = explode(',', $_POST['selection']);
|
||||
if (count($dims) != 4)
|
||||
return false;
|
||||
|
||||
Util::checkNumeric($dims);
|
||||
|
||||
// actually crop the image
|
||||
$srcImg = imagecreatefromjpeg($fullPath);
|
||||
|
||||
$x = (int)(imagesx($srcImg) * $dims[0]);
|
||||
$y = (int)(imagesy($srcImg) * $dims[1]);
|
||||
$w = (int)(imagesx($srcImg) * $dims[2]);
|
||||
$h = (int)(imagesy($srcImg) * $dims[3]);
|
||||
|
||||
$destImg = imagecreatetruecolor($w, $h);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopy($destImg, $srcImg, 0, 0, $x, $y, $w, $h);
|
||||
imagedestroy($srcImg);
|
||||
|
||||
// write to db
|
||||
$newId = DB::Aowow()->query(
|
||||
'INSERT INTO ?_screenshots (type, typeId, uploader, date, width, height, caption) VALUES (?d, ?d, ?d, UNIX_TIMESTAMP(), ?d, ?d, ?)',
|
||||
$_SESSION['ssUpload']['type'], $_SESSION['ssUpload']['typeId'],
|
||||
User::$id,
|
||||
$w, $h,
|
||||
$this->caption
|
||||
);
|
||||
|
||||
// write to file
|
||||
if (is_int($newId)) // 0 is valid, NULL or FALSE is not
|
||||
imagejpeg($destImg, $this->pendingPath.$newId.'.jpg', 100);
|
||||
|
||||
unset($_SESSION['ssUpload']);
|
||||
header('Location: ?user='.User::$displayName.'#screenshots');
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$maxW = 488;
|
||||
$maxH = 325;
|
||||
$minCrop = CFG_SCREENSHOT_MIN_SIZE;
|
||||
|
||||
if ($minCrop <= 0)
|
||||
{
|
||||
Util::addNote(U_GROUP_DEV | U_GROUP_ADMIN, 'ScreenshotPage::generateContent() - config error: dimensions for uploaded screenshots egual or less than zero. Value forced to 200');
|
||||
$minCrop = 200;
|
||||
}
|
||||
|
||||
if (!$this->destType)
|
||||
{
|
||||
$this->error = Lang::$main['ssErrors']['noDest'];
|
||||
return;
|
||||
}
|
||||
|
||||
if (User::$banStatus & ACC_BAN_SCREENSHOT)
|
||||
{
|
||||
$this->error = Lang::$main['ssErrors']['notAllowed'];
|
||||
return;
|
||||
}
|
||||
|
||||
if ($_ = $this->validateScreenshot($isPNG))
|
||||
{
|
||||
$this->error = $_;
|
||||
return;
|
||||
}
|
||||
|
||||
$im = $isPNG ? $this->loadFromPNG() : $this->loadFromJPG();
|
||||
if (!$im)
|
||||
{
|
||||
$this->error = Lang::$main['ssErrors']['load'];
|
||||
return;
|
||||
}
|
||||
|
||||
$name = User::$displayName.'-'.$this->destType.'-'.$this->destTypeId.'-'.Util::createHash(16);
|
||||
$oSize = $rSize = [imagesx($im), imagesy($im)];
|
||||
$rel = $oSize[0] / $oSize[1];
|
||||
|
||||
// not sure if this is the best way
|
||||
$_SESSION['ssUpload'] = array(
|
||||
'file' => $name,
|
||||
'type' => $this->destType,
|
||||
'typeId' => $this->destTypeId
|
||||
);
|
||||
|
||||
// check for oversize and refit to crop-screen
|
||||
if ($rel >= 1.5 && $oSize[0] > $maxW)
|
||||
$rSize = [$maxW, $maxW / $rel];
|
||||
else if ($rel < 1.5 && $oSize[1] > $maxH)
|
||||
$rSize = [$maxH * $rel, $maxH];
|
||||
|
||||
$this->writeImage($im, $oSize, $name.'_original'); // use this image for work
|
||||
$this->writeImage($im, $rSize, $name); // use this image to display
|
||||
|
||||
// r: resized; o: original
|
||||
// r: x <= 488 && y <= 325 while x proportional to y
|
||||
// mincrop is optional and specifies the minimum resulting image size
|
||||
$this->cropper = [
|
||||
'url' => $this->tmpPath.$name.'.jpg',
|
||||
'parent' => 'ss-container',
|
||||
'oWidth' => $oSize[0],
|
||||
'rWidth' => $rSize[0],
|
||||
'oHeight' => $oSize[1],
|
||||
'rHeight' => $rSize[1],
|
||||
];
|
||||
|
||||
$infobox = [];
|
||||
|
||||
// target
|
||||
$infobox[] = sprintf(Lang::$main['displayOn'], Util::ucFirst(Lang::$game[Util::$typeStrings[$this->destType]]), Util::$typeStrings[$this->destType], $this->destTypeId);
|
||||
$this->extendGlobalIds($this->destType, $this->destTypeId);
|
||||
|
||||
// dimensions
|
||||
$infobox[] = Lang::$main['originalSize'].Lang::$main['colon'].$oSize[0].' x '.$oSize[1];
|
||||
$infobox[] = Lang::$main['targetSize'].Lang::$main['colon'].'[span id=qf-newSize][/span]';
|
||||
|
||||
// minimum dimensions
|
||||
if (!User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
$infobox[] = Lang::$main['minSize'].Lang::$main['colon'].$minCrop.' x '.$minCrop;
|
||||
$this->cropper['minCrop'] = $minCrop;
|
||||
}
|
||||
|
||||
$this->infobox = '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]';
|
||||
}
|
||||
|
||||
private function loadFromPNG()
|
||||
{
|
||||
$image = imagecreatefrompng($_FILES['screenshotfile']['tmp_name']);
|
||||
$bg = imagecreatetruecolor(imagesx($image), imagesy($image));
|
||||
|
||||
imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
|
||||
imagealphablending($bg, true);
|
||||
imagecopy($bg, $image, 0, 0, 0, 0, imagesx($image), imagesy($image));
|
||||
imagedestroy($image);
|
||||
|
||||
return $bg;
|
||||
}
|
||||
|
||||
private function loadFromJPG()
|
||||
{
|
||||
return imagecreatefromjpeg($_FILES['screenshotfile']['tmp_name']);
|
||||
}
|
||||
|
||||
private function writeImage($im, $dims, $file)
|
||||
{
|
||||
if ($res = imagecreatetruecolor($dims[0], $dims[1]))
|
||||
if (imagecopyresampled($res, $im, 0, 0, 0, 0, $dims[0], $dims[1], imagesx($im), imagesy($im)))
|
||||
if (imagejpeg($res, $this->tmpPath.$file.'.jpg', 100))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function validateScreenshot(&$isPNG = false)
|
||||
{
|
||||
// no upload happened or some error occured
|
||||
if (!$_FILES || empty($_FILES['screenshotfile']))
|
||||
return Lang::$main['ssErrors']['noUpload'];
|
||||
|
||||
switch ($_FILES['screenshotfile']['error'])
|
||||
{
|
||||
case 1:
|
||||
return sprintf(Lang::$main['ssErrors']['maxSize'], ini_get('upload_max_filesize'));;
|
||||
case 3:
|
||||
return Lang::$main['ssErrors']['interrupted'];
|
||||
case 4:
|
||||
return Lang::$main['ssErrors']['noFile'];
|
||||
case 6:
|
||||
Util::addNote(U_GROUP_ADMIN, 'ScreenshotPage::validateScreenshot() - temporary upload directory is not set');
|
||||
return Lang::$main['intError'];
|
||||
case 7:
|
||||
Util::addNote(U_GROUP_ADMIN, 'ScreenshotPage::validateScreenshot() - could not write temporary file to disk');
|
||||
return Lang::$main['genericError'];
|
||||
}
|
||||
|
||||
// points to invalid file (hack attempt)
|
||||
if (!is_uploaded_file($_FILES['screenshotfile']['tmp_name']))
|
||||
{
|
||||
Util::addNote(U_GROUP_ADMIN, 'ScreenshotPage::validateScreenshot() - uploaded file not in upload directory');
|
||||
return Lang::$main['genericError'];
|
||||
}
|
||||
|
||||
// invalid file
|
||||
$is = getimagesize($_FILES['screenshotfile']['tmp_name']);
|
||||
if (!$is || empty($is['mime']))
|
||||
return Lang::$main['ssErrors']['notImage'];
|
||||
|
||||
// allow jpeg, png
|
||||
switch ($is['mime'])
|
||||
{
|
||||
case 'image/png':
|
||||
$isPNG = true;
|
||||
case 'image/jpg':
|
||||
case 'image/jpeg':
|
||||
break;
|
||||
default:
|
||||
return Lang::$main['ssErrors']['wrongFormat'];
|
||||
}
|
||||
|
||||
// size-missmatch: 4k UHD upper limit; 150px lower limit
|
||||
if ($is[0] < 150 || $is[1] < 150)
|
||||
return sprintf(Lang::$main['ssErrors']['tooSmall'], 150, 150);
|
||||
|
||||
if ($is[0] > 3840 || $is[1] > 2160)
|
||||
return sprintf(Lang::$main['ssErrors']['tooLarge'], 150, 150);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function generatePath() { }
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, Lang::$main['ssUpload']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
16
setup/updates/03_screenshots.sql
Normal file
16
setup/updates/03_screenshots.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
DROP TABLE IF EXISTS `aowow_screenshots`;
|
||||
CREATE TABLE IF NOT EXISTS `aowow_screenshots` (
|
||||
`id` int(16) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`type` tinyint(4) unsigned NOT NULL,
|
||||
`typeId` mediumint(9) NOT NULL,
|
||||
`uploader` int(16) unsigned NOT NULL,
|
||||
`date` int(32) unsigned NOT NULL,
|
||||
`width` smallint(5) unsigned NOT NULL,
|
||||
`height` smallint(5) unsigned NOT NULL,
|
||||
`caption` varchar(250) DEFAULT NULL,
|
||||
`status` tinyint(3) unsigned NOT NULL COMMENT 'see defines.php - CC_FLAG_*',
|
||||
`approvedBy` int(16) unsigned DEFAULT NULL,
|
||||
`deletedBy` int(16) unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `type` (`type`,`typeId`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
129
static/css/Cropper.css
Normal file
129
static/css/Cropper.css
Normal file
@@ -0,0 +1,129 @@
|
||||
.cropper {
|
||||
width:488px;
|
||||
height:325px;
|
||||
border:3px solid #404040;
|
||||
text-align:center;
|
||||
background:black;
|
||||
}
|
||||
|
||||
.canvas {
|
||||
position:relative;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.selection {
|
||||
position:absolute;
|
||||
cursor:move;
|
||||
}
|
||||
|
||||
.selection .opac {
|
||||
position:absolute;
|
||||
left:0;
|
||||
top:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
background-color:#369;
|
||||
filter:alpha(opacity=40);
|
||||
opacity:.4;
|
||||
}
|
||||
|
||||
.selection div {
|
||||
position:absolute;
|
||||
font-size:1px;
|
||||
}
|
||||
|
||||
.selection .grabw {
|
||||
left:-4px;
|
||||
top:0;
|
||||
width:9px;
|
||||
height:100%;
|
||||
cursor:w-resize;
|
||||
}
|
||||
|
||||
.selection .grabe {
|
||||
right:-4px;
|
||||
top:0;
|
||||
width:9px;
|
||||
height:100%;
|
||||
cursor:w-resize;
|
||||
}
|
||||
|
||||
.selection .grabn {
|
||||
left:0;
|
||||
top:-4px;
|
||||
width:100%;
|
||||
height:9px;
|
||||
cursor:n-resize;
|
||||
}
|
||||
|
||||
.selection .grabs {
|
||||
left:0;
|
||||
bottom:-4px;
|
||||
width:100%;
|
||||
height:9px;
|
||||
cursor:n-resize;
|
||||
}
|
||||
|
||||
.selection .grabnw {
|
||||
left:-3px;
|
||||
top:-3px;
|
||||
width:10px;
|
||||
height:10px;
|
||||
cursor:nw-resize;
|
||||
}
|
||||
|
||||
.selection .grabne {
|
||||
right:-3px;
|
||||
top:-3px;
|
||||
width:10px;
|
||||
height:10px;
|
||||
cursor:ne-resize;
|
||||
}
|
||||
|
||||
.selection .grabsw {
|
||||
left:-3px;
|
||||
bottom:-3px;
|
||||
width:10px;
|
||||
height:10px;
|
||||
cursor:ne-resize;
|
||||
}
|
||||
|
||||
.selection .grabse {
|
||||
right:-3px;
|
||||
bottom:-3px;
|
||||
width:10px;
|
||||
height:10px;
|
||||
cursor:nw-resize;
|
||||
}
|
||||
|
||||
.selection .hborder {
|
||||
left:0;
|
||||
top:0;
|
||||
width:100%;
|
||||
height:1px;
|
||||
background:url(//wowimg.zamimg.com/images/ui/misc/selection-h.gif) repeat-x top;
|
||||
}
|
||||
|
||||
.selection .hborder2 {
|
||||
left:0;
|
||||
bottom:0;
|
||||
width:100%;
|
||||
height:1px;
|
||||
background:url(//wowimg.zamimg.com/images/ui/misc/selection-h.gif) repeat-x bottom;
|
||||
}
|
||||
|
||||
.selection .vborder {
|
||||
left:0;
|
||||
top:0;
|
||||
width:1px;
|
||||
height:100%;
|
||||
background:url(//wowimg.zamimg.com/images/ui/misc/selection-v.gif) repeat-y left;
|
||||
}
|
||||
|
||||
.selection .vborder2 {
|
||||
right:0;
|
||||
top:0;
|
||||
width:1px;
|
||||
height:100%;
|
||||
background:url(//wowimg.zamimg.com/images/ui/misc/selection-v.gif) repeat-y right;
|
||||
}
|
||||
325
static/js/Cropper.js
Normal file
325
static/js/Cropper.js
Normal file
@@ -0,0 +1,325 @@
|
||||
function Cropper(opts) {
|
||||
var
|
||||
canvas,
|
||||
div,
|
||||
_;
|
||||
|
||||
$WH.cO(this, opts);
|
||||
|
||||
if (this.parent) {
|
||||
this.parent = $WH.ge(this.parent);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
this.locked = 0;
|
||||
this.selection = { node: $WH.ce('div') };
|
||||
this.canvas = { node: $WH.ce('div') };
|
||||
|
||||
if (this.minCrop == null) {
|
||||
this.minCrop = [150, 150];
|
||||
}
|
||||
else if (!isNaN(this.minCrop)) {
|
||||
this.minCrop = [(this.minCrop || 150), (this.minCrop || 150)];
|
||||
}
|
||||
|
||||
this.minCrop[0] = Math.ceil(this.minCrop[0] * this.rWidth / this.oWidth);
|
||||
this.minCrop[1] = Math.ceil(this.minCrop[1] * this.rHeight / this.oHeight);
|
||||
|
||||
canvas = this.container = $WH.ce('div');
|
||||
canvas.className = 'cropper';
|
||||
canvas = this.canvas.node;
|
||||
canvas.className = 'canvas';
|
||||
|
||||
if (this.rHeight < 325 && !this.blog) {
|
||||
canvas.style.marginTop = Math.floor((325 - this.rHeight) / 2) + 'px'
|
||||
}
|
||||
|
||||
canvas.style.width = this.rWidth + 'px';
|
||||
canvas.style.height = this.rHeight + 'px';
|
||||
canvas.style.backgroundImage = 'url(' + this.url + ')';
|
||||
$WH.ns(canvas);
|
||||
|
||||
var
|
||||
f = (this.minCrop[0] > this.minCrop[1] ? 0 : 1),
|
||||
e = (this.oWidth > this.oHeight ? 0 : 1),
|
||||
h = [this.oWidth, this.oHeight],
|
||||
g = this.minCrop[f] / this.minCrop[1 - f],
|
||||
l = [];
|
||||
|
||||
if (Math.floor(h[e] / 2) >= this.minCrop[e]) {
|
||||
l[f] = 100;
|
||||
}
|
||||
else {
|
||||
l[f] = Math.ceil(this.minCrop[f] / h[f] * 100 * 1000) / 1000;
|
||||
}
|
||||
|
||||
l[1 - f] = l[f] / g;
|
||||
if ((this.type == 1 && this.typeId == 15384) && g_user.roles & (U_GROUP_MODERATOR | U_GROUP_EDITOR)) {
|
||||
this.minCrop[0] = 1;
|
||||
this.minCrop[1] = 1;
|
||||
l = [100, 100];
|
||||
}
|
||||
|
||||
canvas = this.selection.node;
|
||||
canvas.className = 'selection';
|
||||
canvas.style.width = l[0] + '%';
|
||||
canvas.style.height = l[1] + '%';
|
||||
canvas.style.left = (100 - l[0]) / 2 + '%';
|
||||
canvas.style.top = (100 - l[1]) / 2 + '%';
|
||||
|
||||
div = $WH.ce('div');
|
||||
div.className = 'opac';
|
||||
div.onmousedown = Cropper.lock.bind(this, 5);
|
||||
canvas.appendChild(div);
|
||||
|
||||
_ = ['hborder', 'hborder2', 'vborder', 'vborder2'];
|
||||
for (var i = 0, len = _.length; i < len; ++i) {
|
||||
div = $WH.ce('div');
|
||||
div.className = _[i];
|
||||
canvas.appendChild(div);
|
||||
}
|
||||
|
||||
_ = [['w', 4], ['e', 6], ['n', 8], ['s', 2], ['nw', 7], ['ne', 9], ['sw', 1], ['se', 3]];
|
||||
for (var i = 0, len = _.length; i < len; ++i) {
|
||||
div = $WH.ce('div');
|
||||
div.className = 'grab' + _[i][0];
|
||||
div.onmousedown = Cropper.lock.bind(this, _[i][1]);
|
||||
canvas.appendChild(div);
|
||||
}
|
||||
|
||||
this.canvas.node.appendChild(this.selection.node);
|
||||
this.container.appendChild(this.canvas.node);
|
||||
this.parent.appendChild(this.container);
|
||||
|
||||
$WH.aE(document, 'mousedown', Cropper.mouseDown.bind(this));
|
||||
$WH.aE(document, 'mouseup', Cropper.mouseUp.bind(this));
|
||||
$WH.aE(document, 'mousemove', Cropper.mouseMove.bind(this));
|
||||
}
|
||||
|
||||
Cropper.prototype = {
|
||||
refreshCoords: function () {
|
||||
this.selection.coords = $WH.ac(this.selection.node);
|
||||
|
||||
this.selection.size = [this.selection.node.offsetWidth, this.selection.node.offsetHeight];
|
||||
|
||||
this.canvas.coords = $WH.ac(this.canvas.node);
|
||||
},
|
||||
|
||||
getCoords: function () {
|
||||
this.refreshCoords();
|
||||
|
||||
var
|
||||
left = this.selection.coords[0] - this.canvas.coords[0],
|
||||
top = this.selection.coords[1] - this.canvas.coords[1],
|
||||
width = this.selection.size[0],
|
||||
height = this.selection.size[1];
|
||||
|
||||
var
|
||||
w = this.rWidth,
|
||||
h = this.rHeight;
|
||||
|
||||
return [
|
||||
(left / w).toFixed(3),
|
||||
(top / h).toFixed(3),
|
||||
(width / w).toFixed(3),
|
||||
(height / h).toFixed(3)
|
||||
].join(',');
|
||||
},
|
||||
|
||||
moveSelection: function (left, top, width, height) {
|
||||
this.selection.node.style.left = left + 'px';
|
||||
this.selection.node.style.top = top + 'px';
|
||||
this.selection.node.style.width = width + 'px';
|
||||
this.selection.node.style.height = height + 'px';
|
||||
},
|
||||
|
||||
selectAll: function () {
|
||||
this.moveSelection(0, 0, this.rWidth, this.rHeight);
|
||||
}
|
||||
};
|
||||
|
||||
Cropper.lock = function (locked) {
|
||||
this.locked = locked;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Cropper.mouseDown = function (ev) {
|
||||
ev = $WH.$E(ev);
|
||||
|
||||
this.drag = 1;
|
||||
this.anchorX = ev.clientX;
|
||||
this.anchorY = ev.clientY;
|
||||
this.refreshCoords();
|
||||
};
|
||||
|
||||
Cropper.mouseUp = function (ev) {
|
||||
ev = $WH.$E(ev);
|
||||
|
||||
this.drag = this.locked = 0;
|
||||
};
|
||||
|
||||
Cropper.mouseMove = function (ev) {
|
||||
if (this.drag && this.locked) {
|
||||
ev = $WH.$E(ev);
|
||||
|
||||
var
|
||||
left = this.selection.coords[0] - this.canvas.coords[0],
|
||||
top = this.selection.coords[1] - this.canvas.coords[1],
|
||||
width = left + this.selection.size[0],
|
||||
height = top + this.selection.size[1];
|
||||
|
||||
var
|
||||
x = (ev.clientX - this.anchorX),
|
||||
y = (ev.clientY - this.anchorY);
|
||||
|
||||
var locks = null;
|
||||
|
||||
if (this.locked == 5) {
|
||||
left += x;
|
||||
width += x;
|
||||
top += y;
|
||||
height += y;
|
||||
}
|
||||
else {
|
||||
if (this.locked == 1 || this.locked == 4 || this.locked == 7) {
|
||||
left += Math.max(x, -left);
|
||||
left = Math.min(left, this.rWidth);
|
||||
|
||||
if (this.locked == 4) {
|
||||
locks = 'x';
|
||||
}
|
||||
else {
|
||||
locks = 'xy';
|
||||
}
|
||||
|
||||
if (Math.abs(left - width) < this.minCrop[0]) {
|
||||
if (left > width) {
|
||||
left = width + this.minCrop[0];
|
||||
}
|
||||
else {
|
||||
left = width - this.minCrop[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.locked == 3 || this.locked == 6 || this.locked == 9) {
|
||||
width += Math.min(x, this.rWidth - width);
|
||||
width = Math.max(width, 0);
|
||||
|
||||
if (this.locked == 6) {
|
||||
locks = 'x';
|
||||
}
|
||||
else {
|
||||
locks = 'xy';
|
||||
}
|
||||
|
||||
if (Math.abs(left - width) < this.minCrop[0]) {
|
||||
if (width > left) {
|
||||
width = left + this.minCrop[0];
|
||||
}
|
||||
else {
|
||||
width = left - this.minCrop[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.locked == 1 || this.locked == 2 || this.locked == 3) {
|
||||
height += Math.min(y, this.rHeight - height);
|
||||
height = Math.max(height, 0);
|
||||
|
||||
if (this.locked == 2) {
|
||||
locks = 'y';
|
||||
}
|
||||
else {
|
||||
locks = 'xy';
|
||||
}
|
||||
|
||||
if (Math.abs(top - height) < this.minCrop[1]) {
|
||||
if (height > top) {
|
||||
height = top + this.minCrop[1];
|
||||
}
|
||||
else {
|
||||
height = top - this.minCrop[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.locked == 7 || this.locked == 8 || this.locked == 9) {
|
||||
top += Math.max(y, -top);
|
||||
top = Math.min(top, this.rHeight);
|
||||
|
||||
if (this.locked == 8) {
|
||||
locks = 'y';
|
||||
}
|
||||
else {
|
||||
locks = 'xy';
|
||||
}
|
||||
|
||||
if (Math.abs(top - height) < this.minCrop[1]) {
|
||||
if (top > height) {
|
||||
top = height + this.minCrop[1];
|
||||
}
|
||||
else {
|
||||
top = height - this.minCrop[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (left > width) {
|
||||
var _ = left;
|
||||
left = width;
|
||||
width = _;
|
||||
}
|
||||
|
||||
if (top > height) {
|
||||
var _ = top;
|
||||
top = height;
|
||||
height = _;
|
||||
}
|
||||
|
||||
if (this.constraint) {
|
||||
var
|
||||
absX = Math.abs(x),
|
||||
absY = Math.abs(y);
|
||||
|
||||
if (locks == 'x' || (locks == 'xy' && absX > absY)) {
|
||||
var b = width - left;
|
||||
var k = this.constraint[1] / this.constraint[0];
|
||||
var p = b * k;
|
||||
|
||||
height = top + p;
|
||||
}
|
||||
else if (locks == 'y' || (locks == 'xy' && absX < absY)) {
|
||||
var p = height - top;
|
||||
var k = this.constraint[0] / this.constraint[1];
|
||||
var b = p * k;
|
||||
|
||||
width = left + b;
|
||||
}
|
||||
}
|
||||
|
||||
if (left < 0) {
|
||||
width -= left;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
if (top < 0) {
|
||||
height -= top;
|
||||
top = 0;
|
||||
}
|
||||
|
||||
if (width > this.rWidth) {
|
||||
left -= (width - this.rWidth);
|
||||
width = this.rWidth;
|
||||
}
|
||||
|
||||
if (height > this.rHeight) {
|
||||
top -= (height - this.rHeight);
|
||||
height = this.rHeight;
|
||||
}
|
||||
|
||||
this.moveSelection(left, top, width - left, height - top);
|
||||
}
|
||||
};
|
||||
1
static/js/screenshot.js
Normal file
1
static/js/screenshot.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
<title><?php echo htmlentities(implode(' - ', $this->title)); ?></title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="SHORTCUT ICON" href="<?php echo STATIC_URL; ?>/images/logos/favicon.ico" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="<?php echo STATIC_URL; ?>/download/searchplugins/aowow.xml" title="Aowow" />
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo STATIC_URL.'/css/basic.css?'.AOWOW_REVISION; ?>" />
|
||||
@@ -8,7 +8,7 @@
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo STATIC_URL.'/css/aowow.css?'.AOWOW_REVISION; ?>" />
|
||||
<link rel="stylesheet" type="text/css" href="<?php echo STATIC_URL.'/css/locale_'.User::$localeString.'.css?'.AOWOW_REVISION; ?>" />
|
||||
<?php
|
||||
if (User::isInGroup(U_GROUP_STAFF)):
|
||||
if (User::isInGroup(U_GROUP_STAFF | U_GROUP_SCREENSHOT | U_GROUP_VIDEO)):
|
||||
echo ' <link rel="stylesheet" type="text/css" href="'.STATIC_URL.'/css/staff.css?'.AOWOW_REVISION."\" />\n";
|
||||
endif;
|
||||
|
||||
@@ -40,7 +40,7 @@ endif;
|
||||
<script src="<?php echo STATIC_URL.'/js/locale.js?'.AOWOW_REVISION; ?>" type="text/javascript"></script>
|
||||
<script src="<?php echo STATIC_URL.'/js/Markup.js?'.AOWOW_REVISION; ?>" type="text/javascript"></script>
|
||||
<?php
|
||||
if (User::isInGroup(U_GROUP_STAFF)):
|
||||
if (User::isInGroup(U_GROUP_STAFF | U_GROUP_SCREENSHOT | U_GROUP_VIDEO)):
|
||||
echo ' <script src="'.STATIC_URL.'/js/staff.js?'.AOWOW_REVISION."\" type=\"text/javascript\"></script>\n";
|
||||
endif;
|
||||
|
||||
|
||||
@@ -36,12 +36,22 @@ if (!empty($this->type) && !empty($this->typeId)):
|
||||
?>
|
||||
<tr><th id="infobox-screenshots"><?php echo Lang::$main['screenshots']; ?></th></tr>
|
||||
<tr><td><div class="infobox-spacer"></div><div id="infobox-sticky-ss"></div></td></tr>
|
||||
<?php
|
||||
if (User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO) || !empty($this->community['vi'])):
|
||||
?>
|
||||
<tr><th id="infobox-videos"><?php echo Lang::$main['videos']; ?></th></tr>
|
||||
<tr><td><div class="infobox-spacer"></div><div id="infobox-sticky-vi"></div></td></tr>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
</table>
|
||||
<script type="text/javascript">ss_appendSticky()</script>
|
||||
<?php
|
||||
if (User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_VIDEO) || !empty($this->community['vi'])):
|
||||
?>
|
||||
<script type="text/javascript">vi_appendSticky()</script>
|
||||
<?php
|
||||
endif;
|
||||
else:
|
||||
echo " </table>\n";
|
||||
endif;
|
||||
|
||||
138
template/pages/admin/screenshots.tpl.php
Normal file
138
template/pages/admin/screenshots.tpl.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?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><?php echo $this->name; ?></h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>User: </td>
|
||||
<td colspan="2"><input type="text" id="usermanage" size="23"></td>
|
||||
<td>» <a href="#" onClick="ss_ManageUser()">Search by User</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Page: </td>
|
||||
<td>
|
||||
<select id="pagetype">
|
||||
<?php
|
||||
foreach (Util::$typeStrings as $i => $str):
|
||||
if (isset(Lang::$game[$str])):
|
||||
echo " <option value=\"".$i."\">".Util::ucFirst(Lang::$game[$str])."</option>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
</select>
|
||||
</td>
|
||||
<td>#<input type="number" size="5" id="pagetypeid"></td>
|
||||
<td>» <a href="#" onClick="ss_Manage(null, $('#pagetype').val(), $('#pagetypeid').val())">Search by Page</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr />
|
||||
<table style="width:100%;">
|
||||
<thead><tr><th style="width:135px;"><div>Menu</div></th><th style="width:400px;">Pages</th><th>Screenshots: <span id="screenshotTotal"></span></th></tr></thead>
|
||||
<tbody><tr>
|
||||
<td id="menu-container" style="vertical-align: top;">
|
||||
<div id="show-all-pages"><?php echo $this->ssNFound ? ' – <a href="?admin=screenshots&all">Show All</a> ('.$this->ssNFound.')' : null; ?></div>
|
||||
<h4>Mass Select</h4>
|
||||
– <a href="#" onClick="ssm_MassSelect(1);">Select All</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(0);">Deselect All</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(-1);">Toggle Selection</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(2);">Select All Pending</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(5);">Select All Unique</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(3);">Select All Approved</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(4);">Select All Sticky</a><br>
|
||||
<div id="withselected" style="display:none;">
|
||||
<h4>Mass Action <b>(0)</b></h4>
|
||||
– <a href="#" id="massapprove">Approve All</a><br>
|
||||
– <a href="#" id="massdelete">Delete All</a><br>
|
||||
– <a href="#" id="masssticky">Sticky All</a><br>
|
||||
</div>
|
||||
</td>
|
||||
<td id="pages-container" style="vertical-align: top;"></td>
|
||||
<td id="data-container" style="vertical-align: top;"><table class="grid" id="theScreenshotsList"><thead><tr>
|
||||
<th>Screenshot</th>
|
||||
<th>Id</th>
|
||||
<th>Caption</th>
|
||||
<th>Date</th>
|
||||
<th>Uploader</th>
|
||||
<th>Status</th>
|
||||
<th>Options</th>
|
||||
</tr></thead></table></td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
var hasLoader = false;
|
||||
function ajaxAnchor(el)
|
||||
{
|
||||
if (!el.href || hasLoader)
|
||||
return;
|
||||
|
||||
$('#withselected').find('h4').append(" ").append(CreateAjaxLoader());
|
||||
hasLoader = true;
|
||||
|
||||
new Ajax(el.href, {
|
||||
method: 'get',
|
||||
onSuccess: function(xhr) {
|
||||
hasLoader = false;
|
||||
$('#withselected img').remove();
|
||||
|
||||
var g = $WH.g_getGets();
|
||||
if (g.type && g.typeid)
|
||||
ss_Manage(null, g.type, g.typeid);
|
||||
else if (g.user)
|
||||
ss_ManageUser();
|
||||
else
|
||||
ss_Refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$WH.ge('usermanage').onkeydown = function(e)
|
||||
{
|
||||
e = $WH.$E(e);
|
||||
if (e.keyCode != 13)
|
||||
return;
|
||||
|
||||
ss_ManageUser();
|
||||
}
|
||||
|
||||
$WH.ge('pagetypeid').onkeydown = function(e)
|
||||
{
|
||||
e = $WH.$E(e);
|
||||
var validKeys = [8, 9, 13, 35, 36, 37, 39, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57];
|
||||
if (!e.ctrlKey && $WH.in_array(validKeys, e.keyCode) == -1)
|
||||
return false;
|
||||
|
||||
if (e.keyCode == 13 && this.value != '')
|
||||
ss_Manage();
|
||||
|
||||
return true;
|
||||
}
|
||||
<?php
|
||||
if ($this->getAll):
|
||||
echo " var ss_getAll = true;\n";
|
||||
endif;
|
||||
if ($this->ssPages):
|
||||
echo " var ssm_screenshotPages = ".json_encode($this->ssPages, JSON_NUMERIC_CHECK).";\n";
|
||||
echo " ssm_UpdatePages();\n";
|
||||
elseif ($this->ssData):
|
||||
echo " var ssm_screenshotData = ".json_encode($this->ssData, JSON_NUMERIC_CHECK).";\n";
|
||||
echo " ssm_UpdateList();\n";
|
||||
endif;
|
||||
?>
|
||||
ss_OnResize();
|
||||
</script>
|
||||
</div>
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
<?php $this->brick('footer'); ?>
|
||||
119
template/pages/screenshot.tpl.php
Normal file
119
template/pages/screenshot.tpl.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?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');
|
||||
|
||||
$this->brick('infobox');
|
||||
|
||||
if (isset($this->error)):
|
||||
?>
|
||||
<div class="pad3"></div>
|
||||
|
||||
<div class="inputbox">
|
||||
<h1><?php echo Lang::$main['prepError']; ?></h1>
|
||||
<div id="inputbox-error"><?php echo $this->error; ?><br><a href="<?php echo $this->destType ? '?'.Util::$typeStrings[$this->destType].'='.$this->destTypeId : 'javascript:history.back();'; ?>"><?php echo Lang::$main['back']; ?></a></div>
|
||||
<?php
|
||||
else:
|
||||
?>
|
||||
<div class="text">
|
||||
<h1><?php echo $this->name; ?></h1>
|
||||
|
||||
<?php
|
||||
if ($this->mode == 'add'):
|
||||
?>
|
||||
<div id="ss-container" style="float:right;"></div>
|
||||
<div id="img-edit-form">
|
||||
<span><?php echo Lang::$main['cropHint']; ?></span>
|
||||
<div class="pad"></div>
|
||||
<b><?php echo Lang::$main['caption'].Lang::$main['colon']; ?></b><br>
|
||||
<form action="?screenshot=finalize" method="post">
|
||||
<textarea style="resize: none;" name="screenshotcaption" cols="27" rows="4"><?php echo $this->caption; ?></textarea>
|
||||
<div class="text-counter">text counter ph</div>
|
||||
<div style="clear:right;"></div>
|
||||
<input type="hidden" id="selection" name="selection" value=""></input>
|
||||
<input type="submit" value="<?php echo Lang::$main['ssSubmit']; ?>"></input>
|
||||
</form>
|
||||
</div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var
|
||||
cropper = new Cropper(<?php echo json_encode($this->cropper, JSON_NUMERIC_CHECK); ?>),
|
||||
captionMaxLen = 200;
|
||||
|
||||
Body = $('#img-edit-form').find('textarea');
|
||||
TextCounter = $('#img-edit-form').find('div.text-counter');
|
||||
Form = $('#img-edit-form').find('form');
|
||||
qfSizeDiv = $('.infobox').find('#qf-newSize');
|
||||
|
||||
$('body').mouseup(UpdateImageSelection);
|
||||
|
||||
Form.submit(function () { return submitSS(); });
|
||||
|
||||
UpdateTextCounter();
|
||||
UpdateImageSelection();
|
||||
|
||||
Body.keyup(function (e) { return UpdateTextCounter(); });
|
||||
Body.keypress(function (e) { // ENTER
|
||||
if (e.keyCode == 13 || captionMaxLen - getCaptionLen() <= 0 )
|
||||
return false;
|
||||
});
|
||||
|
||||
Form.find('textarea').focus();
|
||||
|
||||
function getCaptionLen()
|
||||
{
|
||||
return Body.val().replace(/(\s+)/g, ' ').replace(/^\s*/, '').replace(/\s*$/, '').length;
|
||||
}
|
||||
|
||||
function UpdateTextCounter()
|
||||
{
|
||||
var text = '(error)';
|
||||
var cssClass = 'q0';
|
||||
var chars = getCaptionLen();
|
||||
var charsLeft = captionMaxLen - chars;
|
||||
|
||||
text = $WH.sprintf(charsLeft == 1 ? LANG.replylength4_format : LANG.replylength3_format, charsLeft);
|
||||
|
||||
if (charsLeft < 25)
|
||||
cssClass = 'q10';
|
||||
else if (charsLeft < 50)
|
||||
cssClass = 'q5';
|
||||
else if (charsLeft < 75)
|
||||
cssClass = 'q11';
|
||||
|
||||
TextCounter.html(text).attr('class', cssClass);
|
||||
}
|
||||
|
||||
function UpdateImageSelection()
|
||||
{
|
||||
dims = cropper.getCoords().split(',');
|
||||
|
||||
w = Math.floor(cropper.oWidth * dims[2]);
|
||||
h = Math.floor(cropper.oHeight * dims[3]);
|
||||
|
||||
qfSizeDiv.html(w + ' x ' + h);
|
||||
}
|
||||
|
||||
function submitSS()
|
||||
{
|
||||
$('#selection').val(cropper.getCoords());
|
||||
|
||||
return true;
|
||||
}
|
||||
//]]></script>
|
||||
|
||||
<div class="pad2"></div>
|
||||
<?php
|
||||
endif;
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
<?php $this->brick('footer'); ?>
|
||||
Reference in New Issue
Block a user