Merge pull request #63 from g-plane/master

细节优化,感谢 @g-plane!
This commit is contained in:
printempw 2017-04-28 22:12:40 +08:00 committed by GitHub
commit e6030842aa
38 changed files with 1065 additions and 644 deletions

View File

@ -165,25 +165,25 @@ class AdminController extends Controller
return view('admin.users'); return view('admin.users');
} }
public function getUserData() public function getUserData(Request $request)
{ {
$users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at']); $users = collect();
$permissionTextMap = [ if ($request->has('uid')) {
User::BANNED => trans('admin.users.status.banned'), $users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at'])
User::NORMAL => trans('admin.users.status.normal'), ->where('uid', intval($request->input('uid')));
User::ADMIN => trans('admin.users.status.admin'), } else {
User::SUPER_ADMIN => trans('admin.users.status.super-admin') $users = User::select(['uid', 'email', 'nickname', 'score', 'permission', 'register_at']);
]; }
return Datatables::of($users)->editColumn('email', function ($user) { return Datatables::of($users)->editColumn('email', function ($user) {
return $user->email ?: 'EMPTY'; return $user->email ?: 'EMPTY';
})->editColumn('permission', function ($user) use ($permissionTextMap) {
return array_get($permissionTextMap, $user->permission);
}) })
->setRowId('uid') ->setRowId('uid')
->editColumn('score', 'vendor.admin-operations.users.score') ->addColumn('operations', app('user.current')->getPermission())
->addColumn('operations', 'vendor.admin-operations.users.operations') ->addColumn('players_count', function ($user) {
return Player::where('uid', $user->uid)->count();
})
->make(true); ->make(true);
} }
@ -198,15 +198,17 @@ class AdminController extends Controller
return view('admin.players'); return view('admin.players');
} }
public function getPlayerData() public function getPlayerData(Request $request)
{ {
$players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified']); $players = collect();
if ($request->has('uid')) {
$players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified'])
->where('uid', intval($request->input('uid')));
} else {
$players = Player::select(['pid', 'uid', 'player_name', 'preference', 'tid_steve', 'tid_alex', 'tid_cape', 'last_modified']);
}
return Datatables::of($players)->editColumn('preference', 'vendor.admin-operations.players.preference') return Datatables::of($players)->setRowId('pid')->make(true);
->setRowId('pid')
->addColumn('previews', 'vendor.admin-operations.players.previews')
->addColumn('operations', 'vendor.admin-operations.players.operations')
->make(true);
} }
/** /**
@ -228,6 +230,10 @@ class AdminController extends Controller
'email' => 'required|email' 'email' => 'required|email'
]); ]);
if ($users->get($request->input('email'), 'email')) {
return json(trans('admin.users.operations.email.existed', ['email' => $request->input('email')]), 1);
}
$user->setEmail($request->input('email')); $user->setEmail($request->input('email'));
return json(trans('admin.users.operations.email.success'), 0); return json(trans('admin.users.operations.email.success'), 0);
@ -354,6 +360,28 @@ class AdminController extends Controller
$player->delete(); $player->delete();
return json(trans('admin.players.delete.success'), 0); return json(trans('admin.players.delete.success'), 0);
} elseif ($action == "name") {
$player->rename($request->input('name'));
return json(trans('admin.players.name.success', ['player' => $player->player_name]), 0, ['name' => $player->player_name]);
}
}
/**
* Get one user information
*
* @param string $uid
* @return JsonResponse
*/
public function getOneUser($uid, UserRepository $users)
{
$user = $users->get(intval($uid));
if ($user) {
return json('success', 0, ['user' => $user->makeHidden([
'password', 'ip', 'last_sign_at', 'register_at'
])->toArray()]);
} else {
return json('No such user.', 1);
} }
} }

View File

@ -25,43 +25,40 @@ class ClosetController extends Controller
$this->closet = new Closet(session('uid')); $this->closet = new Closet(session('uid'));
} }
public function index(Request $request) public function index()
{
return view('user.closet')->with('user', app('user.current'));
}
public function getClosetData(Request $request)
{ {
$category = $request->input('category', 'skin'); $category = $request->input('category', 'skin');
$page = $request->input('page', 1); $page = abs($request->input('page', 1));
$page = $page <= 0 ? 1 : $page;
$q = $request->input('q', null); $q = $request->input('q', null);
$items = []; $items = [];
if ($q) { if ($q) {
foreach (['skin', 'cape'] as $category) { // do search
// do search foreach ($this->closet->getItems($category) as $item) {
foreach ($this->closet->getItems($category) as $item) { if (stristr($item->name, $q)) {
if (strstr($item->name, $q)) { $items[] = $item;
$items[$category][] = $item;
}
} }
} }
} else { } else {
$items['skin'] = $this->closet->getItems('skin'); $items = $this->closet->getItems($category);
$items['cape'] = $this->closet->getItems('cape');
} }
// pagination // pagination
$total_pages = []; $total_pages = ceil(count($items) / 6);
foreach ($items as $key => $value) { $items = array_slice($items, ($page - 1) * 6, 6);
$total_pages[] = ceil(count($items[$key]) / 6);
$items[$key] = array_slice($value, ($page-1)*6, 6);
}
return view('user.closet')->with('items', $items) return response()->json([
->with('page', $page) 'category' => $category,
->with('q', $q) 'items' => $items,
->with('category', $category) 'total_pages' => $total_pages
->with('total_pages', $total_pages ? max($total_pages) : 0) ]);
->with('user', app('user.current'));
} }
public function info() public function info()

View File

@ -138,9 +138,13 @@ class PlayerController extends Controller
return json(trans('user.player.set.success', ['name' => $this->player->player_name]), 0); return json(trans('user.player.set.success', ['name' => $this->player->player_name]), 0);
} }
public function clearTexture() public function clearTexture(Request $request)
{ {
$this->player->clearTexture(); $types = array_filter(['steve', 'alex', 'cape'], function ($type) use ($request) {
return $request->input($type);
});
$this->player->clearTexture($types);
return json(trans('user.player.clear.success', ['name' => $this->player->player_name]), 0); return json(trans('user.player.clear.success', ['name' => $this->player->player_name]), 0);
} }

View File

@ -75,13 +75,13 @@ class PluginController extends Controller
return trans($plugin->description); return trans($plugin->description);
}) })
->editColumn('author', function ($plugin) { ->editColumn('author', function ($plugin) {
return "<a href='{$plugin->url}' target='_blank'>".trans($plugin->author)."</a>"; return ['author' => trans($plugin->author), 'url' => $plugin->url];
}) })
->addColumn('status', function ($plugin) { ->addColumn('status', function ($plugin) {
return trans('admin.plugins.status.'.($plugin->isEnabled() ? 'enabled' : 'disabled')); return trans('admin.plugins.status.'.($plugin->isEnabled() ? 'enabled' : 'disabled'));
}) })
->addColumn('operations', function ($plugin) { ->addColumn('operations', function ($plugin) {
return view('vendor.admin-operations.plugins.operations', compact('plugin')); return ['enabled' => $plugin->isEnabled(), 'hasConfigView' => $plugin->hasConfigView()];
}) })
->make(true); ->make(true);
} }

View File

@ -32,7 +32,7 @@ class SetupController extends Controller
{ {
$this->validate($request, [ $this->validate($request, [
'email' => 'required|email', 'email' => 'required|email',
'password' => 'required|min:6|max:16|confirmed', 'password' => 'required|min:8|max:16|confirmed',
'site_name' => 'required' 'site_name' => 'required'
]); ]);

View File

@ -32,41 +32,41 @@ class SkinlibController extends Controller
{ {
$filter = $request->input('filter', 'skin'); $filter = $request->input('filter', 'skin');
$sort = $request->input('sort', 'time'); $sort = $request->input('sort', 'time');
$uid = $request->input('uid', session('uid')); $uid = intval($request->input('uid', 0));
$page = $request->input('page', 1); $page = $request->input('page', 1) <= 0 ? 1 : $request->input('page', 1);
$page = $page <= 0 ? 1 : $page;
$sort_by = ($sort == "time") ? "upload_at" : $sort; $sort_by = ($sort == "time") ? "upload_at" : $sort;
if ($filter == "skin") { if ($filter == "skin") {
$textures = Texture::where(function($query) { $textures = Texture::where('type', 'steve')->orWhere('type', 'alex');
$query->where('type', '=', 'steve')
->orWhere('type', '=', 'alex');
})->orderBy($sort_by, 'desc');
} elseif ($filter == "user") {
$textures = Texture::where('uploader', $uid)->orderBy($sort_by, 'desc');
} else { } else {
$textures = Texture::where('type', $filter)->orderBy($sort_by, 'desc'); $textures = Texture::where('type', $filter);
}
$textures = $textures->orderBy($sort_by, 'desc')->get();
if ($uid != 0) {
$textures = $textures->where('uploader', $uid);
} }
if (!is_null($this->user)) { if (!is_null($this->user)) {
// show private textures when show uploaded textures of current user // show private textures when show uploaded textures of current user
if (!$this->user->isAdmin()) if ($uid != $this->user->uid && !$this->user->isAdmin()) {
$textures = $textures->where('public', '1') $textures = $textures->where('public', 1)
->orWhere('uploader', $this->user->uid); ->merge($textures->where('uploader', $this->user->uid));
}
} else { } else {
$textures = $textures->where('public', '1'); $textures = $textures->where('public', 1);
} }
$total_pages = ceil($textures->count() / 20); $total_pages = ceil($textures->count() / 20);
$textures = $textures->skip(($page - 1) * 20)->take(20)->get(); $textures = $textures->slice(($page - 1) * 20);
return view('skinlib.index')->with('user', $this->user) return view('skinlib.index')->with('user', $this->user)
->with('sort', $sort) ->with('sort', $sort)
->with('filter', $filter) ->with('filter', $filter)
->with('uploader', $uid)
->with('textures', $textures) ->with('textures', $textures)
->with('page', $page) ->with('page', $page)
->with('total_pages', $total_pages); ->with('total_pages', $total_pages);
@ -80,22 +80,36 @@ class SkinlibController extends Controller
$sort_by = ($sort == "time") ? "upload_at" : $sort; $sort_by = ($sort == "time") ? "upload_at" : $sort;
if ($q == '') {
return redirect('skinlib');
}
if ($filter == "skin") { if ($filter == "skin") {
$textures = Texture::like('name', $q)->where(function($query) use ($q) { $textures = Texture::like('name', $q)->where(function($query) use ($q) {
$query->where('public', '=', '1') $query->where('type', '=', 'steve')
->where('type', '=', 'steve')
->orWhere('type', '=', 'alex'); ->orWhere('type', '=', 'alex');
})->orderBy($sort_by, 'desc')->get(); })->orderBy($sort_by, 'desc')->get();
} else { } else {
$textures = Texture::like('name', $q) $textures = Texture::like('name', $q)
->where('type', $filter) ->where('type', $filter)
->where('public', '1') ->where('public', 1)
->orderBy($sort_by, 'desc')->get(); ->orderBy($sort_by, 'desc')->get();
} }
if (!is_null($this->user)) {
// show private textures when show uploaded textures of current user
if (!$this->user->isAdmin()) {
$textures = $textures->where('public', 1)
->merge($textures->where('uploader', $this->user->uid));
}
} else {
$textures = $textures->where('public', 1);
}
return view('skinlib.search')->with('user', $this->user) return view('skinlib.search')->with('user', $this->user)
->with('sort', $sort) ->with('sort', $sort)
->with('filter', $filter) ->with('filter', $filter)
->with('uploader', 0)
->with('q', $q) ->with('q', $q)
->with('textures', $textures); ->with('textures', $textures);
} }
@ -153,6 +167,7 @@ class SkinlibController extends Controller
$t->upload_at = Utils::getTimeFormatted(); $t->upload_at = Utils::getTimeFormatted();
$cost = $t->size * (($t->public == "1") ? Option::get('score_per_storage') : Option::get('private_score_per_storage')); $cost = $t->size * (($t->public == "1") ? Option::get('score_per_storage') : Option::get('private_score_per_storage'));
$cost += option('score_per_closet_item');
if ($this->user->getScore() < $cost) if ($this->user->getScore() < $cost)
return json(trans('skinlib.upload.lack-score'), 7); return json(trans('skinlib.upload.lack-score'), 7);
@ -182,7 +197,7 @@ class SkinlibController extends Controller
} }
} }
public function delete(Request $request) public function delete(Request $request, UserRepository $users)
{ {
$result = Texture::find($request->tid); $result = Texture::find($request->tid);
@ -197,17 +212,24 @@ class SkinlibController extends Controller
Storage::delete($result['hash']); Storage::delete($result['hash']);
if (option('return_score')) { if (option('return_score')) {
if ($result->public == 1) if ($result->public == 1) {
$this->user->setScore($result->size * Option::get('score_per_storage'), 'plus'); $users->get($result->uploader)->setScore($result->size * Option::get('score_per_storage'), 'plus');
foreach (Closet::all() as $closet) {
if ($closet->has($result->tid)) {
$closet->remove($result->tid);
$users->get($closet->uid)->setScore(option('score_per_closet_item'), 'plus');
}
}
}
else else
$this->user->setScore($result->size * Option::get('private_score_per_storage'), 'plus'); $users->get($result->uploader)->setScore($result->size * Option::get('private_score_per_storage'), 'plus');
} }
if ($result->delete()) if ($result->delete())
return json(trans('skinlib.delete.success'), 0); return json(trans('skinlib.delete.success'), 0);
} }
public function privacy(Request $request) public function privacy(Request $request, UserRepository $users)
{ {
$t = Texture::find($request->input('tid')); $t = Texture::find($request->input('tid'));
$type = $t->type; $type = $t->type;
@ -227,12 +249,12 @@ class SkinlibController extends Controller
if ($closet->uid != $uid && $closet->has($t->tid)) { if ($closet->uid != $uid && $closet->has($t->tid)) {
$closet->remove($t->tid); $closet->remove($t->tid);
if (option('return_score')) { if (option('return_score')) {
User::find($closet->uid)->setScore(option('score_per_closet_item'), 'plus'); $users->get($closet->uid)->setScore(option('score_per_closet_item'), 'plus');
} }
} }
} }
app('user.current')->setScore( $users->get($t->uploader)->setScore(
$t->size * (option('private_score_per_storage') - option('score_per_storage')) * ($t->public == 1 ? -1 : 1), $t->size * (option('private_score_per_storage') - option('score_per_storage')) * ($t->public == 1 ? -1 : 1),
'plus' 'plus'
); );

View File

@ -90,9 +90,9 @@ class UserController extends Controller
* Handle changing user profile. * Handle changing user profile.
* *
* @param Request $request * @param Request $request
* @return void * @return mixed
*/ */
public function handleProfile(Request $request) public function handleProfile(Request $request, UserRepository $users)
{ {
$action = $request->input('action', ''); $action = $request->input('action', '');
@ -129,6 +129,10 @@ class UserController extends Controller
'password' => 'required|min:8|max:16' 'password' => 'required|min:8|max:16'
]); ]);
if ($users->get($request->input('new_email'), 'email')) {
return json(trans('user.profile.email.existed'), 1);
}
if (!$this->user->verifyPassword($request->input('password'))) if (!$this->user->verifyPassword($request->input('password')))
return json(trans('user.profile.email.wrong-password'), 1); return json(trans('user.profile.email.wrong-password'), 1);

View File

@ -65,6 +65,7 @@ Route::group(['middleware' => 'auth', 'prefix' => 'user'], function ()
// Closet // Closet
Route::get ('/closet', 'ClosetController@index'); Route::get ('/closet', 'ClosetController@index');
Route::get ('/closet-data', 'ClosetController@getClosetData');
Route::post('/closet/add', 'ClosetController@add'); Route::post('/closet/add', 'ClosetController@add');
Route::post('/closet/remove', 'ClosetController@remove'); Route::post('/closet/remove', 'ClosetController@remove');
Route::post('/closet/rename', 'ClosetController@rename'); Route::post('/closet/rename', 'ClosetController@rename');
@ -107,6 +108,7 @@ Route::group(['middleware' => 'admin', 'prefix' => 'admin'], function ()
Route::get('/players', 'AdminController@players'); Route::get('/players', 'AdminController@players');
Route::get('/player-data', 'AdminController@getPlayerData'); Route::get('/player-data', 'AdminController@getPlayerData');
Route::get('/user/{uid}', 'AdminController@getOneUser');
// ajax handlers // ajax handlers
Route::post('/users', 'AdminController@userAjaxHandler'); Route::post('/users', 'AdminController@userAjaxHandler');

View File

@ -97,17 +97,22 @@ class Player extends Model
/** /**
* Clear the textures of player. * Clear the textures of player.
* *
* @return mixed * @param array|string $types
* @return $this
*/ */
public function clearTexture() public function clearTexture($types)
{ {
$this->setPreference('default'); $types = (array) $types;
return $this->setTexture([ $map = [];
'tid_steve' => 0,
'tid_alex' => 0, foreach ($types as $type) {
'tid_cape' => 0 $map["tid_$type"] = 0;
]); }
$this->setTexture($map);
return $this;
} }
/** /**

View File

@ -24,6 +24,10 @@
"font-awesome": "Font-Awesome#^4.6.3", "font-awesome": "Font-Awesome#^4.6.3",
"bootstrap-fileinput": "^4.3.3", "bootstrap-fileinput": "^4.3.3",
"bootstrap": "^3.3.6", "bootstrap": "^3.3.6",
"sweetalert2": "^4.1.6" "sweetalert2": "^4.1.6",
"jqPaginator": "^1.2.0"
},
"resolutions": {
"jquery": "1.9.1 - 3"
} }
} }

View File

@ -1,8 +1,8 @@
/* /*
* @Author: printempw * @Author: printempw
* @Date: 2016-07-21 13:38:26 * @Date: 2016-07-21 13:38:26
* @Last Modified by: printempw * @Last Modified by: g-plane
* @Last Modified time: 2017-01-22 20:45:06 * @Last Modified time: 2017-04-26 15:39:46
*/ */
'use strict'; 'use strict';
@ -35,6 +35,7 @@ var vendorScripts = [
'toastr/toastr.min.js', 'toastr/toastr.min.js',
'es6-promise/es6-promise.auto.min.js', 'es6-promise/es6-promise.auto.min.js',
'sweetalert2/dist/sweetalert2.min.js', 'sweetalert2/dist/sweetalert2.min.js',
'jqPaginator/dist/jqPaginator.min.js',
'resources/assets/dist/scripts/general.js', 'resources/assets/dist/scripts/general.js',
]; ];

View File

@ -1,16 +1,39 @@
/* /*
* @Author: printempw * @Author: printempw
* @Date: 2016-07-22 14:02:44 * @Date: 2016-07-22 14:02:44
* @Last Modified by: printempw * @Last Modified by: g-plane
* @Last Modified time: 2017-01-21 10:58:50 * @Last Modified time: 2017-04-28 19:54:02
*/ */
'use strict'; 'use strict';
let pluginsTable;
$(document).ready(function() { $(document).ready(function() {
$('input').iCheck({ $('input').iCheck({
checkboxClass: 'icheckbox_square-blue' checkboxClass: 'icheckbox_square-blue'
}); });
swal.setDefaults({
confirmButtonText: trans('general.confirm'),
cancelButtonText: trans('general.cancel')
});
$.extend(true, $.fn.dataTable.defaults, {
language: trans('vendor.datatables'),
scrollX: true,
pageLength: 25,
autoWidth: false,
processing: true,
serverSide: true
});
if (window.location.href.indexOf(url('admin/users')) >= 0) {
initUsersTable();
} else if (window.location.href.indexOf(url('admin/players')) >= 0) {
initPlayersTable();
} else if (window.location.href.indexOf(url('admin/plugins/manage')) >= 0) {
pluginsTable = initPluginsTable();
}
}); });
$('#layout-skins-list [data-skin]').click(function(e) { $('#layout-skins-list [data-skin]').click(function(e) {
@ -37,67 +60,75 @@ $('#color-submit').click(function() {
}); });
function changeUserEmail(uid) { function changeUserEmail(uid) {
var email = prompt(trans('admin.newUserEmail')); let dom = $(`tr#user-${uid} > td:nth-child(2)`);
swal({
if (!email) return; text: trans('admin.newUserEmail'),
showCancelButton: true,
$.ajax({ input: 'text',
type: "POST", inputValue: dom.text()
url: "./users?action=email", }).then(email => {
dataType: "json", $.ajax({
data: { 'uid': uid, 'email': email }, type: "POST",
success: function(json) { url: "./users?action=email",
if (json.errno == 0) { dataType: "json",
$($('tr#'+uid+' > td')[1]).html(email); data: { 'uid': uid, 'email': email },
toastr.success(json.msg); success: json => {
} else { if (json.errno == 0) {
toastr.warning(json.msg); dom.text(email);
} toastr.success(json.msg);
}, } else {
error: showAjaxError toastr.warning(json.msg);
}
},
error: showAjaxError
});
}); });
} }
function changeUserNickName(uid) { function changeUserNickName(uid) {
var nickname = prompt(trans('admin.newUserNickname')); let dom = $(`tr#user-${uid} > td:nth-child(3)`);
swal({
if (!nickname) return; text: trans('admin.newUserNickname'),
showCancelButton: true,
$.ajax({ input: 'text',
type: "POST", inputValue: dom.text()
url: "./users?action=nickname", }).then(nickname => {
dataType: "json", $.ajax({
data: { 'uid': uid, 'nickname': nickname }, type: "POST",
success: function(json) { url: "./users?action=nickname",
if (json.errno == 0) { dataType: "json",
$($('tr#'+uid+' > td')[2]).html(nickname); data: { 'uid': uid, 'nickname': nickname },
toastr.success(json.msg); success: json => {
} else { if (json.errno == 0) {
toastr.warning(json.msg); dom.text(nickname);
} toastr.success(json.msg);
}, } else {
error: showAjaxError toastr.warning(json.msg);
}
},
error: showAjaxError
});
}); });
} }
function changeUserPwd(uid) { function changeUserPwd(uid) {
var password = prompt(trans('admin.newUserPassword')); swal({
text: trans('admin.newUserPassword'),
if (!password) return; showCancelButton: true,
input: 'password',
$.ajax({ }).then(password => {
type: "POST", return Promise.resolve($.ajax({
url: "./users?action=password", type: "POST",
dataType: "json", url: "./users?action=password",
data: { 'uid': uid, 'password': password }, dataType: "json",
success: function(json) { data: { 'uid': uid, 'password': password }
if (json.errno == 0) }));
toastr.success(json.msg); }).then(json => {
else if (json.errno == 0)
toastr.warning(json.msg); toastr.success(json.msg);
}, else
error: showAjaxError toastr.warning(json.msg);
}); }).catch(error => showAjaxError);
} }
function changeUserScore(uid, score) { function changeUserScore(uid, score) {
@ -126,12 +157,16 @@ function changeBanStatus(uid) {
data: { 'uid': uid }, data: { 'uid': uid },
success: function(json) { success: function(json) {
if (json.errno == 0) { if (json.errno == 0) {
var object = $('#'+uid).find('a#ban'); let dom = $(`#ban-${uid}`);
var dom = '<a id="ban" href="javascript:changeBanStatus('+uid+');">' + if (dom.attr('data') == 'banned') {
(object.text() == trans('admin.ban') ? trans('admin.unban') : trans('admin.ban')) + '</a>'; dom.text(trans('admin.ban'));
object.html(dom); dom.attr('data', 'normal');
} else {
dom.text(trans('admin.unban'));
dom.attr('data', 'banned');
}
$('#'+uid).find('#permission').text(json.permission == '-1' ? trans('admin.banned') : trans('admin.normal')); $(`#user-${uid} > td:nth-child(5)`).text(json.permission == -1 ? trans('admin.banned') : trans('admin.normal'));
toastr.success(json.msg); toastr.success(json.msg);
} else { } else {
toastr.warning(json.msg); toastr.warning(json.msg);
@ -149,12 +184,16 @@ function changeAdminStatus(uid) {
data: { 'uid': uid }, data: { 'uid': uid },
success: function(json) { success: function(json) {
if (json.errno == 0) { if (json.errno == 0) {
var object = $('#'+uid).find('a#admin'); let dom = $(`#admin-${uid}`);
var dom = '<a href="javascript:changeAdminStatus('+uid+');">' + if (dom.attr('data') == 'admin') {
(object.text() == trans('admin.setAdmin') ? trans('admin.unsetAdmin') : trans('admin.setAdmin')) + '</a>'; dom.text(trans('admin.setAdmin'));
object.html(dom); dom.attr('data', 'normal');
} else {
dom.text(trans('admin.unsetAdmin'));
dom.attr('data', 'admin');
}
$('#'+uid).find('#permission').text(json.permission == '1' ? trans('admin.admin') : trans('admin.normal')); $(`#user-${uid} > td:nth-child(5)`).text(json.permission == 1 ? trans('admin.admin') : trans('admin.normal'));
toastr.success(json.msg); toastr.success(json.msg);
} else { } else {
toastr.warning(json.msg); toastr.warning(json.msg);
@ -165,23 +204,25 @@ function changeAdminStatus(uid) {
} }
function deleteUserAccount(uid) { function deleteUserAccount(uid) {
if (!window.confirm(trans('admin.deleteUserNotice'))) return; swal({
text: trans('admin.deleteUserNotice'),
$.ajax({ type: 'warning',
type: "POST", showCancelButton: true
url: "./users?action=delete", }).then(() => {
dataType: "json", return Promise.resolve($.ajax({
data: { 'uid': uid }, type: "POST",
success: function(json) { url: "./users?action=delete",
if (json.errno == 0) { dataType: "json",
$('tr#'+uid).remove(); data: { 'uid': uid }
toastr.success(json.msg); }))
} else { }).then(json => {
toastr.warning(json.msg); if (json.errno == 0) {
} $('tr#user-' + uid).remove();
}, toastr.success(json.msg);
error: showAjaxError } else {
}); toastr.warning(json.msg);
}
}).catch(error => showAjaxError);
} }
$('body').on('keypress', '.score', function(event){ $('body').on('keypress', '.score', function(event){
@ -191,7 +232,7 @@ $('body').on('keypress', '.score', function(event){
} }
}); });
$('body').on('change', '#preference', function() { function changePreference() {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "./players?action=preference", url: "./players?action=preference",
@ -206,9 +247,9 @@ $('body').on('change', '#preference', function() {
}, },
error: showAjaxError error: showAjaxError
}); });
}); }
function changeTexture(pid) { function changeTexture(pid, playerName) {
let dom = ` let dom = `
<div class="form-group"> <div class="form-group">
<label for="model">${trans('admin.textureType')}</label> <label for="model">${trans('admin.textureType')}</label>
@ -223,8 +264,6 @@ function changeTexture(pid) {
<input id="tid" class="form-control" type="text" placeholder="${trans('admin.pidNotice')}"> <input id="tid" class="form-control" type="text" placeholder="${trans('admin.pidNotice')}">
</div>`; </div>`;
let playerName = $('#'+pid).find('#player-name').text();
showModal(dom, trans('admin.changePlayerTexture', {'player': playerName}), 'default', { showModal(dom, trans('admin.changePlayerTexture', {'player': playerName}), 'default', {
callback: `ajaxChangeTexture(${pid})` callback: `ajaxChangeTexture(${pid})`
}); });
@ -259,46 +298,106 @@ function ajaxChangeTexture(pid) {
}); });
} }
function changePlayerName(pid, oldName) {
let dom = $(`tr#${pid} > td:nth-child(3)`);
swal({
text: trans('admin.changePlayerNameNotice'),
input: 'text',
inputValue: oldName,
inputValidator: name => {
return new Promise((resolve, reject) => {
if (name) {
resolve();
} else {
reject(trans('admin.emptyPlayerName'));
}
})
}
}).then(name => {
return Promise.resolve($.ajax({
type: 'POST',
url: './players?action=name',
dataType: 'json',
data: { pid: pid, name: name }
}));
}).then(json => {
if (json.errno == 0) {
dom.text(json.name);
toastr.success(json.msg);
} else {
toastr.warning(json.msg);
}
}).catch(error => showAjaxError);
}
function changeOwner(pid) { function changeOwner(pid) {
var uid = prompt(trans('admin.changePlayerOwner')); let dom = $(`#${pid} > td:nth-child(2)`);
swal({
if (!uid) return; html: `${trans('admin.changePlayerOwner')}<br><small>&nbsp;</small>`,
input: 'number',
$.ajax({ inputValue: dom.text(),
type: "POST", showCancelButton: true
url: "./players?action=owner", }).then(uid => {
dataType: "json", $.ajax({
data: { 'pid': pid, 'uid': uid }, type: "POST",
success: function(json) { url: "./players?action=owner",
if (json.errno == 0) { dataType: "json",
$($('#'+pid).children()[1]).text(uid); data: { 'pid': pid, 'uid': uid },
toastr.success(json.msg); success: function (json) {
} else { if (json.errno == 0) {
toastr.warning(json.msg); dom.text(uid);
} toastr.success(json.msg);
}, } else {
error: showAjaxError toastr.warning(json.msg);
}
},
error: showAjaxError
});
}); });
$('.swal2-input').on('input', debounce(() => {
const uid = $('.swal2-input').val();
if (uid > 0) {
Promise.resolve($.ajax({
type: 'GET',
url: `./user/${uid}`,
dataType: 'json'
})).then(result => {
$('#swal2-content').html(
`${trans('admin.changePlayerOwner')}<br>
<small>${trans('admin.targetUser', { nickname: result.user.nickname })}</small>`
);
}).catch(() => {
$('#swal2-content').html(`${trans('admin.changePlayerOwner')}<br><small>${trans('admin.noSuchUser')}</small>`);
});
}
}, 350));
} }
function deletePlayer(pid) { function deletePlayer(pid) {
if (!window.confirm(trans('admin.deletePlayerNotice'))) return; swal({
text: trans('admin.deletePlayerNotice'),
type: 'warning',
showCancelButton: true
}).then(() => {
return Promise.resolve($.ajax({
type: "POST",
url: "./players?action=delete",
dataType: "json",
data: { 'pid': pid },
success: function (json) {
$.ajax({ },
type: "POST", error: showAjaxError
url: "./players?action=delete", }))
dataType: "json", }).then(json => {
data: { 'pid': pid }, if (json.errno == 0) {
success: function(json) { $('tr#' + pid).remove();
if (json.errno == 0) { toastr.success(json.msg);
$('tr#'+pid).remove(); } else {
toastr.success(json.msg); toastr.warning(json.msg);
} else { }
toastr.warning(json.msg); }).catch(error => showAjaxError);
}
},
error: showAjaxError
});
} }
function enablePlugin(name) { function enablePlugin(name) {
@ -310,7 +409,7 @@ function enablePlugin(name) {
if (json.errno == 0) { if (json.errno == 0) {
toastr.success(json.msg); toastr.success(json.msg);
table.ajax.reload(null, false); pluginsTable.ajax.reload(null, false);
} else { } else {
toastr.warning(json.msg); toastr.warning(json.msg);
} }
@ -328,7 +427,7 @@ function disablePlugin(name) {
if (json.errno == 0) { if (json.errno == 0) {
toastr.warning(json.msg); toastr.warning(json.msg);
table.ajax.reload(null, false); pluginsTable.ajax.reload(null, false);
} else { } else {
toastr.warning(json.msg); toastr.warning(json.msg);
} }
@ -351,7 +450,7 @@ function deletePlugin(name) {
if (json.errno == 0) { if (json.errno == 0) {
toastr.success(json.msg); toastr.success(json.msg);
$('tr[id=plugin-'+name+']').remove(); pluginsTable.ajax.reload(null, false);
} else { } else {
toastr.warning(json.msg); toastr.warning(json.msg);
} }
@ -453,3 +552,273 @@ function downloadUpdates() {
.fail(showAjaxError); .fail(showAjaxError);
} }
function initUsersTable() {
let dataUrl = url('admin/user-data');
if (getQueryString('uid')) {
dataUrl += '?uid=' + getQueryString('uid');
}
$('#user-table').DataTable({
ajax: dataUrl,
scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7,
rowCallback: (row, data) => {
$(row).attr('id', `user-${data.uid}`);
},
columnDefs: [
{
targets: 0,
data: 'uid',
width: '1%'
},
{
targets: 1,
data: 'email'
},
{
targets: 2,
data: 'nickname'
},
{
targets: 3,
data: 'score',
render: data => {
return `<input type="number" class="form-control score" value="${data}" title="${trans('admin.scoreTip')}" data-toggle="tooltip" data-placement="right">`;
}
},
{
targets: 4,
data: 'players_count',
render: (data, type, row) => {
return `<span title="${trans('admin.doubleClickToSeePlayers')}"
style="cursor: pointer;"
ondblclick="window.location.href = '${url('admin/players?uid=') + row.uid}'"
data-toggle="tooltip" data-placement="top">${data}</span>`;
}
},
{
targets: 5,
data: 'permission',
render: data => {
switch (data) {
case -1:
return trans('admin.banned');
case 0:
return trans('admin.normal');
case 1:
return trans('admin.admin');
case 2:
return trans('admin.superAdmin');
}
}
},
{
targets: 6,
data: 'register_at'
},
{
targets: 7,
data: 'operations',
searchable: false,
orderable: false,
render: (data, type, row) => {
let operationsHtml, adminOption = '', bannedOption = '', deleteUserButton;
if (row.permission !== 2) {
if (data === 2) {
if (row.permission === 1) {
adminOption = `<li class="divider"></li>
<li><a id="admin-${row.uid}" data="admin" href="javascript:changeAdminStatus(${row.uid});">${trans('admin.unsetAdmin')}</a></li>`;
} else {
adminOption = `<li class="divider"></li>
<li><a id="admin-${row.uid}" data="normal" href="javascript:changeAdminStatus(${row.uid});">${trans('admin.setAdmin')}</a></li>`;
}
}
if (row.permission === -1) {
bannedOption = `<li class="divider"></li>
<li><a id="ban-${row.uid}" data="banned" href="javascript:changeBanStatus(${row.uid});">${trans('admin.unban')}</a></li>`;
} else {
bannedOption = `<li class="divider"></li>
<li><a id="ban-${row.uid}" data="normal" href="javascript:changeBanStatus(${row.uid});">${trans('admin.ban')}</a></li>`;
}
}
if (data === 2) {
if (row.permission === 2) {
deleteUserButton = `
<a class="btn btn-danger btn-sm" disabled="disabled" data-toggle="tooltip" data-placement="bottom" title="${trans('admin.cannotDeleteSuperAdmin')}">${trans('admin.deleteUser')}</a>`;
} else {
deleteUserButton = `
<a class="btn btn-danger btn-sm" href="javascript:deleteUserAccount(${row.uid});">${trans('admin.deleteUser')}</a>`;
}
} else {
if (row.permission === 1 || row.permission === 2) {
deleteUserButton = `
<a class="btn btn-danger btn-sm" disabled="disabled" data-toggle="tooltip" data-placement="bottom" title="${trans('admin.cannotDeleteAdmin')}">${trans('admin.deleteUser')}</a>`;
} else {
deleteUserButton = `
<a class="btn btn-danger btn-sm" href="javascript:deleteUserAccount(${row.uid});">${trans('admin.deleteUser')}</a>`;
}
}
return `
<div class="btn-group">
<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
${trans('admin.operationsTitle')} <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="javascript:changeUserEmail(${row.uid});">${trans('admin.changeEmail')}</a></li>
<li><a href="javascript:changeUserNickName(${row.uid});">${trans('admin.changeNickName')}</a></li>
<li><a href="javascript:changeUserPwd(${row.uid});">${trans('admin.changePassword')}</a></li>
${adminOption}${bannedOption}
</ul>
</div>
${deleteUserButton}`;
}
}
]
});
}
function initPlayersTable() {
let dataUrl = url('admin/player-data');
if (getQueryString('uid')) {
dataUrl += '?uid=' + getQueryString('uid');
}
$('#player-table').DataTable({
ajax: dataUrl,
scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7,
columnDefs: [
{
targets: 0,
data: 'pid',
width: '1%'
},
{
targets: 1,
data: 'uid',
render: (data, type, row) => {
return `<span title="${trans('admin.doubleClickToSeeUser')}"
style="cursor: pointer;"
ondblclick="window.location.href = '${url('admin/users?uid=') + row.uid}'"
data-toggle="tooltip" data-placement="top">${data}</span>`;
}
},
{
targets: 2,
data: 'player_name'
},
{
targets: 3,
data: 'preference',
render: data => {
return `
<select class="form-control" onchange="changePreference.call(this)">
<option ${(data == "default") ? 'selected=selected' : ''} value="default">Default</option>
<option ${(data == "slim") ? 'selected=selected' : ''} value="slim">Slim</option>
</select>`;
}
},
{
targets: 4,
searchable: false,
orderable: false,
render: (data, type, row) => {
let html = { steve: '', alex: '', cape: '' };
['steve', 'alex', 'cape'].forEach(textureType => {
if (row['tid_' + textureType] === 0) {
html[textureType] = `<img id="${row.pid}-${row['tid_' + textureType]}" width="64" />`;
} else {
html[textureType] = `
<a href="${url('/')}skinlib/show/${row['tid_' + textureType]}">
<img id="${row.pid}-${row['tid_' + textureType]}" width="64" src="${url('/')}preview/64/${row['tid_' + textureType]}.png" />
</a>`;
}
});
return html.steve + html.alex + html.cape;
}
},
{
targets: 5,
data: 'last_modified'
},
{
targets: 6,
searchable: false,
orderable: false,
render: (data, type, row) => {
return `
<div class="btn-group">
<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
${trans('admin.operationsTitle')} <span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="javascript:changeTexture(${row.pid}, '${row.player_name}');">${trans('admin.changeTexture')}</a></li>
<li><a href="javascript:changePlayerName(${row.pid}, '${row.player_name}');">${trans('admin.changePlayerName')}</a></li>
<li><a href="javascript:changeOwner(${row.pid});">${trans('admin.changeOwner')}</a></li>
</ul>
</div>
<a class="btn btn-danger btn-sm" href="javascript:deletePlayer(${row.pid});">${trans('admin.deletePlayer')}</a>`;
}
}
]
});
}
function initPluginsTable() {
return $('#plugin-table').DataTable({
ajax: url('admin/plugins/data'),
columnDefs: [
{
targets: 0,
data: 'title'
},
{
targets: 1,
data: 'description',
width: '35%'
},
{
targets: 2,
data: 'author',
render: data => {
if (data.url === '' || data.url === null) {
return data.author;
} else {
return `<a href="${data.url}" target="_blank">${data.author}</a>`;
}
}
},
{
targets: 3,
data: 'version'
},
{
targets: 4,
data: 'status'
},
{
targets: 5,
data: 'operations',
searchable: false,
orderable: false,
render: (data, type, row) => {
let switchEnableButton, configViewButton, deletePluginButton;
if (data.enabled) {
switchEnableButton = `
<a class="btn btn-warning btn-sm" href="javascript:disablePlugin('${row.name}');">${trans('admin.disablePlugin')}</a>`;
} else {
switchEnableButton = `
<a class="btn btn-primary btn-sm" href="javascript:enablePlugin('${row.name}');">${trans('admin.enablePlugin')}</a>`;
}
if (data.enabled && data.hasConfigView) {
configViewButton = `
<a class="btn btn-default btn-sm" href="${url('/')}admin/plugins/config/${row.name}">${trans('admin.configurePlugin')}</a>`;
} else {
configViewButton = `
<a class="btn btn-default btn-sm" disabled="disabled" title="${trans('admin.noPluginConfigNotice')}" data-toggle="tooltip" data-placement="top">${trans('admin.configurePlugin')}</a>`;
}
deletePluginButton = `
<a class="btn btn-danger btn-sm" href="javascript:deletePlugin('${row.name}');">${trans('admin.deletePlugin')}</a>`;
return switchEnableButton + configViewButton + deletePluginButton;
}
}
]
});
}

View File

@ -1,8 +1,8 @@
/* /*
* @Author: printempw * @Author: printempw
* @Date: 2016-09-15 10:39:41 * @Date: 2016-09-15 10:39:41
* @Last Modified by: printempw * @Last Modified by: g-plane
* @Last Modified time: 2017-01-22 18:51:51 * @Last Modified time: 2017-04-27 15:33:24
*/ */
'use strict'; 'use strict';
@ -88,7 +88,7 @@ function trans(key, parameters = {}) {
return temp; return temp;
} }
function showModal(msg, title = 'Messgae', type = 'default', options = {}) { function showModal(msg, title = 'Message', type = 'default', options = {}) {
let btnType = (type != "default") ? "btn-outline" : "btn-primary"; let btnType = (type != "default") ? "btn-outline" : "btn-primary";
let onClick = (options.callback === undefined) ? 'data-dismiss="modal"' : `onclick="${options.callback}"`; let onClick = (options.callback === undefined) ? 'data-dismiss="modal"' : `onclick="${options.callback}"`;
@ -157,6 +157,28 @@ function getQueryString(key) {
} }
} }
/**
* Return a debounced function
*
* @param {Function} func
* @param {number} delay
* @param {Array} args
* @param {Object} context
*/
function debounce(func, delay, args = [], context = undefined) {
if (isNaN(delay) || typeof func !== 'function') {
throw new Error('Arguments type of function "debounce" is incorrent!');
}
let timer = null;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
}
}
// polyfill of String.prototype.endsWith // polyfill of String.prototype.endsWith
if (!String.prototype.endsWith) { if (!String.prototype.endsWith) {
String.prototype.endsWith = function (searchString, position) { String.prototype.endsWith = function (searchString, position) {
@ -200,18 +222,11 @@ function confirmLogout() {
} }
function logout() { function logout() {
return new Promise((resolve, reject) => { return Promise.resolve($.ajax({
$.ajax({ type: "POST",
type: "POST", url: url('auth/logout'),
url: url('auth/logout'), dataType: "json"
dataType: "json", }));
success: (json) => resolve(json),
error: (json) => {
showAjaxError(json);
reject(json);
}
});
});
} }
$('#logout-button').click(() => confirmLogout()); $('#logout-button').click(() => confirmLogout());
@ -237,7 +252,7 @@ var TexturePreview = function (type, tid, preference) {
this.change3dPreview = function () { this.change3dPreview = function () {
if (this.playerPreference == this.preference) { if (this.playerPreference == this.preference || this.type == 'cape') {
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: url(`skinlib/info/${this.tid}`), url: url(`skinlib/info/${this.tid}`),

View File

@ -1,8 +1,8 @@
/* /*
* @Author: printempw * @Author: printempw
* @Date: 2016-07-19 10:46:38 * @Date: 2016-07-19 10:46:38
* @Last Modified by: printempw * @Last Modified by: g-plane
* @Last Modified time: 2017-01-22 15:57:57 * @Last Modified time: 2017-04-25 21:56:19
*/ */
'use strict'; 'use strict';
@ -158,8 +158,9 @@ function handleFiles(files, type) {
(type == "skin") ? MSP.changeSkin(img.src) : MSP.changeCape(img.src); (type == "skin") ? MSP.changeSkin(img.src) : MSP.changeCape(img.src);
let domTextureName = $('#name'); let domTextureName = $('#name');
if (domTextureName.val() === '' || domTextureName.val() === domTextureName.attr('data-last-file-name')) { if (domTextureName.val() === '' || domTextureName.val() === domTextureName.attr('data-last-file-name')) {
domTextureName.attr('data-last-file-name', file.name); const fileName = file.name.replace(/\.[Pp][Nn][Gg]$/, '');
domTextureName.val(file.name); domTextureName.attr('data-last-file-name', fileName);
domTextureName.val(fileName);
} }
}; };
img.onerror = () => toastr.warning(trans('skinlib.fileExtError')); img.onerror = () => toastr.warning(trans('skinlib.fileExtError'));
@ -243,10 +244,11 @@ function upload() {
return false; return false;
} }
function changeTextureName(tid) { function changeTextureName(tid, oldName) {
swal({ swal({
text: trans('skinlib.setNewTextureName'), text: trans('skinlib.setNewTextureName'),
input: 'text', input: 'text',
inputValue: oldName,
showCancelButton: true, showCancelButton: true,
inputValidator: (value) => { inputValidator: (value) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@ -1,8 +1,8 @@
/* /*
* @Author: printempw * @Author: printempw
* @Date: 2016-07-16 10:02:24 * @Date: 2016-07-16 10:02:24
* @Last Modified by: printempw * @Last Modified by: g-plane
* @Last Modified time: 2017-01-20 21:19:07 * @Last Modified time: 2017-04-27 16:37:05
*/ */
'use strict'; 'use strict';
@ -18,13 +18,13 @@ $('body').on('click', '#preview-switch', () => {
TexturePreview.previewType == '3D' ? TexturePreview.show2dPreview() : TexturePreview.show3dPreview(); TexturePreview.previewType == '3D' ? TexturePreview.show2dPreview() : TexturePreview.show3dPreview();
}); });
var selected = []; let selectedTextures = [];
$('body').on('click', '.item-body', function () { $('body').on('click', '.item-body', function () {
$('.item-selected').parent().removeClass('item-selected'); $('.item-selected').parent().removeClass('item-selected');
$(this).parent().addClass('item-selected'); $(this).parent().addClass('item-selected');
let tid = $(this).parent().attr('tid'); const tid = parseInt($(this).parent().attr('tid'));
$.ajax({ $.ajax({
type: "POST", type: "POST",
@ -33,24 +33,94 @@ $('body').on('click', '.item-body', function () {
success: (json) => { success: (json) => {
if (json.type == "cape") { if (json.type == "cape") {
MSP.changeCape('../textures/' + json.hash); MSP.changeCape('../textures/' + json.hash);
selected['cape'] = tid; selectedTextures['cape'] = tid;
} else { } else {
MSP.changeSkin('../textures/' + json.hash); MSP.changeSkin('../textures/' + json.hash);
selected['skin'] = tid; selectedTextures['skin'] = tid;
} }
selected.length = 0; if (selectedTextures['skin'] !== undefined && selectedTextures['cape'] !== undefined)
$('#textures-indicator').text(`${trans('general.skin')} & ${trans('general.cape')}`);
['skin', 'cape'].forEach((key) => { else if (selectedTextures['skin'] != undefined)
if (selected[key] !== undefined) selected.length++; $('#textures-indicator').text(trans('general.skin'));
else if (selectedTextures['cape'] != undefined)
$('#textures-indicator').html(selected.length); $('#textures-indicator').text(trans('general.cape'));
});
}, },
error: showAjaxError error: showAjaxError
}); });
}); });
$('body').on('click', '.category-switch', () => {
const category = $('a[href="#skin-category"]').parent().hasClass('active') ? 'cape' : 'skin';
const page = parseInt($('#closet-paginator').attr(`last-${category}-page`));
const search = $('input[name=q]').val();
reloadCloset(category, page, search);
});
function renderClosetItemComponent(item) {
return `
<div class="item" tid="${item.tid}">
<div class="item-body">
<img src="${url('/')}preview/${item.tid}.png">
</div>
<div class="item-footer">
<p class="texture-name">
<span title="${item.name}">${item.name} <small>(${item.type})</small></span>
</p>
<a href="${url('/')}skinlib/show/${item.tid}" title="${trans('user.viewInSkinlib')}" class="more" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-share"></i></a>
<span title="${trans('general.more')}" class="more" data-toggle="dropdown" aria-haspopup="true" id="more-button"><i class="fa fa-cog"></i></span>
<ul class="dropup dropdown-menu" aria-labelledby="more-button">
<li><a href="javascript:renameClosetItem(${item.tid}, '${item.name}');">${trans('user.renameItem')}</a></li>
<li><a href="javascript:removeFromCloset(${item.tid});">${trans('user.removeItem')}</a></li>
<li><a href="javascript:setAsAvatar(${item.tid});">${trans('user.setAsAvatar')}</a></li>
</ul>
</div>
</div>`;
}
function renderCloset(items, category) {
const search = $('input[name=q]').val();
let container = $(`#${category}-category`);
container.html('');
if (items.length === 0) {
$('#closet-paginator').hide();
if (search === '') {
container.html(`<div class="empty-msg">
${trans('user.emptyClosetMsg', { url: url('skinlib?filter=' + category) })}</div>`);
} else {
container.html(`<div class="empty-msg">${trans('general.noResult')}</div>`);
}
} else {
$('#closet-paginator').show();
for (const item of items) {
container.append(renderClosetItemComponent(item));
}
}
}
function reloadCloset(category, page, search) {
Promise.resolve($.ajax({
type: 'GET',
url: url('user/closet-data'),
dataType: 'json',
data: {
category: category,
page: page,
q: search
}
})).then(result => {
renderCloset(result.items, result.category);
let paginator = $('#closet-paginator');
paginator.attr(`last-${result.category}-page`, page);
paginator.jqPaginator('option', {
currentPage: page,
totalPages: result.total_pages
});
}).catch(error => showAjaxError);
}
function showPlayerTexturePreview(pid) { function showPlayerTexturePreview(pid) {
$.ajax({ $.ajax({
type: "POST", type: "POST",
@ -81,10 +151,11 @@ function showPlayerTexturePreview(pid) {
}); });
} }
function renameClosetItem(tid) { function renameClosetItem(tid, oldName) {
swal({ swal({
title: trans('user.renameClosetItem'), title: trans('user.renameClosetItem'),
input: 'text', input: 'text',
inputValue: oldName,
showCancelButton: true, showCancelButton: true,
inputValidator: function(value) { inputValidator: function(value) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
@ -133,6 +204,14 @@ function removeFromCloset(tid) {
}); });
$('div[tid='+tid+']').remove(); $('div[tid='+tid+']').remove();
['skin', 'cape'].forEach(type => {
let container = $(`#${type}-category`);
if ($.trim(container.html()) == '') {
container.html(`<div class="empty-msg">
${trans('user.emptyClosetMsg', { url: url('skinlib?filter=' + type) })}</div>`);
}
})
} else { } else {
toastr.warning(json.msg); toastr.warning(json.msg);
} }
@ -178,6 +257,43 @@ $(document).ready(function() {
confirmButtonText: trans('general.confirm'), confirmButtonText: trans('general.confirm'),
cancelButtonText: trans('general.cancel') cancelButtonText: trans('general.cancel')
}); });
if (window.location.pathname.includes('/user/closet')) {
Promise.resolve($.ajax({
type: 'GET',
url: /(^https?.*)\/user\/closet/.exec(window.location.href)[1] + '/user/closet-data',
dataType: 'json'
})).then(result => {
renderCloset(result.items, result.category);
$('#closet-paginator').jqPaginator({
totalPages: result.total_pages,
visiblePages: 5,
currentPage: 1,
first: '<li><a style="cursor: pointer;">«</a></li>',
prev: '<li><a style="cursor: pointer;"></a></li>',
next: '<li><a style="cursor: pointer;"></a></li>',
last: '<li><a style="cursor: pointer;">»</a></li>',
page: '<li><a style="cursor: pointer;">{{page}}</a></li>',
wrapper: '<ul class="pagination pagination-sm no-margin"></ul>',
onPageChange: page => {
reloadCloset(
$('#skin-category').hasClass('active') ? 'skin' : 'cape',
page,
$('input[name=q]').val()
);
}
});
}).catch(error => showAjaxError);
$('input[name=q]').on('input', debounce(() => {
const category = $('#skin-category').hasClass('active') ? 'skin' : 'cape';
reloadCloset(
category,
1,
$('input[name=q]').val()
);
}, 350));
}
}); });
function setTexture() { function setTexture() {
@ -189,7 +305,7 @@ function setTexture() {
if (!pid) { if (!pid) {
toastr.info(trans('user.emptySelectedPlayer')); toastr.info(trans('user.emptySelectedPlayer'));
} else if (selected.length == 0) { } else if (selectedTextures['skin'] == undefined && selectedTextures['cape'] == undefined) {
toastr.info(trans('user.emptySelectedTexture')); toastr.info(trans('user.emptySelectedTexture'));
} else { } else {
$.ajax({ $.ajax({
@ -198,8 +314,8 @@ function setTexture() {
dataType: "json", dataType: "json",
data: { data: {
'pid': pid, 'pid': pid,
'tid[skin]': selected['skin'], 'tid[skin]': selectedTextures['skin'],
'tid[cape]': selected['cape'] 'tid[cape]': selectedTextures['cape']
}, },
success: function(json) { success: function(json) {
if (json.errno == 0) { if (json.errno == 0) {
@ -238,7 +354,7 @@ $('body').on('change', '#preference', function() {
function changePlayerName(pid, current_player_name) { function changePlayerName(pid, current_player_name) {
swal({ swal({
title: trans('user.changePlayerName'), title: trans('user.changePlayerName'),
text: trans('user.playerNameRule'), text: $('#player_name').attr('placeholder'),
inputValue: current_player_name, inputValue: current_player_name,
input: 'text', input: 'text',
showCancelButton: true, showCancelButton: true,
@ -277,32 +393,49 @@ function changePlayerName(pid, current_player_name) {
} }
function clearTexture(pid) { function clearTexture(pid) {
swal({ let dom = `
text: trans('user.clearTexture'), <div class="form-group">
type: 'warning', <input type="checkbox" id="clear-steve"> Default (Steve)
showCancelButton: true </div>
}).then(function() { <div class="form-group">
$.ajax({ <input type="checkbox" id="clear-alex"> Slim (Alex)
type: "POST", </div>
url: "./player/texture/clear", <div class="form-group">
dataType: "json", <input type="checkbox" id="clear-cape"> ${trans('general.cape')}
data: { 'pid' : pid }, </div>
success: function(json) { <script>
if (json.errno == 0) { $('input[type=checkbox]').iCheck({ checkboxClass: 'icheckbox_square-blue' });
swal({ </script>
type: 'success', `;
html: json.msg showModal(dom, trans('user.chooseClearTexture'), 'default', { callback: `ajaxClearTexture(${pid})` });
}); return;
} else { }
swal({
type: 'error', function ajaxClearTexture(pid) {
html: json.msg $('.modal').each(function () {
}); if ($(this).css('display') == "none")
} $(this).remove();
},
error: showAjaxError
});
}); });
let data = { pid: pid };
['steve', 'alex', 'cape'].forEach(type => {
data[type] = $(`#clear-${type}`).prop('checked') ? 1 : 0;
});
if (data['steve'] == 0 && data['alex'] == 0 && data['cape'] == 0) {
toastr.warning(trans('user.noClearChoice'));
return;
}
Promise.resolve($.ajax({
type: 'POST',
url: './player/texture/clear',
dataType: 'json',
data: data
})).then(json => {
swal({ type: json.errno == 0 ? 'success' : 'error', html: json.msg });
$('.modal').modal('hide');
}).catch(error => showAjaxError);
} }
function deletePlayer(pid) { function deletePlayer(pid) {
@ -405,49 +538,46 @@ function changeNickName() {
} }
function changePassword() { function changePassword() {
let domOldPwd = $('#password');
let domNewPwd = $('#new-passwd');
let domConfirmPwd = $('#confirm-pwd');
var password = $('#password').val(); let password = domOldPwd.val();
var new_passwd = $('#new-passwd').val(); let new_passwd = domNewPwd.val();
if (password == "") { if (password == "") {
toastr.info(trans('user.emptyPassword')); toastr.info(trans('user.emptyPassword'));
$('#passwd').focus(); domOldPwd.focus();
} else if (new_passwd == "") { } else if (new_passwd == "") {
toastr.info(trans('user.emptyNewPassword')); toastr.info(trans('user.emptyNewPassword'));
$('#new-passwd').focus(); domNewPwd.focus();
} else if ($('#confirm-pwd').val() == "") { } else if (domConfirmPwd.val() == "") {
toastr.info(trans('auth.emptyConfirmPwd')); toastr.info(trans('auth.emptyConfirmPwd'));
$('#confirm-pwd').focus(); domConfirmPwd.focus();
} else if (new_passwd != $('#confirm-pwd').val()) { } else if (new_passwd != domConfirmPwd.val()) {
toastr.warning(trans('auth.invalidConfirmPwd')); toastr.warning(trans('auth.invalidConfirmPwd'));
$('#confirm-pwd').focus(); domConfirmPwd.focus();
} else { } else {
$.ajax({ Promise.resolve($.ajax({
type: "POST", type: "POST",
url: "./profile?action=password", url: "./profile?action=password",
dataType: "json", dataType: "json",
data: { 'current_password': password, 'new_password': new_passwd}, data: { 'current_password': password, 'new_password': new_passwd }
success: function(json) { })).then(result => {
if (json.errno == 0) { if (result.errno == 0) {
swal({ return swal({ type: 'success', text: result.msg })
type: 'success', .then(() => {
html: json.msg return logout();
}).then(function() { }).then(result => {
logout(true, function() { if (result.errno == 0) {
window.location = "../auth/login"; window.location = url('auth/login');
}); }
}); }).catch(error => showAjaxError);
} else { } else {
swal({ return swal({ type: 'warning', text: result.msg });
type: 'warning', }
html: json.msg }).catch(error => showAjaxError);
});
}
},
error: showAjaxError
});
} }
return false;
} }
$('#new-email').focusin(function() { $('#new-email').focusin(function() {
@ -481,32 +611,27 @@ function changeEmail() {
text: trans('user.changeEmail', { new_email: new_email }), text: trans('user.changeEmail', { new_email: new_email }),
type: 'question', type: 'question',
showCancelButton: true showCancelButton: true
}).then(function() { }).then(() => {
$.ajax({ return Promise.resolve($.ajax({
type: "POST", type: 'POST',
url: "./profile?action=email", url: './profile?action=email',
dataType: "json", dataType: 'json',
data: { 'new_email' : new_email, 'password' : $('#current-password').val() }, data: { 'new_email': new_email, 'password': $('#current-password').val() }
success: function(json) { }));
if (json.errno == 0) { }).then(result => {
swal({ if (result.errno == 0) {
type: 'success', return swal({ type: 'success', text: result.msg })
html: json.msg .then(() => {
}).then(function() { return logout();
logout(true, function() { }).then(result => {
window.location = "../auth/login"; if (result.errno == 0) {
}); window.location = url('auth/login');
}); }
} else { }).catch(error => showAjaxError);
swal({ } else {
type: 'warning', return swal({ type: 'warning', text: result.msg });
html: json.msg }
}); }).catch(error => showAjaxError);
}
},
error: showAjaxError
});
});
} }
function deleteAccount() { function deleteAccount() {

View File

@ -6,19 +6,20 @@ index:
overview: Overview overview: Overview
users: users:
players-count:
title: Players Count
status: status:
title: Status title: Status
normal: Normal normal: Normal
banned: Banned banned: Banned
admin: Admin admin: Admin
super-admin: Super Admin super-admin: Super Admin
score:
tip: Press enter to submit new score
operations: operations:
title: Operations title: Operations
non-existent: No such user. non-existent: No such user.
email: email:
change: Edit Email change: Edit Email
existed: :email is existed.
success: Email changed successfully. success: Email changed successfully.
nickname: nickname:
change: Edit Nickname change: Edit Nickname
@ -61,6 +62,8 @@ players:
change: Change Textures change: Change Textures
non-existent: No such texture tid.:tid non-existent: No such texture tid.:tid
success: The textures of :player has been updated. success: The textures of :player has been updated.
name:
success: Player name has been updated to :player
owner: owner:
change: Change Owner change: Change Owner
success: The player :player was transferred to user :user. success: The player :player was transferred to user :user.
@ -100,12 +103,6 @@ plugins:
operations: operations:
title: Operations title: Operations
disable: Disable
enable: Enable
configure: Configure
no-config-notice: The plugin has been disabled or no configuration is provided.
delete: Delete
enabled: :plugin has been enabled. enabled: :plugin has been enabled.
disabled: :plugin has been disabled. disabled: :plugin has been disabled.
deleted: The plugin was deleted successfully. deleted: The plugin was deleted successfully.

View File

@ -62,12 +62,17 @@
setAsPublic: 'Set as Public', setAsPublic: 'Set as Public',
setPublicNotice: 'Sure to set this as public texture?', setPublicNotice: 'Sure to set this as public texture?',
deleteNotice: 'Are you sure to delete this texture? Scores will be returned.' deleteNotice: 'Are you sure to delete this texture?'
}, },
user: { user: {
signInRemainingTime: 'Available after :time hours', signInRemainingTime: 'Available after :time hours',
// Closet // Closet
emptyClosetMsg: '<p>Nothing in your closet...</p><p>Why not explore the <a href=":url">Skin Library</a> for a while?</p>',
renameItem: 'Rename item',
removeItem: 'Remove from closet',
setAsAvatar: 'Set as avatar',
viewInSkinlib: 'View in skin library',
switch2dPreview: 'Switch to 2D Preview', switch2dPreview: 'Switch to 2D Preview',
switch3dPreview: 'Switch to 3D Preview', switch3dPreview: 'Switch to 3D Preview',
removeFromClosetNotice: 'Sure to remove this texture from your closet?', removeFromClosetNotice: 'Sure to remove this texture from your closet?',
@ -77,11 +82,12 @@
// Player // Player
changePlayerName: 'Please enter the player name:', changePlayerName: 'Please enter the player name:',
playerNameRule: 'The player name should only contain letters, numbers, and dashes.',
emptyPlayerName: 'Empty player name.', emptyPlayerName: 'Empty player name.',
clearTexture: 'Sure to clear the skins & cape of this player?', clearTexture: 'Sure to clear the skins & cape of this player?',
deletePlayer: 'Sure to delete this player?', deletePlayer: 'Sure to delete this player?',
deletePlayerNotice: 'It\'s permanent. No backups.', deletePlayerNotice: 'It\'s permanent. No backups.',
chooseClearTexture: 'Choose texture types you want to clear',
noClearChoice: 'You haven\'t choose any types',
// Profile // Profile
setAvatar: 'Sure to set this as your avatar?', setAvatar: 'Sure to set this as your avatar?',
@ -95,38 +101,59 @@
emptyDeletePassword: 'Please enter the current password:' emptyDeletePassword: 'Please enter the current password:'
}, },
admin: { admin: {
// Change User Profile operationsTitle: 'Operations',
newUserEmail: 'Please enter the new email:',
newUserNickname: 'Please enter the new nickname:',
newUserPassword: 'Please enter the new password:',
deleteUserNotice: 'Are you sure to delete this user? It\' permanent.',
changePlayerOwner: 'Please enter the id of user which this player should be transferred to:',
deletePlayerNotice: 'Are you sure to delete this player? It\' permanent.',
// Status // Users
banned: 'Banned',
normal: 'Normal',
admin: 'Admin',
// Operations
ban: 'Ban', ban: 'Ban',
unban: 'Unban', unban: 'Unban',
setAdmin: 'Set as admin', setAdmin: 'Set as admin',
unsetAdmin: 'Remove admin', unsetAdmin: 'Remove admin',
deleteUser: 'Delete User',
cannotDeleteAdmin: 'You can\'t delete admins.',
cannotDeleteSuperAdmin: 'You can\'t delete super admin in this way',
changeEmail: 'Edit Email',
changeNickName: 'Edit Nickname',
changePassword: 'Edit Password',
newUserEmail: 'Please enter the new email:',
newUserNickname: 'Please enter the new nickname:',
newUserPassword: 'Please enter the new password:',
deleteUserNotice: 'Are you sure to delete this user? It\' permanent.',
scoreTip: 'Press ENTER to submit new score',
doubleClickToSeeUser: 'Double click to see info of this user',
doubleClickToSeePlayers: 'Double click to see his/her players',
// Change Player Texture // Status
banned: 'Banned',
normal: 'Normal',
admin: 'Admin',
superAdmin: 'Super Admin',
// Players
textureType: 'Texture Type', textureType: 'Texture Type',
skin: 'Skin (:model Model)', skin: 'Skin (:model Model)',
cape: 'Cape', cape: 'Cape',
pid: 'Texture ID', pid: 'Texture ID',
pidNotice: 'Please enter the tid of texture', pidNotice: 'Please enter the tid of texture. Inputting 0 can clear texture of this player.',
changePlayerTexture: 'Change textures of :player', changePlayerTexture: 'Change textures of :player',
changeTexture: 'Change Textures',
changePlayerName: 'Change Player Name',
changeOwner: 'Change Owner',
deletePlayer: 'Delete',
changePlayerOwner: 'Please enter the id of user which this player should be transferred to:',
deletePlayerNotice: 'Are you sure to delete this player? It\' permanent.',
targetUser: 'Target user is :nickname',
noSuchUser: 'No such user',
changePlayerNameNotice: 'Please input new player name:',
emptyPlayerName: 'Player name cannot be empty.',
// Index // Index
textureUploads: 'Texture Uploads', textureUploads: 'Texture Uploads',
userRegistration: 'User Registration', userRegistration: 'User Registration',
// Plugins // Plugins
configurePlugin: 'Configure',
noPluginConfigNotice: 'The plugin has been disabled or no configuration is provided.',
deletePlugin: 'Delete',
statusEnabled: 'Enabled', statusEnabled: 'Enabled',
statusDisabled: 'Disabled', statusDisabled: 'Disabled',
enablePlugin: 'Enable', enablePlugin: 'Enable',
@ -139,10 +166,14 @@
extracting: 'Extracting update package..' extracting: 'Extracting update package..'
}, },
general: { general: {
skin: 'Skin',
cape: 'Cape',
fatalError: 'Fatal Error (Please contact the author)', fatalError: 'Fatal Error (Please contact the author)',
confirmLogout: 'Sure to log out?', confirmLogout: 'Sure to log out?',
confirm: 'OK', confirm: 'OK',
cancel: 'Cancel' cancel: 'Cancel',
more: 'More',
noResult: 'No result.'
} }
}; };
})(window.jQuery); })(window.jQuery);

View File

@ -16,10 +16,11 @@ score-intro:
title: What is score? title: What is score?
introduction: | introduction: |
We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually. We use score system to prevent the behaviors like uplaoding huge amount of textures and registering players casually.
Both adding players and uplaoding textures will consume your score. The score will be returned if you deleted them. Both adding players and uplaoding textures will consume your score. :return-score
Adding textures from skin library to your closet will not decline your score.
The inital score of user on this site is :initial_score, you can acquire :score-from ~ :score-to scores by signing in. The inital score of user on this site is :initial_score, you can acquire :score-from ~ :score-to scores by signing in.
will-return-score: The score will be returned if you deleted them.
no-return-score: But the score will NOT be returned if you deleted them.
rates: rates:
storage: :score scores = 1 KB storage storage: :score scores = 1 KB storage
player: :score scores = 1 player player: :score scores = 1 player
@ -27,13 +28,11 @@ score-intro:
closet: closet:
upload: Upload Texture upload: Upload Texture
search: Search Texture search: Search Texture
type-to-search: Type to search
switch-category: Switch Category switch-category: Switch Category
view: View in skin library view: View in skin library
more: More more: More
set-avatar: Set as avatar set-avatar: Set as avatar
empty-msg: |
<p>Nothing in your closet...</p>
<p>Why not explore the <a href=":url">Skin Library</a> for a while?</p>
use-as: use-as:
button: Apply... button: Apply...
@ -128,6 +127,7 @@ profile:
password: Current Password password: Current Password
button: Change Email button: Change Email
wrong-password: Wrong password. wrong-password: Wrong password.
existed: This email address is used.
success: Email address updated successfully, please log in again. success: Email address updated successfully, please log in again.
delete: delete:

View File

@ -6,19 +6,20 @@ index:
overview: 概览 overview: 概览
users: users:
players-count:
title: 拥有角色数
status: status:
title: 状态 title: 状态
normal: 普通用户 normal: 普通用户
banned: 封禁 banned: 封禁
admin: 管理员 admin: 管理员
super-admin: 超级管理员 super-admin: 超级管理员
score:
tip: 输入修改后的积分,回车提交
operations: operations:
title: 更多操作 title: 更多操作
non-existent: 用户不存在 non-existent: 用户不存在
email: email:
change: 修改邮箱 change: 修改邮箱
existed: :email 已被占用
success: 邮箱修改成功 success: 邮箱修改成功
nickname: nickname:
change: 修改昵称 change: 修改昵称
@ -61,6 +62,8 @@ players:
change: 更换材质 change: 更换材质
non-existent: 材质 tid.:tid 不存在 non-existent: 材质 tid.:tid 不存在
success: 角色 :player 的材质修改成功 success: 角色 :player 的材质修改成功
name:
success: 角色名成功更改为 :player
owner: owner:
change: 更换角色拥有者 change: 更换角色拥有者
success: 角色 :player 已成功让渡至 :user success: 角色 :player 已成功让渡至 :user
@ -100,12 +103,6 @@ plugins:
operations: operations:
title: 操作 title: 操作
disable: 禁用插件
enable: 启用插件
configure: 插件配置
no-config-notice: 插件已被禁用或无配置页
delete: 删除插件
enabled: :plugin 已启用 enabled: :plugin 已启用
disabled: :plugin 已禁用 disabled: :plugin 已禁用
deleted: 插件已被成功删除 deleted: 插件已被成功删除

View File

@ -62,12 +62,17 @@
setAsPublic: '设为公开', setAsPublic: '设为公开',
setPublicNotice: '要将此材质设置为公开吗?', setPublicNotice: '要将此材质设置为公开吗?',
deleteNotice: '真的要删除此材质吗?积分将会被返还' deleteNotice: '真的要删除此材质吗?'
}, },
user: { user: {
signInRemainingTime: ':time 小时后可签到', signInRemainingTime: ':time 小时后可签到',
// Closet // Closet
emptyClosetMsg: '<p>衣柜里啥都没有哦~</p><p>去<a href=":url">皮肤库</a>看看吧~</p>',
renameItem: '重命名物品',
removeItem: '从衣柜中移除',
setAsAvatar: '设为头像',
viewInSkinlib: '在皮肤库中查看',
switch2dPreview: '切换 2D 预览', switch2dPreview: '切换 2D 预览',
switch3dPreview: '切换 3D 预览', switch3dPreview: '切换 3D 预览',
removeFromClosetNotice: '确定要从衣柜中移除此材质吗?', removeFromClosetNotice: '确定要从衣柜中移除此材质吗?',
@ -77,11 +82,12 @@
// Player // Player
changePlayerName: '请输入角色名:', changePlayerName: '请输入角色名:',
playerNameRule: '允许数字、字母以及下划线,是否支持中文角色名请参考本站设置',
emptyPlayerName: '你还没有填写名称哦', emptyPlayerName: '你还没有填写名称哦',
clearTexture: '确定要重置该用户的皮肤/披风吗?', clearTexture: '确定要重置该用户的皮肤/披风吗?',
deletePlayer: '真的要删除该玩家吗?', deletePlayer: '真的要删除该玩家吗?',
deletePlayerNotice: '这将是永久性的删除', deletePlayerNotice: '这将是永久性的删除',
chooseClearTexture: '选择要删除的材质类型',
noClearChoice: '您还没选择要删除的材质类型',
// Profile // Profile
setAvatar: '确定要将此材质设置为用户头像吗?', setAvatar: '确定要将此材质设置为用户头像吗?',
@ -95,38 +101,59 @@
emptyDeletePassword: '请先输入当前用户密码' emptyDeletePassword: '请先输入当前用户密码'
}, },
admin: { admin: {
// Change User Profile operationsTitle: '更多操作',
newUserEmail: '请输入新邮箱:',
newUserNickname: '请输入新昵称:',
newUserPassword: '请输入新密码:',
deleteUserNotice: '真的要删除此用户吗?此操作不可恢复',
changePlayerOwner: '请输入此角色要让渡至的用户 UID',
deletePlayerNotice: '真的要删除此角色吗?此操作不可恢复',
// Status // Users
banned: '封禁',
normal: '正常',
admin: '管理员',
// Operations
ban: '封禁', ban: '封禁',
unban: '解封', unban: '解封',
setAdmin: '设为管理员', setAdmin: '设为管理员',
unsetAdmin: '解除管理员', unsetAdmin: '解除管理员',
deleteUser: '删除用户',
cannotDeleteAdmin: '你不能删除管理员账号哦',
cannotDeleteSuperAdmin: '超级管理员账号不能被这样删除的啦',
changeEmail: '修改邮箱',
changeNickName: '修改昵称',
changePassword: '更改密码',
newUserEmail: '请输入新邮箱:',
newUserNickname: '请输入新昵称:',
newUserPassword: '请输入新密码:',
deleteUserNotice: '真的要删除此用户吗?此操作不可恢复',
scoreTip: '输入修改后的积分,回车提交',
doubleClickToSeeUser: '双击可查看该用户的信息',
doubleClickToSeePlayers: '双击可查看该用户的角色',
// Change Player Texture // Status
banned: '封禁',
normal: '普通用户',
admin: '管理员',
superAdmin: '超级管理员',
// Players
textureType: '材质类型', textureType: '材质类型',
skin: '皮肤(:model 模型)', skin: '皮肤(:model 模型)',
cape: '披风', cape: '披风',
pid: '材质 ID', pid: '材质 ID',
pidNotice: '输入要更换的材质的 TID', pidNotice: '输入要更换的材质的 TID,输入 0 即可清除该角色的材质',
changePlayerTexture: '更换角色 :player 的材质', changePlayerTexture: '更换角色 :player 的材质',
changeTexture: '更换材质',
changePlayerName: '更改角色名',
changeOwner: '更换角色拥有者',
deletePlayer: '删除角色',
changePlayerOwner: '请输入此角色要让渡至的用户 UID',
deletePlayerNotice: '真的要删除此角色吗?此操作不可恢复',
targetUser: '目标用户::nickname',
noSuchUser: '没有这个用户哦~',
changePlayerNameNotice: '请输入新的角色名:',
emptyPlayerName: '您还没填写角色名呢',
// Index // Index
textureUploads: '材质上传', textureUploads: '材质上传',
userRegistration: '用户注册', userRegistration: '用户注册',
// Plugins // Plugins
configurePlugin: '插件配置',
noPluginConfigNotice: '插件已被禁用或无配置页',
deletePlugin: '删除插件',
statusEnabled: '已启用', statusEnabled: '已启用',
statusDisabled: '已禁用', statusDisabled: '已禁用',
enablePlugin: '启用插件', enablePlugin: '启用插件',
@ -139,10 +166,14 @@
extracting: '正在解压更新包' extracting: '正在解压更新包'
}, },
general: { general: {
skin: '皮肤',
cape: '披风',
fatalError: '严重错误(请联系作者)', fatalError: '严重错误(请联系作者)',
confirmLogout: '确定要登出吗?', confirmLogout: '确定要登出吗?',
confirm: '确定', confirm: '确定',
cancel: '取消' cancel: '取消',
more: '更多',
noResult: '无结果'
}, },
vendor: { vendor: {
datatables: { datatables: {

View File

@ -22,10 +22,12 @@ score-intro:
「贯彻爱与真实的。。呸!」上面只是卖下萌~ 「贯彻爱与真实的。。呸!」上面只是卖下萌~
为了不出现用户一个劲上传材质导致存储空间爆满,我们决定启用积分系统。 为了不出现用户一个劲上传材质导致存储空间爆满,我们决定启用积分系统。
添加角色以及上传材质都会消耗积分,而删除已经添加的角色和已上传的材质时积分将会被返还 添加角色以及上传材质都会消耗积分,:return-score
本站用户初始积分为 :initial_score每日签到可以随机获得 :score-from ~ :score-to 积分 本站用户初始积分为 :initial_score每日签到可以随机获得 :score-from ~ :score-to 积分
添加皮肤库里的材质到衣柜不消耗积分。 添加皮肤库里的材质到衣柜不消耗积分。
will-return-score: 而删除已经添加的角色和已上传的材质时积分将会被返还
no-return-score: 但删除已经添加的角色和已上传的材质时积分不会被返还
rates: rates:
storage: :score 积分 = 1 KB 存储空间 storage: :score 积分 = 1 KB 存储空间
player: :score 积分 = 1 个角色 player: :score 积分 = 1 个角色
@ -33,13 +35,11 @@ score-intro:
closet: closet:
upload: 上传材质 upload: 上传材质
search: 搜索材质 search: 搜索材质
type-to-search: 输入即搜索
switch-category: 切换分类 switch-category: 切换分类
view: 在皮肤库中查看 view: 在皮肤库中查看
more: 更多 more: 更多
set-avatar: 设为头像 set-avatar: 设为头像
empty-msg: |
<p>衣柜里啥都没有哦~</p>
<p>去<a href=":url">皮肤库</a>看看吧~</p>
use-as: use-as:
button: 使用... button: 使用...
@ -134,6 +134,7 @@ profile:
password: 当前密码 password: 当前密码
button: 修改邮箱 button: 修改邮箱
wrong-password: 密码错误 wrong-password: 密码错误
existed: 这个邮箱已经被别人占用啦
success: 邮箱修改成功,请重新登录 success: 邮箱修改成功,请重新登录
delete: delete:

View File

@ -43,26 +43,5 @@
$(document).ready(function() { $(document).ready(function() {
$('.box-body').css('min-height', $('.content-wrapper').height() - $('.content-header').outerHeight() - 120); $('.box-body').css('min-height', $('.content-wrapper').height() - $('.content-header').outerHeight() - 120);
}); });
$('#player-table').DataTable({
language: trans('vendor.datatables'),
scrollX: true,
autoWidth: false,
processing: true,
serverSide: true,
ajax: '{{ url("admin/player-data") }}',
createdRow: function (row, data, index) {
$('td', row).eq(2).attr('id', 'player-name');
},
columns: [
{data: 'pid', 'width': '1%'},
{data: 'uid'},
{data: 'player_name'},
{data: 'preference'},
{data: 'previews', searchable: false, orderable: false},
{data: 'last_modified'},
{data: 'operations', searchable: false, orderable: false}
]
});
</script> </script>
@endsection @endsection

View File

@ -47,32 +47,3 @@
</div><!-- /.content-wrapper --> </div><!-- /.content-wrapper -->
@endsection @endsection
@section('script')
<script type="text/javascript">
var table = $('#plugin-table').DataTable({
language: trans('vendor.datatables'),
scrollX: true,
pageLength: 25,
autoWidth: false,
processing: true,
serverSide: true,
ajax: '{{ url("admin/plugins/data") }}',
createdRow: function (row, data, index) {
$('td', row).eq(1).attr('id', 'description');
$('td', row).eq(2).attr('id', 'author');
$('td', row).eq(3).attr('id', 'version');
$('td', row).eq(4).attr('id', 'status');
},
columns: [
{data: 'title'},
{data: 'description', 'width': '35%'},
{data: 'author'},
{data: 'version'},
{data: 'status'},
{data: 'operations', searchable: false, orderable: false}
]
});
</script>
@endsection

View File

@ -24,6 +24,7 @@
<th>{{ trans('general.user.email') }}</th> <th>{{ trans('general.user.email') }}</th>
<th>{{ trans('general.user.nickname') }}</th> <th>{{ trans('general.user.nickname') }}</th>
<th>{{ trans('general.user.score') }}</th> <th>{{ trans('general.user.score') }}</th>
<th>{{ trans('admin.users.players-count.title') }}</th>
<th>{{ trans('admin.users.status.title') }}</th> <th>{{ trans('admin.users.status.title') }}</th>
<th>{{ trans('general.user.register-at') }}</th> <th>{{ trans('general.user.register-at') }}</th>
<th>{{ trans('general.operations') }}</th> <th>{{ trans('general.operations') }}</th>
@ -42,28 +43,5 @@
$(document).ready(function() { $(document).ready(function() {
$('.box-body').css('min-height', $('.content-wrapper').height() - $('.content-header').outerHeight() - 120); $('.box-body').css('min-height', $('.content-wrapper').height() - $('.content-header').outerHeight() - 120);
}); });
$('#user-table').DataTable({
language: trans('vendor.datatables'),
scrollX: true,
autoWidth: false,
processing: true,
serverSide: true,
ajax: '{{ url("admin/user-data") }}',
createdRow: function (row, data, index) {
$('td', row).eq(1).attr('id', 'email');
$('td', row).eq(2).attr('id', 'nickname');
$('td', row).eq(4).attr('id', 'permission');
},
columns: [
{data: 'uid', 'width': '1%'},
{data: 'email'},
{data: 'nickname'},
{data: 'score'},
{data: 'permission'},
{data: 'register_at'},
{data: 'operations', searchable: false, orderable: false}
]
});
</script> </script>
@endsection @endsection

View File

@ -39,17 +39,17 @@
<i class="fa fa-filter" aria-hidden="true"></i> {{ trans('skinlib.general.filter') }} <span class="caret"></span> <i class="fa fa-filter" aria-hidden="true"></i> {{ trans('skinlib.general.filter') }} <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
<li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=skin&sort={{ $sort }}'>{{ trans('general.skin') }} <small>{{ trans('skinlib.filter.any-model') }}</small></a></li> <li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=skin&{{ isset($_GET["uid"]) ? "uid=$uploader&" : "" }}sort={{ $sort }}'>{{ trans('general.skin') }} <small>{{ trans('skinlib.filter.any-model') }}</small></a></li>
<li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=steve&sort={{ $sort }}'>{{ trans('general.skin') }} <small>{{ trans('skinlib.filter.steve-model') }}</small></a></li> <li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=steve&{{ isset($_GET["uid"]) ? "uid=$uploader&" : "" }}sort={{ $sort }}'>{{ trans('general.skin') }} <small>{{ trans('skinlib.filter.steve-model') }}</small></a></li>
<li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=alex&sort={{ $sort }}'>{{ trans('general.skin') }} <small>{{ trans('skinlib.filter.alex-model') }}</small></a></li> <li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=alex&{{ isset($_GET["uid"]) ? "uid=$uploader&" : "" }}sort={{ $sort }}'>{{ trans('general.skin') }} <small>{{ trans('skinlib.filter.alex-model') }}</small></a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=cape&sort={{ $sort }}'>{{ trans('general.cape') }}</a></li> <li><a href='?{{ isset($_GET["q"]) ? "q=$q&" : "" }}filter=cape&{{ isset($_GET["uid"]) ? "uid=$uploader&" : "" }}sort={{ $sort }}'>{{ trans('general.cape') }}</a></li>
@if (!is_null($user)) @if (!is_null($user))
<li class="divider"></li> <li class="divider"></li>
<li><a href="?filter=user&uid={{ $user->uid }}&sort={{ $sort }}">{{ trans('skinlib.general.my-upload') }}</a></li> <li><a href="?{{ isset($_GET["filter"]) ? "filter=$filter&" : "" }}uid={{ $user->uid }}&sort={{ $sort }}">{{ trans('skinlib.general.my-upload') }}</a></li>
@endif @endif
<li class="divider"></li> <li class="divider"></li>
<li><a href="/skinlib">{{ trans('skinlib.filter.clean-filter') }}</a></li> <li><a href="{{ url('skinlib') }}">{{ trans('skinlib.filter.clean-filter') }}</a></li>
</ul> </ul>
</li> </li>

View File

@ -10,7 +10,6 @@
<section class="content-header"> <section class="content-header">
<h1> <h1>
{{ $__env->getSections()['title'] }} {{ $__env->getSections()['title'] }}
<small>Search Result</small>
</h1> </h1>
@include('vendor.breadcrumb') @include('vendor.breadcrumb')

View File

@ -51,14 +51,20 @@
<td id="name">{{ $texture->name }} <td id="name">{{ $texture->name }}
@if (!is_null($user) && ($texture->uploader == $user->uid || $user->isAdmin())) @if (!is_null($user) && ($texture->uploader == $user->uid || $user->isAdmin()))
<small> <small>
<a href="javascript:changeTextureName({{ $texture->tid }});">{{ trans('skinlib.show.edit-name') }}</a> <a href="javascript:changeTextureName({{ $texture->tid }}, '{{ $texture->name }}');">{{ trans('skinlib.show.edit-name') }}</a>
</small> </small>
@endif @endif
</td> </td>
</tr> </tr>
<tr> <tr>
<td>{{ trans('skinlib.show.model') }}</td> <td>{{ trans('skinlib.show.model') }}</td>
<td>{{ $texture->type }}</td> <td>
@if ($texture->type == 'cape')
{{ trans('general.cape') }}
@else
{{ $texture->type }}
@endif
</td>
</tr> </tr>
<tr> <tr>
<td>Hash <td>Hash
@ -75,7 +81,7 @@
<tr> <tr>
<td>{{ trans('skinlib.show.uploader') }}</td> <td>{{ trans('skinlib.show.uploader') }}</td>
@if ($uploader = app('users')->get($texture->uploader)) @if ($uploader = app('users')->get($texture->uploader))
<td><a href="{{ url('skinlib?filter=user&uid='.$uploader->uid) }}&sort=time">{{ $uploader->getNickName() }}</a></td> <td><a href="{{ url('skinlib?filter='.($texture->type == 'cape' ? 'cape' : 'skin').'&uid='.$uploader->uid) }}&sort=time">{{ $uploader->getNickName() }}</a></td>
@else @else
<td><a href="#">{{ trans('general.unexistent-user') }}</a></td> <td><a href="#">{{ trans('general.unexistent-user') }}</a></td>
@endif @endif

View File

@ -26,51 +26,30 @@
<div class="nav-tabs-custom"> <div class="nav-tabs-custom">
<!-- Tabs within a box --> <!-- Tabs within a box -->
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="#skin-category" data-toggle="tab">{{ trans('general.skin') }}</a></li> <li class="active"><a href="#skin-category" class="category-switch" data-toggle="tab">{{ trans('general.skin') }}</a></li>
<li><a href="#cape-category" data-toggle="tab">{{ trans('general.cape') }}</a></li> <li><a href="#cape-category" class="category-switch" data-toggle="tab">{{ trans('general.cape') }}</a></li>
<div style="padding: 7px;"> <li class="pull-right" style="padding: 7px;">
<div class="has-feedback pull-right"> <div class="has-feedback pull-right">
<form method="get" action="" class="user-search-form"> <div class="user-search-form">
<input type="text" name="q" class="form-control input-sm" placeholder="输入,回车搜索" value="{{ $q }}"> <input type="text" name="q" class="form-control input-sm" placeholder="{{ trans('user.closet.type-to-search') }}">
<span class="glyphicon glyphicon-search form-control-feedback"></span> <span class="glyphicon glyphicon-search form-control-feedback"></span>
</form> </div>
</div> </div>
</div> </li>
</ul> </ul>
<div class="tab-content no-padding"> <div class="tab-content no-padding">
<div class="tab-pane active box-body" id="skin-category"> <div class="tab-pane active box-body" id="skin-category"></div>
@include('vendor.closet-items', ['items' => (array)array_get($items, 'skin')]) <div class="tab-pane box-body" id="cape-category"></div>
</div>
<div class="tab-pane box-body" id="cape-category">
@include('vendor.closet-items', ['items' => (array)array_get($items, 'cape')])
</div>
</div> </div>
<div class="box-footer"> <div class="box-footer">
<ul class="pagination pagination-sm no-margin pull-right"> <div class="pull-right" id="closet-paginator" last-skin-page="1" last-cape-page="1"></div>
<?php $base_url = $q ? "?q=$q&" : "?"; ?>
<li><a href="{{ $base_url }}page=1">«</a></li>
@if ($page != 1)
<li><a href="{{ $base_url }}page={{ $page-1 }}">{{ $page - 1 }}</a></li>
@endif
<li><a href="{{ $base_url }}page={{ $page }}" class="active">{{ $page }}</a></li>
@if ($total_pages > $page)
<li><a href="{{ $base_url }}page={{ $page+1 }}">{{ $page+1 }}</a></li>
@endif
<li><a href="{{ $base_url }}page={{ $total_pages }}">»</a></li>
</ul>
<p class="pull-right">{{ trans('general.pagination', ['page' => $page, 'total' => $total_pages]) }}</p>
</div> </div>
</div><!-- /.nav-tabs-custom --> </div><!-- /.nav-tabs-custom -->
</div> </div>
<!-- Left col --> <!-- Right col -->
<div class="col-md-4"> <div class="col-md-4">
<div class="box box-default"> <div class="box box-default">

View File

@ -110,7 +110,8 @@
{!! nl2br(trans('user.score-intro.introduction', [ {!! nl2br(trans('user.score-intro.introduction', [
'initial_score' => option('user_initial_score'), 'initial_score' => option('user_initial_score'),
'score-from' => $from, 'score-from' => $from,
'score-to' => $to 'score-to' => $to,
'return-score' => option('return_score') ? trans('user.score-intro.will-return-score') : trans('user.score-intro.no-return-score')
])) !!} ])) !!}
<hr /> <hr />

View File

@ -1,11 +0,0 @@
<div class="btn-group">
<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ trans('admin.players.operations.title') }} <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="javascript:changeTexture('{{ $pid }}');">{{ trans('admin.players.textures.change') }}</a></li>
<li><a href="javascript:changeOwner('{{ $pid }}');">{{ trans('admin.players.owner.change') }}</a></li>
</ul>
</div>
<a class="btn btn-danger btn-sm" href="javascript:deletePlayer('{{ $pid }}');">{{ trans('admin.players.delete.delete') }}</a>

View File

@ -1,4 +0,0 @@
<select class="form-control" id="preference">
<option {{ ($preference == "default") ? 'selected=selected' : '' }} value="default">Default</option>
<option {{ ($preference == "slim") ? 'selected=selected' : '' }} value="slim">Slim</option>
</select>

View File

@ -1,23 +0,0 @@
@if ($tid_steve == '0')
<img id="{{ $pid }}-steve" width="64" />
@else
<a href="{{ url('skinlib/show/'.$tid_steve) }}">
<img id="{{ $pid }}-steve" width="64" src="{{ url('preview/64/'.$tid_steve) }}.png" />
</a>
@endif
@if ($tid_alex == '0')
<img id="{{ $pid }}-alex" width="64" />
@else
<a href="{{ url('skinlib/show/'.$tid_alex) }}">
<img id="{{ $pid }}-alex" width="64" src="{{ url('preview/64/'.$tid_alex) }}.png" />
</a>
@endif
@if ($tid_cape == '0')
<img id="{{ $pid }}-cape" width="64" />
@else
<a href="{{ url('skinlib/show/'.$tid_cape) }}">
<img id="{{ $pid }}-cape" width="64" src="{{ url('preview/64/'.$tid_cape) }}.png" />
</a>
@endif

View File

@ -1,13 +0,0 @@
@if ($plugin->isEnabled())
<a class="btn btn-warning btn-sm" href="javascript:disablePlugin('{{ $plugin->name }}');">{{ trans('admin.plugins.operations.disable') }}</a>
@else
<a class="btn btn-primary btn-sm" href="javascript:enablePlugin('{{ $plugin->name }}');">{{ trans('admin.plugins.operations.enable') }}</a>
@endif
@if ($plugin->isEnabled() && $plugin->hasConfigView())
<a class="btn btn-default btn-sm" href="{{ url('admin/plugins/config/'.$plugin->name) }}">{{ trans('admin.plugins.operations.configure') }}</a>
@else
<a class="btn btn-default btn-sm" disabled="disabled" title="{{ trans('admin.plugins.operations.no-config-notice') }}" data-toggle="tooltip" data-placement="top">{{ trans('admin.plugins.operations.configure') }}</a>
@endif
<a class="btn btn-danger btn-sm" href="javascript:deletePlugin('{{ $plugin->name }}');">{{ trans('admin.plugins.operations.delete') }}</a>

View File

@ -1,50 +0,0 @@
<?php use App\Models\User; ?>
<div class="btn-group">
<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ trans('admin.users.operations.title') }} <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="javascript:changeUserEmail('{{ $uid }}');">{{ trans('admin.users.operations.email.change') }}</a></li>
<li><a href="javascript:changeUserNickName('{{ $uid }}');">{{ trans('admin.users.operations.nickname.change') }}</a></li>
<li><a href="javascript:changeUserPwd('{{ $uid }}');">{{ trans('admin.users.operations.password.change') }}</a></li>
@unless ($permission == User::SUPER_ADMIN)
<li class="divider"></li>
{{-- If current user is super admin --}}
@if (app('user.current')->getPermission() == User::SUPER_ADMIN)
@if ($permission == User::ADMIN)
<li><a id="admin" href="javascript:changeAdminStatus('{{ $uid }}');">{{ trans('admin.users.operations.admin.unset.text') }}</a></li>
@else
<li><a id="admin" href="javascript:changeAdminStatus('{{ $uid }}');">{{ trans('admin.users.operations.admin.set.text') }}</a></li>
@endif
@endif
<li class="divider"></li>
@if ($permission == User::BANNED)
<li><a id="ban" href="javascript:changeBanStatus('{{ $uid }}');">{{ trans('admin.users.operations.ban.unban.text') }}</a></li>
@else
<li><a id="ban" href="javascript:changeBanStatus('{{ $uid }}');">{{ trans('admin.users.operations.ban.ban.text') }}</a></li>
@endif
@endunless
</ul>
</div>
{{-- If current user is super admin --}}
@if (app('user.current')->getPermission() == User::SUPER_ADMIN)
@if ($permission == "2")
<a class="btn btn-danger btn-sm" disabled="disabled" data-toggle="tooltip" data-placement="bottom" title="{{ trans('admin.users.operations.delete.cant-super-admin') }}">{{ trans('admin.users.operations.delete.delete') }}</a>
@else
<a class="btn btn-danger btn-sm" href="javascript:deleteUserAccount('{{ $uid }}');">{{ trans('admin.users.operations.delete.delete') }}</a>
@endif
@else
@if ($permission == "1" || $permission == "2")
<a class="btn btn-danger btn-sm" disabled="disabled" data-toggle="tooltip" data-placement="bottom" title="{{ trans('admin.users.operations.delete-cant-admin') }}">{{ trans('admin.users.operations.delete.delete') }}</a>
@else
<a class="btn btn-danger btn-sm" href="javascript:deleteUserAccount('{{ $uid }}');">{{ trans('admin.users.operations.delete.delete') }}</a>
@endif
@endif

View File

@ -1 +0,0 @@
<input type="text" class="form-control score" value="{{ $score }}" title="{{ trans('admin.users.score.tip') }}" data-toggle="tooltip" data-placement="right">

View File

@ -5,17 +5,18 @@
{{ trans('skinlib.filter.skin') }} {{ trans('skinlib.filter.skin') }}
<small>{{ trans('skinlib.filter.any-model') }}</small> <small>{{ trans('skinlib.filter.any-model') }}</small>
@elseif ($filter == "steve") @elseif ($filter == "steve")
{{ trans('skinlib.filter.any-model') }} {{ trans('skinlib.filter.skin') }}
<small>({{ trans('skinlib.filter.steve-model') }})</small> <small>{{ trans('skinlib.filter.steve-model') }}</small>
@elseif ($filter == "alex") @elseif ($filter == "alex")
{{ trans('skinlib.filter.skin') }} {{ trans('skinlib.filter.skin') }}
<small>{{ trans('skinlib.filter.alex-model') }}</small> <small>{{ trans('skinlib.filter.alex-model') }}</small>
@elseif ($filter == "cape") @elseif ($filter == "cape")
{{ trans('skinlib.filter.cape') }} {{ trans('skinlib.filter.cape') }}
@elseif ($filter == "user")
{{ trans('skinlib.filter.uploader', ['name' => App::make('users')->get($_GET['uid'])->getNickName()]) }}
@endif @endif
</li> </li>
@unless ($uploader == 0)
<li>{{ trans('skinlib.filter.uploader', ['name' => App::make('users')->get($_GET['uid'])->getNickName()]) }}</li>
@endunless
<li class="active"> <li class="active">
@if ($sort == "time") @if ($sort == "time")
{{ trans('skinlib.sort.newest-uploaded') }} {{ trans('skinlib.sort.newest-uploaded') }}

View File

@ -1,30 +0,0 @@
@forelse ($items as $item)
<div class="item" tid="{{ $item->tid }}">
<div class="item-body">
<img src="{{ url('preview/'.$item->tid) }}.png">
</div>
<div class="item-footer">
<p class="texture-name">
<span title="{{ $item->name }}">{{ $item->name }} <small>({{ $item->type }})</small></span>
</p>
<a href="{{ url('skinlib/show/'.$item->tid) }}" title="{{ trans('user.closet.view') }}" class="more" data-toggle="tooltip" data-placement="bottom"><i class="fa fa-share"></i></a>
<span title="{{ trans('user.closet.more') }}" class="more" data-toggle="dropdown" aria-haspopup="true" id="more-button"><i class="fa fa-cog"></i></span>
<ul class="dropup dropdown-menu" aria-labelledby="more-button">
<li><a href="javascript:renameClosetItem({{ $item->tid }});">{{ trans('user.closet.rename.title') }}</a></li>
<li><a href="javascript:removeFromCloset({{ $item->tid }});">{{ trans('user.closet.remove.title') }}</a></li>
<li><a href="javascript:setAsAvatar({{ $item->tid }});">{{ trans('user.closet.set-avatar') }}</a></li>
</ul>
</div>
</div>
@empty
<div class="empty-msg">
@if($q)
{{ trans('skinlib.general.no-result') }}
@else
{!! trans('user.closet.empty-msg', ['url' => url('skinlib')]) !!}
@endif
</div>
@endforelse

View File

@ -8,7 +8,11 @@
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
@foreach(config('locales') as $code => $langInfo) @foreach(config('locales') as $code => $langInfo)
@if (!isset($langInfo['alias'])) @if (!isset($langInfo['alias']))
<li class="locale"><a href="?lang={{ $code }}">{{ $langInfo['name'] }}</a></li> @if (count($_GET) == 0 || (count($_GET) == 1 && isset($_GET['lang'])))
<li class="locale"><a href="?lang={{ $code }}">{{ $langInfo['name'] }}</a></li>
@else
<li class="locale"><a href="{{ $_SERVER['REQUEST_URI'] }}&lang={{ $code }}">{{ $langInfo['name'] }}</a></li>
@endif
@endif @endif
@endforeach @endforeach
</ul> </ul>