Refactor & modulize JavaScript files
This commit is contained in:
parent
fe04c49f7e
commit
104f5a32a7
|
|
@ -1,824 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
let pluginsTable;
|
||||
|
||||
$(document).ready(function() {
|
||||
$('input').iCheck({
|
||||
checkboxClass: 'icheckbox_square-blue'
|
||||
});
|
||||
swal.setDefaults({
|
||||
confirmButtonText: trans('general.confirm'),
|
||||
cancelButtonText: trans('general.cancel')
|
||||
});
|
||||
|
||||
$.extend(true, $.fn.dataTable.defaults, {
|
||||
language: trans('common.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) {
|
||||
e.preventDefault();
|
||||
var skin_name = $(this).data('skin');
|
||||
$('body').removeClass(current_skin).addClass(skin_name);
|
||||
current_skin = skin_name;
|
||||
});
|
||||
|
||||
$('#color-submit').click(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./customize?action=color",
|
||||
dataType: "json",
|
||||
data: { "color_scheme": current_skin },
|
||||
success: function(json) {
|
||||
if (json.errno == 0)
|
||||
toastr.success(json.msg);
|
||||
else
|
||||
toastr.warning(json.msg);
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
|
||||
function changeUserEmail(uid) {
|
||||
let dom = $(`tr#user-${uid} > td:nth-child(2)`);
|
||||
swal({
|
||||
text: trans('admin.newUserEmail'),
|
||||
showCancelButton: true,
|
||||
input: 'text',
|
||||
inputValue: dom.text()
|
||||
}).then(email => {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./users?action=email",
|
||||
dataType: "json",
|
||||
data: { 'uid': uid, 'email': email },
|
||||
success: json => {
|
||||
if (json.errno == 0) {
|
||||
dom.text(email);
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function changeUserNickName(uid) {
|
||||
let dom = $(`tr#user-${uid} > td:nth-child(3)`);
|
||||
swal({
|
||||
text: trans('admin.newUserNickname'),
|
||||
showCancelButton: true,
|
||||
input: 'text',
|
||||
inputValue: dom.text()
|
||||
}).then(nickname => {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./users?action=nickname",
|
||||
dataType: "json",
|
||||
data: { 'uid': uid, 'nickname': nickname },
|
||||
success: json => {
|
||||
if (json.errno == 0) {
|
||||
dom.text(nickname);
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function changeUserPwd(uid) {
|
||||
swal({
|
||||
text: trans('admin.newUserPassword'),
|
||||
showCancelButton: true,
|
||||
input: 'password',
|
||||
}).then(password => {
|
||||
return Promise.resolve($.ajax({
|
||||
type: "POST",
|
||||
url: "./users?action=password",
|
||||
dataType: "json",
|
||||
data: { 'uid': uid, 'password': password }
|
||||
}));
|
||||
}).then(json => {
|
||||
if (json.errno == 0)
|
||||
toastr.success(json.msg);
|
||||
else
|
||||
toastr.warning(json.msg);
|
||||
}).catch(error => showAjaxError);
|
||||
}
|
||||
|
||||
function changeUserScore(uid, score) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./users?action=score",
|
||||
dataType: "json",
|
||||
// handle id formatted as '#user-1234'
|
||||
data: { 'uid': uid.slice(5), 'score': score },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function changeBanStatus(uid) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./users?action=ban",
|
||||
dataType: "json",
|
||||
data: { 'uid': uid },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
let dom = $(`#ban-${uid}`);
|
||||
|
||||
if (dom.attr('data') == 'banned') {
|
||||
dom.text(trans('admin.ban')).attr('data', 'normal');
|
||||
} else {
|
||||
dom.text(trans('admin.unban')).attr('data', 'banned');
|
||||
}
|
||||
|
||||
$(`#user-${uid} > td.status`).text(
|
||||
json.permission == -1 ? trans('admin.banned') : trans('admin.normal')
|
||||
);
|
||||
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function changeAdminStatus(uid) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./users?action=admin",
|
||||
dataType: "json",
|
||||
data: { 'uid': uid },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
let dom = $(`#admin-${uid}`);
|
||||
|
||||
if (dom.attr('data') == 'admin') {
|
||||
dom.text(trans('admin.setAdmin')).attr('data', 'normal');
|
||||
} else {
|
||||
dom.text(trans('admin.unsetAdmin')).attr('data', 'admin');
|
||||
}
|
||||
|
||||
$(`#user-${uid} > td.status`).text(
|
||||
json.permission == 1 ? trans('admin.admin') : trans('admin.normal')
|
||||
);
|
||||
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUserAccount(uid) {
|
||||
swal({
|
||||
text: trans('admin.deleteUserNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => {
|
||||
return Promise.resolve($.ajax({
|
||||
type: "POST",
|
||||
url: "./users?action=delete",
|
||||
dataType: "json",
|
||||
data: { 'uid': uid }
|
||||
}))
|
||||
}).then(json => {
|
||||
if (json.errno == 0) {
|
||||
$('tr#user-' + uid).remove();
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
}).catch(error => showAjaxError);
|
||||
}
|
||||
|
||||
$('body').on('keypress', '.score', function(event){
|
||||
if (event.which == 13) {
|
||||
changeUserScore($(this).parent().parent().attr('id'), $(this).val());
|
||||
$(this).blur();
|
||||
}
|
||||
});
|
||||
|
||||
function changePreference() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./players?action=preference",
|
||||
dataType: "json",
|
||||
data: { 'pid': $(this).parent().parent().attr('id'), 'preference': $(this).val() },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function changeTexture(pid, playerName) {
|
||||
let dom = `
|
||||
<div class="form-group">
|
||||
<label for="model">${trans('admin.textureType')}</label>
|
||||
<select class="form-control" id="model">
|
||||
<option value="steve">${trans('admin.skin', {'model': 'Steve'})}</option>
|
||||
<option value="alex">${trans('admin.skin', {'model': 'Alex'})}</option>
|
||||
<option value="cape">${trans('admin.cape')}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tid">${trans('admin.pid')}</label>
|
||||
<input id="tid" class="form-control" type="text" placeholder="${trans('admin.pidNotice')}">
|
||||
</div>`;
|
||||
|
||||
showModal(dom, trans('admin.changePlayerTexture', {'player': playerName}), 'default', {
|
||||
callback: `ajaxChangeTexture(${pid})`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
function ajaxChangeTexture(pid) {
|
||||
// remove interference of modal which is hide
|
||||
$('.modal').each(function() {
|
||||
if ($(this).css('display') == "none")
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
var model = $('#model').val();
|
||||
var tid = $('#tid').val();
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./players?action=texture",
|
||||
dataType: "json",
|
||||
data: { 'pid': pid, 'model': model, 'tid': tid },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
$('#'+pid+'-'+model).attr('src', '../preview/64/'+tid+'.png');
|
||||
$('.modal').modal('hide');
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
let dom = $(`#${pid} > td:nth-child(2)`);
|
||||
swal({
|
||||
html: `${trans('admin.changePlayerOwner')}<br><small> </small>`,
|
||||
input: 'number',
|
||||
inputValue: dom.text(),
|
||||
showCancelButton: true
|
||||
}).then(uid => {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./players?action=owner",
|
||||
dataType: "json",
|
||||
data: { 'pid': pid, 'uid': uid },
|
||||
success: function (json) {
|
||||
if (json.errno == 0) {
|
||||
dom.text(uid);
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
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') +
|
||||
'<small style="display: block; margin-top: .5em;">' +
|
||||
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) {
|
||||
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) {
|
||||
|
||||
},
|
||||
error: showAjaxError
|
||||
}))
|
||||
}).then(json => {
|
||||
if (json.errno == 0) {
|
||||
$('tr#' + pid).remove();
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
}).catch(error => showAjaxError);
|
||||
}
|
||||
|
||||
function enablePlugin(name) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "?action=enable&name=" + name,
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
|
||||
pluginsTable.ajax.reload(null, false);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function disablePlugin(name) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "?action=disable&name=" + name,
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.warning(json.msg);
|
||||
|
||||
pluginsTable.ajax.reload(null, false);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function deletePlugin(name) {
|
||||
swal({
|
||||
text: trans('admin.confirmDeletion'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "?action=delete&name=" + name,
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
|
||||
pluginsTable.ajax.reload(null, false);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function downloadUpdates() {
|
||||
var file_size = 0;
|
||||
var progress = 0;
|
||||
|
||||
console.log("Prepared to download");
|
||||
|
||||
$.ajax({
|
||||
url: './update/download?action=prepare-download',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
$('#update-button').html('<i class="fa fa-spinner fa-spin"></i> '+trans('admin.preparing')).prop('disabled', 'disabled');
|
||||
},
|
||||
})
|
||||
.done(function(json) {
|
||||
console.log(json);
|
||||
|
||||
file_size = json.file_size;
|
||||
|
||||
$('#file-size').html(file_size);
|
||||
|
||||
$('#modal-start-download').modal({
|
||||
'backdrop': 'static',
|
||||
'keyboard': false
|
||||
});
|
||||
|
||||
console.log("started downloading");
|
||||
$.ajax({
|
||||
url: './update/download?action=start-download',
|
||||
type: 'POST',
|
||||
dataType: 'json'
|
||||
})
|
||||
.done(function(json) {
|
||||
// set progress to 100 when got the response
|
||||
progress = 100;
|
||||
|
||||
console.log("Downloading finished");
|
||||
console.log(json);
|
||||
})
|
||||
.fail(showAjaxError);
|
||||
|
||||
var interval_id = window.setInterval(function() {
|
||||
|
||||
$('#imported-progress').html(progress);
|
||||
$('.progress-bar').css('width', progress+'%').attr('aria-valuenow', progress);
|
||||
|
||||
if (progress == 100) {
|
||||
clearInterval(interval_id);
|
||||
|
||||
$('.modal-title').html('<i class="fa fa-spinner fa-spin"></i> ' + trans('admin.extracting'));
|
||||
$('.modal-body').append('<p>'+trans('admin.downloadCompleted')+'</p>')
|
||||
|
||||
console.log("Start extracting");
|
||||
$.ajax({
|
||||
url: './update/download?action=extract',
|
||||
type: 'POST',
|
||||
dataType: 'json'
|
||||
})
|
||||
.done(function(json) {
|
||||
console.log("Package extracted and files are covered");
|
||||
$('#modal-start-download').modal('toggle');
|
||||
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(function() {
|
||||
window.location = "../";
|
||||
}, function(dismiss) {
|
||||
window.location = "../";
|
||||
});
|
||||
})
|
||||
.fail(showAjaxError);
|
||||
|
||||
} else {
|
||||
$.ajax({
|
||||
url: './update/download?action=get-file-size',
|
||||
type: 'GET'
|
||||
})
|
||||
.done(function(json) {
|
||||
progress = (json.size / file_size * 100).toFixed(2);
|
||||
|
||||
console.log("Progress: "+progress);
|
||||
})
|
||||
.fail(showAjaxError);
|
||||
}
|
||||
|
||||
}, 300);
|
||||
|
||||
})
|
||||
.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',
|
||||
className: 'status',
|
||||
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;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
21
resources/assets/src/js/admin/customize.js
Normal file
21
resources/assets/src/js/admin/customize.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* global current_skin:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
$('#layout-skins-list [data-skin]').click(function (e) {
|
||||
e.preventDefault();
|
||||
let skin_name = $(this).data('skin');
|
||||
$('body').removeClass(current_skin).addClass(skin_name);
|
||||
current_skin = skin_name;
|
||||
});
|
||||
|
||||
$('#color-submit').click(() => {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/customize?action=color'),
|
||||
dataType: 'json',
|
||||
data: { color_scheme: current_skin }
|
||||
}).then(({ errno, msg }) => {
|
||||
(errno == 0) ? toastr.success(msg) : toastr.warning(msg);
|
||||
}).catch(err => showAjaxError(err));
|
||||
});
|
||||
24
resources/assets/src/js/admin/index.js
Normal file
24
resources/assets/src/js/admin/index.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* global initUsersTable, initPlayersTable, initPluginsTable */
|
||||
|
||||
'use strict';
|
||||
|
||||
$.pluginsTable = null;
|
||||
|
||||
$(document).ready(() => {
|
||||
$.extend(true, $.fn.dataTable.defaults, {
|
||||
language: trans('common.datatables'),
|
||||
scrollX: true,
|
||||
pageLength: 25,
|
||||
autoWidth: false,
|
||||
processing: true,
|
||||
serverSide: true
|
||||
});
|
||||
|
||||
if (window.location.pathname.includes('admin/users')) {
|
||||
initUsersTable();
|
||||
} else if (window.location.pathname.includes('admin/players')) {
|
||||
initPlayersTable();
|
||||
} else if (window.location.pathname.includes('admin/plugins/manage')) {
|
||||
$.pluginsTable = initPluginsTable();
|
||||
}
|
||||
});
|
||||
164
resources/assets/src/js/admin/players.js
Normal file
164
resources/assets/src/js/admin/players.js
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/* exported changePreference, changeTexture, ajaxChangeTexture, changePlayerName, changeOwner, deletePlayer */
|
||||
|
||||
'use strict';
|
||||
|
||||
function changePreference() {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/players?action=preference'),
|
||||
dataType: 'json',
|
||||
data: {
|
||||
pid: $(this).parent().parent().attr('id'),
|
||||
preference: $(this).val()
|
||||
}
|
||||
}).then(({ errno, msg }) => {
|
||||
(errno == 0) ? toastr.success(msg) : toastr.warning(msg);
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeTexture(pid, playerName) {
|
||||
let dom = `
|
||||
<div class="form-group">
|
||||
<label for="model">${trans('admin.textureType')}</label>
|
||||
<select class="form-control" id="model">
|
||||
<option value="steve">${trans('admin.skin', { 'model': 'Steve' })}</option>
|
||||
<option value="alex">${trans('admin.skin', { 'model': 'Alex' })}</option>
|
||||
<option value="cape">${trans('admin.cape')}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tid">${trans('admin.pid')}</label>
|
||||
<input id="tid" class="form-control" type="text" placeholder="${trans('admin.pidNotice')}">
|
||||
</div>`;
|
||||
|
||||
showModal(dom, trans('admin.changePlayerTexture', { 'player': playerName }), 'default', {
|
||||
callback: `ajaxChangeTexture(${pid})`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
function ajaxChangeTexture(pid) {
|
||||
// Remove interference of modal which is hide
|
||||
$('.modal').each(function () {
|
||||
if ($(this).css('display') == 'none') $(this).remove();
|
||||
});
|
||||
|
||||
var model = $('#model').val();
|
||||
var tid = $('#tid').val();
|
||||
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/players?action=texture'),
|
||||
dataType: 'json',
|
||||
data: { pid: pid, model: model, tid: tid }
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
$(`#${pid}-${model}`).attr('src', url(`preview/64/${tid}.png`));
|
||||
$('.modal').modal('hide');
|
||||
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changePlayerName(pid, oldName) {
|
||||
let dom = $(`tr#${pid} > td:nth-child(3)`);
|
||||
let newPlayerName = '';
|
||||
|
||||
swal({
|
||||
text: trans('admin.changePlayerNameNotice'),
|
||||
input: 'text',
|
||||
inputValue: oldName,
|
||||
inputValidator: name => (new Promise((resolve, reject) => {
|
||||
(newPlayerName = name) ? resolve() : reject(trans('admin.emptyPlayerName'));
|
||||
}))
|
||||
}).then(name => fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/players?action=name'),
|
||||
dataType: 'json',
|
||||
data: { pid: pid, name: name }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
dom.text(newPlayerName);
|
||||
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeOwner(pid) {
|
||||
let dom = $(`#${pid} > td:nth-child(2)`);
|
||||
let owner = 0;
|
||||
|
||||
swal({
|
||||
html: `${trans('admin.changePlayerOwner')}<br><small> </small>`,
|
||||
input: 'number',
|
||||
inputValue: dom.text(),
|
||||
showCancelButton: true
|
||||
}).then(uid => {
|
||||
owner = uid;
|
||||
|
||||
return fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/players?action=owner'),
|
||||
dataType: 'json',
|
||||
data: { pid: pid, uid: uid }
|
||||
});
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
dom.text(owner);
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
|
||||
$('.swal2-input').on('input', debounce(() => {
|
||||
let uid = $('.swal2-input').val();
|
||||
|
||||
if (isNaN(uid) || uid <= 0)
|
||||
return;
|
||||
|
||||
fetch({
|
||||
type: 'GET',
|
||||
url: url(`admin/user/${uid}`),
|
||||
dataType: 'json'
|
||||
}).then(result => {
|
||||
$('.swal2-content').html(
|
||||
trans('admin.changePlayerOwner') +
|
||||
'<small style="display: block; margin-top: .5em;">' +
|
||||
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) {
|
||||
swal({
|
||||
text: trans('admin.deletePlayerNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/players?action=delete'),
|
||||
dataType: 'json',
|
||||
data: { pid: pid }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
$(`tr#${pid}`).remove();
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
55
resources/assets/src/js/admin/plugins.js
Normal file
55
resources/assets/src/js/admin/plugins.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* exported enablePlugin, disablePlugin, deletePlugin */
|
||||
|
||||
'use strict';
|
||||
|
||||
function enablePlugin(name) {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url(`admin/plugins?action=enable&name=${name}`),
|
||||
dataType: 'json'
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
toastr.success(msg);
|
||||
|
||||
$.pluginsTable.ajax.reload(null, false);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function disablePlugin(name) {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url(`admin/plugins?action=disable&name=${name}`),
|
||||
dataType: 'json'
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
toastr.warning(msg);
|
||||
|
||||
$.pluginsTable.ajax.reload(null, false);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function deletePlugin(name) {
|
||||
swal({
|
||||
text: trans('admin.confirmDeletion'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url(`admin/plugins?action=delete&name=${name}`),
|
||||
dataType: 'json'
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
toastr.success(msg);
|
||||
|
||||
$.pluginsTable.ajax.reload(null, false);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
272
resources/assets/src/js/admin/tables.js
Normal file
272
resources/assets/src/js/admin/tables.js
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/* exported initUsersTable, initPlayersTable, initPluginsTable */
|
||||
|
||||
'use strict';
|
||||
|
||||
function initUsersTable() {
|
||||
let uid = getQueryString('uid');
|
||||
let dataUrl = url('admin/user-data') + (uid ? `?uid=${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',
|
||||
className: 'status',
|
||||
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 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 uid = getQueryString('uid');
|
||||
let dataUrl = url('admin/player-data') + (uid ? `?uid=${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;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
91
resources/assets/src/js/admin/update.js
Normal file
91
resources/assets/src/js/admin/update.js
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* exported downloadUpdates */
|
||||
|
||||
'use strict';
|
||||
|
||||
function downloadUpdates() {
|
||||
var fileSize = 0;
|
||||
var progress = 0;
|
||||
|
||||
console.log('Prepare to download');
|
||||
|
||||
fetch({
|
||||
url: url('admin/update/download?action=prepare-download'),
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
$('#update-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('admin.preparing')
|
||||
).prop('disabled', 'disabled');
|
||||
}
|
||||
}).then(json => {
|
||||
console.log(json);
|
||||
|
||||
fileSize = json.file_size;
|
||||
|
||||
$('#file-size').html(fileSize);
|
||||
|
||||
$('#modal-start-download').modal({
|
||||
'backdrop': 'static',
|
||||
'keyboard': false
|
||||
});
|
||||
|
||||
console.log('Start downloading');
|
||||
|
||||
fetch({
|
||||
url: url('admin/update/download?action=start-download'),
|
||||
type: 'POST',
|
||||
dataType: 'json'
|
||||
}).then(json => {
|
||||
// Set progress to 100 when got the response
|
||||
progress = 100;
|
||||
|
||||
console.log('Downloading finished');
|
||||
console.log(json);
|
||||
}).catch(err => showAjaxError(err));
|
||||
|
||||
// Downloading progress polling
|
||||
let interval_id = window.setInterval(() => {
|
||||
$('#imported-progress').html(progress);
|
||||
$('.progress-bar').css('width', progress+'%').attr('aria-valuenow', progress);
|
||||
|
||||
if (progress == 100) {
|
||||
clearInterval(interval_id);
|
||||
|
||||
$('.modal-title').html('<i class="fa fa-spinner fa-spin"></i> ' + trans('admin.extracting'));
|
||||
$('.modal-body').append(`<p>${ trans('admin.downloadCompleted') }</p>`);
|
||||
|
||||
console.log('Start extracting');
|
||||
|
||||
fetch({
|
||||
url: url('admin/update/download?action=extract'),
|
||||
type: 'POST',
|
||||
dataType: 'json'
|
||||
}).then(json => {
|
||||
console.log('Package extracted and files are covered');
|
||||
$('#modal-start-download').modal('toggle');
|
||||
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(function() {
|
||||
window.location = url('/');
|
||||
}, function() {
|
||||
window.location = url('/');
|
||||
});
|
||||
}).catch(err => showAjaxError(err));
|
||||
|
||||
} else {
|
||||
fetch({
|
||||
url: url('admin/update/download?action=get-file-size'),
|
||||
type: 'GET'
|
||||
}).then(json => {
|
||||
progress = (json.size / fileSize * 100).toFixed(2);
|
||||
|
||||
console.log('Progress: ' + progress);
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
}, 300);
|
||||
}).catch(err => showAjaxError(err));
|
||||
|
||||
}
|
||||
169
resources/assets/src/js/admin/users.js
Normal file
169
resources/assets/src/js/admin/users.js
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/* exported changeUserEmail, changeUserNickName, changeUserPwd,
|
||||
changeBanStatus, changeAdminStatus, deleteUserAccount */
|
||||
|
||||
'use strict';
|
||||
|
||||
function changeUserEmail(uid) {
|
||||
let dom = $(`tr#user-${uid} > td:nth-child(2)`),
|
||||
newUserEmail = '';
|
||||
|
||||
swal({
|
||||
text: trans('admin.newUserEmail'),
|
||||
showCancelButton: true,
|
||||
input: 'text',
|
||||
inputValue: dom.text(),
|
||||
inputValidator: value => (new Promise((resolve, reject) => {
|
||||
(newUserEmail = value) ? resolve() : reject(trans('auth.emptyEmail'));
|
||||
}))
|
||||
}).then(email => fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/users?action=email'),
|
||||
dataType: 'json',
|
||||
data: { uid: uid, email: email }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
dom.text(newUserEmail);
|
||||
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeUserNickName(uid) {
|
||||
let dom = $(`tr#user-${uid} > td:nth-child(3)`),
|
||||
newNickName = '';
|
||||
|
||||
swal({
|
||||
text: trans('admin.newUserNickname'),
|
||||
showCancelButton: true,
|
||||
input: 'text',
|
||||
inputValue: dom.text(),
|
||||
inputValidator: value => (new Promise((resolve, reject) => {
|
||||
(newNickName = value) ? resolve() : reject(trans('auth.emptyNickname'));
|
||||
}))
|
||||
}).then(nickname => fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/users?action=nickname'),
|
||||
dataType: 'json',
|
||||
data: { uid: uid, nickname: nickname }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
dom.text(newNickName);
|
||||
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeUserPwd(uid) {
|
||||
swal({
|
||||
text: trans('admin.newUserPassword'),
|
||||
showCancelButton: true,
|
||||
input: 'password',
|
||||
}).then(password => fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/users?action=password'),
|
||||
dataType: 'json',
|
||||
data: { uid: uid, password: password }
|
||||
})).then(({ errno, msg }) => {
|
||||
(errno == 0) ? toastr.success(msg) : toastr.warning(msg);
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeUserScore(uid, score) {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/users?action=score'),
|
||||
dataType: 'json',
|
||||
// Handle id formatted as '#user-1234'
|
||||
data: { uid: uid.slice(5), score: score }
|
||||
}).then(({ errno, msg }) => {
|
||||
(errno == 0) ? toastr.success(msg) : toastr.warning(msg);
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeBanStatus(uid) {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/users?action=ban'),
|
||||
dataType: 'json',
|
||||
data: { uid: uid }
|
||||
}).then(({ errno, msg, permission }) => {
|
||||
if (errno == 0) {
|
||||
let dom = $(`#ban-${uid}`);
|
||||
|
||||
if (dom.attr('data') == 'banned') {
|
||||
dom.text(trans('admin.ban')).attr('data', 'normal');
|
||||
} else {
|
||||
dom.text(trans('admin.unban')).attr('data', 'banned');
|
||||
}
|
||||
|
||||
$(`#user-${uid} > td.status`).text(
|
||||
permission == -1 ? trans('admin.banned') : trans('admin.normal')
|
||||
);
|
||||
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeAdminStatus(uid) {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/users?action=admin'),
|
||||
dataType: 'json',
|
||||
data: { uid: uid }
|
||||
}).then(({ errno, msg, permission }) => {
|
||||
if (errno == 0) {
|
||||
let dom = $(`#admin-${uid}`);
|
||||
|
||||
if (dom.attr('data') == 'admin') {
|
||||
dom.text(trans('admin.setAdmin')).attr('data', 'normal');
|
||||
} else {
|
||||
dom.text(trans('admin.unsetAdmin')).attr('data', 'admin');
|
||||
}
|
||||
|
||||
$(`#user-${uid} > td.status`).text(
|
||||
(permission == 1) ? trans('admin.admin') : trans('admin.normal')
|
||||
);
|
||||
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function deleteUserAccount(uid) {
|
||||
swal({
|
||||
text: trans('admin.deleteUserNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('admin/users?action=delete'),
|
||||
dataType: 'json',
|
||||
data: { uid: uid }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
$('tr#user-' + uid).remove();
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
$('body').on('keypress', '.score', function(event){
|
||||
// Change score when Enter key is pressed
|
||||
if (event.which == 13) {
|
||||
$(this).blur();
|
||||
changeUserScore($(this).parent().parent().attr('id'), $(this).val());
|
||||
}
|
||||
});
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
$(document).ready(() => $('input').iCheck({
|
||||
checkboxClass: 'icheckbox_square-blue'
|
||||
}));
|
||||
|
||||
function freshCaptcha() {
|
||||
$('.captcha').attr('src', './captcha?' + new Date().getTime());
|
||||
$('#captcha').val('');
|
||||
}
|
||||
|
||||
var login_fails = 0;
|
||||
|
||||
$('#login-button').click(function () {
|
||||
var data = new Object();
|
||||
|
||||
data.identification = $('#identification').val();
|
||||
data.password = $('#password').val();
|
||||
data.keep = $('#keep').prop('checked') ? true : false;
|
||||
|
||||
if (data.identification == "") {
|
||||
showMsg(trans('auth.emptyIdentification'));
|
||||
$('#identification').focus();
|
||||
} else if (data.password == "") {
|
||||
showMsg(trans('auth.emptyPassword'));
|
||||
$('#password').focus();
|
||||
} else {
|
||||
// if captcha form is shown
|
||||
if ($('#captcha-form').css('display') == "block") {
|
||||
data.captcha = $("#captcha").val();
|
||||
if (data.captcha == "") {
|
||||
showMsg(trans('auth.emptyCaptcha'));
|
||||
$('#captcha').focus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./login",
|
||||
dataType: "json",
|
||||
data: data,
|
||||
beforeSend: () => {
|
||||
$('#login-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('auth.loggingIn')
|
||||
).prop('disabled', 'disabled');
|
||||
},
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
|
||||
// redirect to last requested path
|
||||
let redirect_to = url(blessing.redirect_to || "user");
|
||||
|
||||
window.setTimeout(() => (window.location = redirect_to), 1000);
|
||||
|
||||
} else {
|
||||
if (json.login_fails > 3) {
|
||||
if ($('#captcha-form').css('display') == "none") {
|
||||
swal({
|
||||
type: 'error',
|
||||
html: trans('auth.tooManyFails')
|
||||
});
|
||||
}
|
||||
|
||||
$('#captcha-form').show();
|
||||
}
|
||||
|
||||
freshCaptcha();
|
||||
|
||||
showMsg(json.msg, 'warning');
|
||||
$('#login-button').html(trans('auth.login')).prop('disabled', '');
|
||||
}
|
||||
},
|
||||
error: (json) => {
|
||||
showAjaxError(json);
|
||||
$('#login-button').html(trans('auth.login')).prop('disabled', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.captcha').click(freshCaptcha);
|
||||
|
||||
$('#register-button').click(function () {
|
||||
|
||||
var email = $('#email').val();
|
||||
var password = $('#password').val();
|
||||
var nickname = $('#nickname').val();
|
||||
var captcha = $('#captcha').val();
|
||||
|
||||
// check valid email address
|
||||
if (email == "") {
|
||||
showMsg(trans('auth.emptyEmail'));
|
||||
$('#email').focus();
|
||||
} else if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
showMsg(trans('auth.invalidEmail'), 'warning');
|
||||
} else if (password == "") {
|
||||
showMsg(trans('auth.emptyPassword'));
|
||||
$('#password').focus();
|
||||
} else if (password.length < 8 || password.length > 16) {
|
||||
showMsg(trans('auth.invalidPassword'), 'warning');
|
||||
$('#password').focus();
|
||||
} else if ($('#confirm-pwd').val() == "") {
|
||||
showMsg(trans('auth.emptyConfirmPwd'));
|
||||
$('#confirm-pwd').focus();
|
||||
} else if (password != $('#confirm-pwd').val()) {
|
||||
showMsg(trans('auth.invalidConfirmPwd'), 'warning');
|
||||
$('#confirm-pwd').focus();
|
||||
} else if (nickname == "") {
|
||||
showMsg(trans('auth.emptyNickname'));
|
||||
$('#nickname').focus();
|
||||
} else if (captcha == "") {
|
||||
showMsg(trans('auth.emptyCaptcha'));
|
||||
$('#captcha').focus();
|
||||
} else {
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./register",
|
||||
dataType: "json",
|
||||
data: { 'email': email, 'password': password, 'nickname': nickname, 'captcha': captcha },
|
||||
beforeSend: function () {
|
||||
$('#register-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('auth.registering')
|
||||
).prop('disabled', 'disabled');
|
||||
},
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
window.setTimeout('window.location = "../user"', 1000);
|
||||
} else {
|
||||
showMsg(json.msg, 'warning');
|
||||
freshCaptcha();
|
||||
$('#register-button').html(trans('auth.register')).prop('disabled', '');
|
||||
}
|
||||
},
|
||||
error: (json) => {
|
||||
showAjaxError(json);
|
||||
$('#register-button').html(trans('auth.register')).prop('disabled', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
||||
});
|
||||
|
||||
$('#forgot-button').click(function () {
|
||||
|
||||
var email = $('#email').val();
|
||||
var captcha = $('#captcha').val();
|
||||
|
||||
// check valid email address
|
||||
if (email == "") {
|
||||
showMsg(trans('auth.emptyEmail'));
|
||||
$('#email').focus();
|
||||
} else if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
showMsg(trans('auth.invalidEmail'), 'warning');
|
||||
} else if (captcha == "") {
|
||||
showMsg(trans('auth.emptyCaptcha'));
|
||||
$('#captcha').focus();
|
||||
} else {
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./forgot",
|
||||
dataType: "json",
|
||||
data: { 'email': email, 'captcha': captcha },
|
||||
beforeSend: () => {
|
||||
$('#forgot-button').html('<i class="fa fa-spinner fa-spin"></i> '+trans('auth.sending')).prop('disabled', 'disabled');
|
||||
},
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
showMsg(json.msg, 'success');
|
||||
$('#forgot-button').html(trans('auth.send')).prop('disabled', 'disabled');
|
||||
} else {
|
||||
showMsg(json.msg, 'warning');
|
||||
freshCaptcha();
|
||||
$('#forgot-button').html(trans('auth.send')).prop('disabled', '');
|
||||
}
|
||||
},
|
||||
error: (json) => {
|
||||
showAjaxError(json);
|
||||
$('#forgot-button').html(trans('auth.send')).prop('disabled', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
|
||||
});
|
||||
|
||||
$('#reset-button').click(function () {
|
||||
var uid = $('#uid').val();
|
||||
var password = $('#password').val();
|
||||
|
||||
if (password == "") {
|
||||
showMsg(trans('auth.emptyPassword'));
|
||||
$('#password').focus();
|
||||
} else if (password.length < 8 || password.length > 16) {
|
||||
showMsg(trans('auth.invalidPassword'), 'warning');
|
||||
$('#password').focus();
|
||||
} else if ($('#confirm-pwd').val() == "") {
|
||||
showMsg(trans('auth.emptyConfirmPwd'));
|
||||
$('#confirm-pwd').focus();
|
||||
} else if (password != $('#confirm-pwd').val()) {
|
||||
showMsg(trans('auth.invalidConfirmPwd'), 'warning');
|
||||
$('#confirm-pwd').focus();
|
||||
} else {
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./reset",
|
||||
dataType: "json",
|
||||
data: { 'uid': uid, 'password': password },
|
||||
beforeSend: () => {
|
||||
$('#reset-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('auth.resetting')
|
||||
).prop('disabled', 'disabled');
|
||||
},
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(() => (window.location = "./login"));
|
||||
} else {
|
||||
showMsg(json.msg, 'warning');
|
||||
$('#reset-button').html(trans('auth.reset')).prop('disabled', '');
|
||||
}
|
||||
},
|
||||
error: (json) => {
|
||||
showAjaxError(json);
|
||||
$('#reset-button').html(trans('auth.reset')).prop('disabled', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
11
resources/assets/src/js/auth/captcha.js
Normal file
11
resources/assets/src/js/auth/captcha.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
function refreshCaptcha() {
|
||||
let timestamp = new Date().getTime();
|
||||
// Refresh Captcha Image
|
||||
$('.captcha').attr('src', url(`auth/captcha?${timestamp}`));
|
||||
// Clear input
|
||||
$('#captcha').val('');
|
||||
}
|
||||
|
||||
$('.captcha').click(refreshCaptcha);
|
||||
66
resources/assets/src/js/auth/login.js
Normal file
66
resources/assets/src/js/auth/login.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* global refreshCaptcha */
|
||||
|
||||
'use strict';
|
||||
|
||||
$('#login-button').click(() => {
|
||||
let data = {
|
||||
identification: $('#identification').val(),
|
||||
password: $('#password').val(),
|
||||
keep: $('#keep').prop('checked') ? true : false
|
||||
};
|
||||
|
||||
if (data.identification == '') {
|
||||
showMsg(trans('auth.emptyIdentification'));
|
||||
$('#identification').focus();
|
||||
} else if (data.password == '') {
|
||||
showMsg(trans('auth.emptyPassword'));
|
||||
$('#password').focus();
|
||||
} else {
|
||||
// Verify it when captcha form is shown
|
||||
if ($('#captcha-form').css('display') == 'block') {
|
||||
data.captcha = $('#captcha').val();
|
||||
|
||||
if (data.captcha == '') {
|
||||
showMsg(trans('auth.emptyCaptcha'));
|
||||
$('#captcha').focus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('auth/login'),
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
beforeSend: () => {
|
||||
$('#login-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('auth.loggingIn')
|
||||
).prop('disabled', 'disabled');
|
||||
}
|
||||
}).then(({ errno, msg, login_fails }) => {
|
||||
if (errno == 0) {
|
||||
swal({ type: 'success', html: msg });
|
||||
|
||||
window.setTimeout(() => {
|
||||
window.location = url(blessing.redirect_to || 'user');
|
||||
}, 1000);
|
||||
} else {
|
||||
if (login_fails > 3) {
|
||||
if ($('#captcha-form').css('display') == 'none') {
|
||||
swal({ type: 'error', html: trans('auth.tooManyFails') });
|
||||
|
||||
$('#captcha-form').show();
|
||||
}
|
||||
}
|
||||
|
||||
refreshCaptcha();
|
||||
|
||||
showMsg(msg, 'warning');
|
||||
$('#login-button').html(trans('auth.login')).prop('disabled', '');
|
||||
}
|
||||
}).catch(err => {
|
||||
showAjaxError(err);
|
||||
$('#login-button').html(trans('auth.login')).prop('disabled', '');
|
||||
});
|
||||
}
|
||||
});
|
||||
71
resources/assets/src/js/auth/register.js
Normal file
71
resources/assets/src/js/auth/register.js
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/* global refreshCaptcha */
|
||||
|
||||
'use strict';
|
||||
|
||||
$('#register-button').click(() => {
|
||||
let data = {
|
||||
email: $('#email').val(),
|
||||
password: $('#password').val(),
|
||||
nickname: $('#nickname').val(),
|
||||
captcha: $('#captcha').val()
|
||||
};
|
||||
|
||||
(function validate({ email, password, nickname, captcha }, callback) {
|
||||
// Massive form validation
|
||||
if (email == '') {
|
||||
showMsg(trans('auth.emptyEmail'));
|
||||
$('#email').focus();
|
||||
} else if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
showMsg(trans('auth.invalidEmail'), 'warning');
|
||||
} else if (password == '') {
|
||||
showMsg(trans('auth.emptyPassword'));
|
||||
$('#password').focus();
|
||||
} else if (password.length < 8 || password.length > 16) {
|
||||
showMsg(trans('auth.invalidPassword'), 'warning');
|
||||
$('#password').focus();
|
||||
} else if ($('#confirm-pwd').val() == '') {
|
||||
showMsg(trans('auth.emptyConfirmPwd'));
|
||||
$('#confirm-pwd').focus();
|
||||
} else if (password != $('#confirm-pwd').val()) {
|
||||
showMsg(trans('auth.invalidConfirmPwd'), 'warning');
|
||||
$('#confirm-pwd').focus();
|
||||
} else if (nickname == '') {
|
||||
showMsg(trans('auth.emptyNickname'));
|
||||
$('#nickname').focus();
|
||||
} else if (captcha == '') {
|
||||
showMsg(trans('auth.emptyCaptcha'));
|
||||
$('#captcha').focus();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
||||
return;
|
||||
})(data, () => {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('auth/register'),
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
beforeSend: function () {
|
||||
$('#register-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('auth.registering')
|
||||
).prop('disabled', 'disabled');
|
||||
}
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
swal({ type: 'success', html: msg });
|
||||
|
||||
window.setTimeout(() => {
|
||||
window.location = url('user');
|
||||
}, 1000);
|
||||
} else {
|
||||
showMsg(msg, 'warning');
|
||||
refreshCaptcha();
|
||||
$('#register-button').html(trans('auth.register')).prop('disabled', '');
|
||||
}
|
||||
}).catch(err => {
|
||||
showAjaxError(err);
|
||||
$('#register-button').html(trans('auth.register')).prop('disabled', '');
|
||||
});
|
||||
});
|
||||
});
|
||||
98
resources/assets/src/js/auth/reset.js
Normal file
98
resources/assets/src/js/auth/reset.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* global refreshCaptcha */
|
||||
|
||||
'use strict';
|
||||
|
||||
$('#forgot-button').click(() => {
|
||||
let data = {
|
||||
email: $('#email').val(),
|
||||
captcha: $('#captcha').val()
|
||||
};
|
||||
|
||||
(function validate({ email, captcha }, callback) {
|
||||
if (email == '') {
|
||||
showMsg(trans('auth.emptyEmail'));
|
||||
$('#email').focus();
|
||||
} else if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
showMsg(trans('auth.invalidEmail'), 'warning');
|
||||
} else if (captcha == '') {
|
||||
showMsg(trans('auth.emptyCaptcha'));
|
||||
$('#captcha').focus();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})(data, () => {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('auth/forgot'),
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
beforeSend: () => {
|
||||
$('#forgot-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('auth.sending')
|
||||
).prop('disabled', 'disabled');
|
||||
}
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
showMsg(msg, 'success');
|
||||
$('#forgot-button').html(trans('auth.send')).prop('disabled', 'disabled');
|
||||
} else {
|
||||
showMsg(msg, 'warning');
|
||||
refreshCaptcha();
|
||||
$('#forgot-button').html(trans('auth.send')).prop('disabled', '');
|
||||
}
|
||||
}).catch(err => {
|
||||
showAjaxError(err);
|
||||
$('#forgot-button').html(trans('auth.send')).prop('disabled', '');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$('#reset-button').click(() => {
|
||||
let data = {
|
||||
uid: $('#uid').val(),
|
||||
password: $('#password').val()
|
||||
};
|
||||
|
||||
(function validate({ password }, callback) {
|
||||
if (password == '') {
|
||||
showMsg(trans('auth.emptyPassword'));
|
||||
$('#password').focus();
|
||||
} else if (password.length < 8 || password.length > 16) {
|
||||
showMsg(trans('auth.invalidPassword'), 'warning');
|
||||
$('#password').focus();
|
||||
} else if ($('#confirm-pwd').val() == '') {
|
||||
showMsg(trans('auth.emptyConfirmPwd'));
|
||||
$('#confirm-pwd').focus();
|
||||
} else if (password != $('#confirm-pwd').val()) {
|
||||
showMsg(trans('auth.invalidConfirmPwd'), 'warning');
|
||||
$('#confirm-pwd').focus();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})(data, () => {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('auth/reset'),
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
beforeSend: () => {
|
||||
$('#reset-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('auth.resetting')
|
||||
).prop('disabled', 'disabled');
|
||||
}
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: msg
|
||||
}).then(() => (window.location = url('auth/login')));
|
||||
} else {
|
||||
showMsg(msg, 'warning');
|
||||
$('#reset-button').html(trans('auth.reset')).prop('disabled', '');
|
||||
}
|
||||
}).catch(err => {
|
||||
showAjaxError(err);
|
||||
$('#reset-button').html(trans('auth.reset')).prop('disabled', '');
|
||||
});
|
||||
});
|
||||
});
|
||||
51
resources/assets/src/js/common/i18n.js
Normal file
51
resources/assets/src/js/common/i18n.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* exported trans */
|
||||
|
||||
'use strict';
|
||||
|
||||
$.locales = {};
|
||||
$.currentLocale = {};
|
||||
|
||||
/**
|
||||
* Load current selected language.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function loadLocales() {
|
||||
for (let lang in $.locales) {
|
||||
if (!isEmpty($.locales[lang])) {
|
||||
$.currentLocale = $.locales[lang] || {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate according to given key.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {dict} parameters
|
||||
* @return {string}
|
||||
*/
|
||||
function trans(key, parameters = {}) {
|
||||
if (isEmpty($.currentLocale)) {
|
||||
loadLocales();
|
||||
}
|
||||
|
||||
let segments = key.split('.');
|
||||
let temp = $.currentLocale || {};
|
||||
|
||||
for (let i in segments) {
|
||||
if (isEmpty(temp[segments[i]])) {
|
||||
return key;
|
||||
} else {
|
||||
temp = temp[segments[i]];
|
||||
}
|
||||
}
|
||||
|
||||
for (let i in parameters) {
|
||||
if (!isEmpty(parameters[i])) {
|
||||
temp = temp.replace(':'+i, parameters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
36
resources/assets/src/js/common/layout.js
Normal file
36
resources/assets/src/js/common/layout.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
$.defaultPaginatorConfig = {
|
||||
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>'
|
||||
};
|
||||
|
||||
$(window).resize(activateLayout);
|
||||
|
||||
$(document).ready(() => {
|
||||
activateLayout();
|
||||
|
||||
$('li.active > ul').show();
|
||||
|
||||
$('input').iCheck({
|
||||
checkboxClass: 'icheckbox_square-blue'
|
||||
});
|
||||
|
||||
swal.setDefaults({
|
||||
confirmButtonText: trans('general.confirm'),
|
||||
cancelButtonText: trans('general.cancel')
|
||||
});
|
||||
});
|
||||
|
||||
function activateLayout() {
|
||||
if (location.pathname == '/' || location.pathname.includes('auth'))
|
||||
return;
|
||||
|
||||
$.AdminLTE.layout.activate();
|
||||
}
|
||||
29
resources/assets/src/js/common/logout.js
Normal file
29
resources/assets/src/js/common/logout.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
function confirmLogout() {
|
||||
swal({
|
||||
text: trans('general.confirmLogout'),
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: trans('general.confirm'),
|
||||
cancelButtonText: trans('general.cancel')
|
||||
}).then(() => {
|
||||
logout().then(json => {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
window.setTimeout(() => window.location = url(), 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function logout() {
|
||||
return fetch({
|
||||
type: 'POST',
|
||||
url: url('auth/logout'),
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
|
||||
$('#logout-button').click(() => confirmLogout());
|
||||
59
resources/assets/src/js/common/notify.js
Normal file
59
resources/assets/src/js/common/notify.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* exported showMsg, showAjaxError, showModal */
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Show message to div#msg with level
|
||||
*
|
||||
* @param {string} msg
|
||||
* @param {string} type
|
||||
* @return {void}
|
||||
*/
|
||||
function showMsg(msg, type = 'info') {
|
||||
$('[id=msg]').removeClass().addClass('callout').addClass(`callout-${type}`).html(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show modal if error occured when sending an ajax request.
|
||||
*
|
||||
* @param {object} json
|
||||
* @return {void}
|
||||
*/
|
||||
function showAjaxError(json) {
|
||||
if (typeof json == 'string') {
|
||||
return console.warn(json);
|
||||
}
|
||||
|
||||
if (! json.responseText) {
|
||||
return console.warn('Empty Ajax response body.');
|
||||
}
|
||||
|
||||
showModal(json.responseText.replace(/\n/g, '<br />'), trans('general.fatalError'), 'danger');
|
||||
}
|
||||
|
||||
function showModal(msg, title = 'Message', type = 'default', options = {}) {
|
||||
let btnType = (type != 'default') ? 'btn-outline' : 'btn-primary';
|
||||
let onClick = (options.callback === undefined) ? 'data-dismiss="modal"' : `onclick="${options.callback}"`;
|
||||
|
||||
let dom = `
|
||||
<div class="modal modal-${type} fade in">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">${title}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>${msg}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" ${onClick} class="btn ${btnType}">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
$(dom).modal(options);
|
||||
}
|
||||
30
resources/assets/src/js/common/polyfill.js
Normal file
30
resources/assets/src/js/common/polyfill.js
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
'use strict';
|
||||
|
||||
// polyfill of String.prototype.includes
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function(search, start) {
|
||||
'use strict';
|
||||
if (typeof start !== 'number') {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (start + search.length > this.length) {
|
||||
return false;
|
||||
} else {
|
||||
return this.indexOf(search, start) !== -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// polyfill of String.prototype.endsWith
|
||||
if (!String.prototype.endsWith) {
|
||||
String.prototype.endsWith = function (searchString, position) {
|
||||
var subjectString = this.toString();
|
||||
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
|
||||
position = subjectString.length;
|
||||
}
|
||||
position -= searchString.length;
|
||||
var lastIndex = subjectString.lastIndexOf(searchString, position);
|
||||
return lastIndex !== -1 && lastIndex === position;
|
||||
};
|
||||
}
|
||||
100
resources/assets/src/js/common/texture-preview.js
Normal file
100
resources/assets/src/js/common/texture-preview.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* global MSP */
|
||||
/* exported TexturePreview */
|
||||
|
||||
class TexturePreview {
|
||||
constructor(type, tid, preference) {
|
||||
this.tid = tid;
|
||||
this.type = type;
|
||||
this.selector = $(`#${type}`);
|
||||
this.preference = (type == 'steve') ? 'default' : 'slim';
|
||||
this.playerPreference = preference;
|
||||
}
|
||||
|
||||
change2dPreview() {
|
||||
this.selector
|
||||
.attr('src', url(`preview/200/${this.tid}.png`))
|
||||
.show()
|
||||
.parent().attr('href', url(`skinlib/show/${this.tid}`))
|
||||
.next().hide();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
change3dPreview() {
|
||||
if (this.playerPreference == this.preference || this.type == 'cape') {
|
||||
fetch({
|
||||
type: 'GET',
|
||||
url: url(`skinlib/info/${this.tid}`),
|
||||
dataType: 'json'
|
||||
}).then(({ hash }) => {
|
||||
let textureUrl = url(`textures/${hash}`);
|
||||
|
||||
if (this.type == 'cape') {
|
||||
MSP.changeCape(textureUrl);
|
||||
} else {
|
||||
MSP.changeSkin(textureUrl);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
showNotUploaded() {
|
||||
this.selector.hide().parent().next().show();
|
||||
|
||||
// clear 3D preview of cape
|
||||
if (this.type == 'cape') {
|
||||
MSP.changeCape('');
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
TexturePreview.previewType = '3D';
|
||||
|
||||
TexturePreview.init3dPreview = () => {
|
||||
if (TexturePreview.previewType == '2D') return;
|
||||
|
||||
$('#preview-2d').hide();
|
||||
|
||||
let canvas = null;
|
||||
|
||||
if ($(window).width() < 800) {
|
||||
canvas = MSP.get3dSkinCanvas($('#skinpreview').width(), $('#skinpreview').width());
|
||||
$('#skinpreview').append($(canvas).prop('id', 'canvas3d'));
|
||||
} else {
|
||||
canvas = MSP.get3dSkinCanvas(350, 350);
|
||||
$('#skinpreview').append($(canvas).prop('id', 'canvas3d'));
|
||||
}
|
||||
};
|
||||
|
||||
TexturePreview.show3dPreview = () => {
|
||||
TexturePreview.previewType = '3D';
|
||||
|
||||
TexturePreview.init3dPreview();
|
||||
$('#preview-2d').hide();
|
||||
$('.operations').show();
|
||||
$('#preview-switch').html(trans('user.switch2dPreview'));
|
||||
};
|
||||
|
||||
TexturePreview.show2dPreview = () => {
|
||||
TexturePreview.previewType = '2D';
|
||||
|
||||
$('#canvas3d').remove();
|
||||
$('.operations').hide();
|
||||
$('#preview-2d').show();
|
||||
$('#preview-switch').html(trans('user.switch3dPreview')).attr('onclick', 'show3dPreview();');
|
||||
};
|
||||
|
||||
// change 3D preview status
|
||||
$('.fa-pause').click(function () {
|
||||
MSP.setStatus('rotation', ! MSP.getStatus('rotation'));
|
||||
MSP.setStatus('movements', ! MSP.getStatus('movements'));
|
||||
|
||||
$(this).toggleClass('fa-pause').toggleClass('fa-play');
|
||||
});
|
||||
|
||||
$('.fa-forward').click(() => MSP.setStatus('running', ! MSP.getStatus('running')));
|
||||
$('.fa-repeat' ).click(() => MSP.setStatus('rotation', ! MSP.getStatus('rotation')));
|
||||
98
resources/assets/src/js/common/utils.js
Normal file
98
resources/assets/src/js/common/utils.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* exported isEmpty, fetch, getQueryString, debounce, url */
|
||||
|
||||
'use strict';
|
||||
|
||||
console.log(`\n %c Blessing Skin v${blessing.version} %c https://blessing.studio \n\n`, 'color: #fadfa3; background: #030307; padding:5px 0;', 'background: #fadfa3; padding:5px 0;');
|
||||
|
||||
/**
|
||||
* Check if given value is empty.
|
||||
*
|
||||
* @param {any} obj
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isEmpty(obj) {
|
||||
|
||||
// null and undefined are "empty"
|
||||
if (obj == null) return true;
|
||||
|
||||
if (typeof (obj) == 'number' || typeof (obj) == 'boolean') return false;
|
||||
|
||||
// Assume if it has a length property with a non-zero value
|
||||
// that that property is correct.
|
||||
if (obj.length > 0) return false;
|
||||
if (obj.length === 0) return true;
|
||||
|
||||
// If it isn't an object at this point
|
||||
// it is empty, but it can't be anything *but* empty
|
||||
// Is it empty? Depends on your application.
|
||||
if (typeof obj !== 'object') return true;
|
||||
|
||||
// Otherwise, does it have any properties of its own?
|
||||
// Note that this doesn't handle
|
||||
// toString and valueOf enumeration bugs in IE < 9
|
||||
for (var key in obj) {
|
||||
if (hasOwnProperty.call(obj, key)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A fake fetch API. Returns Promises.
|
||||
*
|
||||
* @param {array} option Same as options of jQuery.ajax()
|
||||
* @return {Promise}
|
||||
*/
|
||||
function fetch(option) {
|
||||
return Promise.resolve($.ajax(option));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parameters in query string with key.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {string} defaultValue
|
||||
* @return {string}
|
||||
*/
|
||||
function getQueryString(key, defaultValue) {
|
||||
let result = location.search.match(new RegExp('[?&]'+key+'=([^&]+)','i'));
|
||||
|
||||
if (result == null || result.length < 1){
|
||||
return defaultValue;
|
||||
} else {
|
||||
return result[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
}
|
||||
|
||||
function url(relativeUri) {
|
||||
relativeUri = relativeUri || '';
|
||||
blessing.base_url = blessing.base_url || '';
|
||||
|
||||
if (relativeUri[0] != '/') {
|
||||
relativeUri = '/' + relativeUri;
|
||||
}
|
||||
|
||||
return blessing.base_url + relativeUri;
|
||||
}
|
||||
|
|
@ -1,384 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
console.log(`\n %c Blessing Skin v${blessing.version} %c https://blessing.studio \n\n`,"color: #fadfa3; background: #030307; padding:5px 0;","background: #fadfa3; padding:5px 0;");
|
||||
|
||||
$.locales = {};
|
||||
$.currentLocale = {};
|
||||
|
||||
$.defaultPaginatorConfig = {
|
||||
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>'
|
||||
};
|
||||
|
||||
// polyfill of String.prototype.includes
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function(search, start) {
|
||||
'use strict';
|
||||
if (typeof start !== 'number') {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (start + search.length > this.length) {
|
||||
return false;
|
||||
} else {
|
||||
return this.indexOf(search, start) !== -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// polyfill of String.prototype.endsWith
|
||||
if (!String.prototype.endsWith) {
|
||||
String.prototype.endsWith = function (searchString, position) {
|
||||
var subjectString = this.toString();
|
||||
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
|
||||
position = subjectString.length;
|
||||
}
|
||||
position -= searchString.length;
|
||||
var lastIndex = subjectString.lastIndexOf(searchString, position);
|
||||
return lastIndex !== -1 && lastIndex === position;
|
||||
};
|
||||
}
|
||||
|
||||
$(window).ready(activateLayout).resize(activateLayout);
|
||||
|
||||
function activateLayout() {
|
||||
if (location.pathname == "/" || location.pathname.includes('auth'))
|
||||
return;
|
||||
|
||||
$.AdminLTE.layout.activate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given value is empty.
|
||||
*
|
||||
* @param {any} obj
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isEmpty(obj) {
|
||||
|
||||
// null and undefined are "empty"
|
||||
if (obj == null) return true;
|
||||
|
||||
if (typeof (obj) == 'number' || typeof (obj) == 'boolean') return false;
|
||||
|
||||
// Assume if it has a length property with a non-zero value
|
||||
// that that property is correct.
|
||||
if (obj.length > 0) return false;
|
||||
if (obj.length === 0) return true;
|
||||
|
||||
// If it isn't an object at this point
|
||||
// it is empty, but it can't be anything *but* empty
|
||||
// Is it empty? Depends on your application.
|
||||
if (typeof obj !== "object") return true;
|
||||
|
||||
// Otherwise, does it have any properties of its own?
|
||||
// Note that this doesn't handle
|
||||
// toString and valueOf enumeration bugs in IE < 9
|
||||
for (var key in obj) {
|
||||
if (hasOwnProperty.call(obj, key)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load current selected language.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function loadLocales() {
|
||||
for (lang in $.locales) {
|
||||
if (!isEmpty($.locales[lang])) {
|
||||
$.currentLocale = $.locales[lang] || {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate according to given key.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {dict} parameters
|
||||
* @return {string}
|
||||
*/
|
||||
function trans(key, parameters = {}) {
|
||||
if (isEmpty($.currentLocale)) {
|
||||
loadLocales();
|
||||
}
|
||||
|
||||
let segments = key.split('.');
|
||||
let temp = $.currentLocale || {};
|
||||
|
||||
for (i in segments) {
|
||||
if (isEmpty(temp[segments[i]])) {
|
||||
return key;
|
||||
} else {
|
||||
temp = temp[segments[i]];
|
||||
}
|
||||
}
|
||||
|
||||
for (i in parameters) {
|
||||
if (!isEmpty(parameters[i])) {
|
||||
temp = temp.replace(':'+i, parameters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
function showModal(msg, title = 'Message', type = 'default', options = {}) {
|
||||
let btnType = (type != "default") ? "btn-outline" : "btn-primary";
|
||||
let onClick = (options.callback === undefined) ? 'data-dismiss="modal"' : `onclick="${options.callback}"`;
|
||||
|
||||
let dom = `
|
||||
<div class="modal modal-${type} fade in">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">${title}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>${msg}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" ${onClick} class="btn ${btnType}">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
$(dom).modal(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show message to div#msg with level
|
||||
*
|
||||
* @param {string} msg
|
||||
* @param {string} type
|
||||
* @return {void}
|
||||
*/
|
||||
function showMsg(msg, type = 'info') {
|
||||
$("[id=msg]").removeClass().addClass("callout").addClass('callout-'+type).html(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show modal if error occured when sending an ajax request.
|
||||
*
|
||||
* @param {object} json
|
||||
* @return {void}
|
||||
*/
|
||||
function showAjaxError(json) {
|
||||
if (!json.responseText) {
|
||||
console.warn('Empty Ajax response body.');
|
||||
return;
|
||||
}
|
||||
|
||||
showModal(json.responseText.replace(/\n/g, '<br />'), trans('general.fatalError'), 'danger');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parameters in query string with key.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {string} defaultValue
|
||||
* @return {string}
|
||||
*/
|
||||
function getQueryString(key, defaultValue) {
|
||||
result = location.search.match(new RegExp('[\?\&]'+key+'=([^\&]+)','i'));
|
||||
|
||||
if (result == null || result.length < 1){
|
||||
return defaultValue;
|
||||
} else {
|
||||
return result[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
function url(relativeUri) {
|
||||
relativeUri = relativeUri || "";
|
||||
blessing.base_url = blessing.base_url || "";
|
||||
|
||||
if (relativeUri[0] != "/") {
|
||||
relativeUri = "/" + relativeUri;
|
||||
}
|
||||
|
||||
return blessing.base_url + relativeUri;
|
||||
}
|
||||
|
||||
function confirmLogout() {
|
||||
swal({
|
||||
text: trans('general.confirmLogout'),
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: trans('general.confirm'),
|
||||
cancelButtonText: trans('general.cancel')
|
||||
}).then(() => {
|
||||
logout().then((json) => {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
window.setTimeout(() => window.location = url(), 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function logout() {
|
||||
return Promise.resolve($.ajax({
|
||||
type: "POST",
|
||||
url: url('auth/logout'),
|
||||
dataType: "json"
|
||||
}));
|
||||
}
|
||||
|
||||
$('#logout-button').click(() => confirmLogout());
|
||||
|
||||
$(document).ready(() => $('li.active > ul').show());
|
||||
|
||||
var TexturePreview = function (type, tid, preference) {
|
||||
this.tid = tid;
|
||||
this.type = type;
|
||||
this.selector = $('#' + type);
|
||||
this.preference = type == 'steve' ? 'default' : 'slim';
|
||||
this.playerPreference = preference;
|
||||
|
||||
this.change2dPreview = function () {
|
||||
this.selector
|
||||
.attr('src', url(`preview/200/${this.tid}.png`))
|
||||
.show()
|
||||
.parent().attr('href', url('skinlib/show/' + this.tid))
|
||||
.next().hide();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
this.change3dPreview = function () {
|
||||
|
||||
if (this.playerPreference == this.preference || this.type == 'cape') {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url(`skinlib/info/${this.tid}`),
|
||||
dataType: "json",
|
||||
success: (json) => {
|
||||
let textureUrl = url('textures/' + json.hash);
|
||||
|
||||
if (this.type == 'cape') {
|
||||
MSP.changeCape(textureUrl);
|
||||
} else {
|
||||
MSP.changeSkin(textureUrl);
|
||||
}
|
||||
},
|
||||
error: (json) => showAjaxError(json)
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
this.showNotUploaded = function () {
|
||||
this.selector.hide().parent().next().show();
|
||||
|
||||
// clear 3D preview of cape
|
||||
if (this.type == 'cape') {
|
||||
MSP.changeCape('');
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
TexturePreview.previewType = '3D';
|
||||
|
||||
TexturePreview.init3dPreview = () => {
|
||||
if (TexturePreview.previewType == '2D') return;
|
||||
|
||||
$('#preview-2d').hide();
|
||||
|
||||
if ($(window).width() < 800) {
|
||||
var canvas = MSP.get3dSkinCanvas($('#skinpreview').width(), $('#skinpreview').width());
|
||||
$("#skinpreview").append($(canvas).prop("id", "canvas3d"));
|
||||
} else {
|
||||
var canvas = MSP.get3dSkinCanvas(350, 350);
|
||||
$("#skinpreview").append($(canvas).prop("id", "canvas3d"));
|
||||
}
|
||||
}
|
||||
|
||||
TexturePreview.show3dPreview = () => {
|
||||
TexturePreview.previewType = "3D";
|
||||
|
||||
TexturePreview.init3dPreview();
|
||||
$('#preview-2d').hide();
|
||||
$('.operations').show();
|
||||
$('#preview-switch').html(trans('user.switch2dPreview'));
|
||||
}
|
||||
|
||||
TexturePreview.show2dPreview = () => {
|
||||
TexturePreview.previewType = '2D';
|
||||
|
||||
$('#canvas3d').remove();
|
||||
$('.operations').hide();
|
||||
$('#preview-2d').show();
|
||||
$('#preview-switch').html(trans('user.switch3dPreview')).attr('onclick', 'show3dPreview();');
|
||||
}
|
||||
|
||||
// change 3D preview status
|
||||
$('.fa-pause').click(function () {
|
||||
MSP.setStatus('rotation', ! MSP.getStatus('rotation'));
|
||||
MSP.setStatus('movements', ! MSP.getStatus('movements'));
|
||||
|
||||
$(this).toggleClass('fa-pause').toggleClass('fa-play');
|
||||
});
|
||||
|
||||
$('.fa-forward').click(() => MSP.setStatus('running', !MSP.getStatus('running')) );
|
||||
$('.fa-repeat' ).click(() => MSP.setStatus('rotation', !MSP.getStatus('rotation')) );
|
||||
|
||||
(function ($) {
|
||||
if ($('#copyright-text').length != 0 && $('#copyright-text').text().indexOf('Blessing') >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'https://work.prinzeugen.net/statistics/whitelist',
|
||||
dataType: 'json',
|
||||
data: { site_name: blessing.site_name, site_url: blessing.base_url }
|
||||
}).done((json) => {
|
||||
if (!json.inWhiteList) {
|
||||
// :(
|
||||
showModal("It looks like that you have removed the program's copyright. It's better for you to restore it ASAP, otherwise something terrible will be applied to your site :)<br><br>If there is a false alarm, please send a mail to h@prinzeugen.net to correct it.", 'CMN BAD ASS', 'danger', {
|
||||
'backdrop': 'static',
|
||||
'keyboard': false
|
||||
});
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
|
|
@ -1,537 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
$(document).ready(() => {
|
||||
swal.setDefaults({
|
||||
confirmButtonText: trans('general.confirm'),
|
||||
cancelButtonText: trans('general.cancel')
|
||||
});
|
||||
|
||||
if ($('#skinlib-container').length != 0) {
|
||||
// Initially render skinlib
|
||||
requestSkinlibData().then(result => {
|
||||
renderSkinlib(result.items);
|
||||
|
||||
updatePaginator(
|
||||
$.skinlib.page,
|
||||
result.total_pages || 1
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#private').on('ifToggled', function () {
|
||||
$(this).prop('checked') ? $('#msg').show() : $('#msg').hide();
|
||||
});
|
||||
$('#type-skin').on('ifToggled', function () {
|
||||
$(this).prop('checked') ? $('#skin-type').show() : $('#skin-type').hide();
|
||||
});
|
||||
|
||||
$.skinlib = {
|
||||
page: getQueryString('page', 1),
|
||||
filter: getQueryString('filter', 'skin'),
|
||||
sort: getQueryString('sort', 'time'),
|
||||
uploader: getQueryString('uploader', 0),
|
||||
keyword: decodeURI(getQueryString('keyword', ''))
|
||||
};
|
||||
|
||||
$(document).ready(() => {
|
||||
|
||||
});
|
||||
|
||||
function renderSkinlib(items) {
|
||||
let container = $('#skinlib-container').html('');
|
||||
|
||||
if (items.length === 0) {
|
||||
$('#skinlib-paginator').hide();
|
||||
|
||||
container.html(`<p style="text-align: center; margin: 30px 0;">
|
||||
${ trans('general.noResult') }
|
||||
</p>`);
|
||||
} else {
|
||||
$('#skinlib-paginator').show();
|
||||
|
||||
for (const item of items) {
|
||||
container.append(renderSkinlibItemComponent(item));
|
||||
}
|
||||
}
|
||||
|
||||
$('.overlay').hide();
|
||||
}
|
||||
|
||||
function reloadSkinlib() {
|
||||
requestSkinlibData().then(result => {
|
||||
$('.overlay').show();
|
||||
renderSkinlib(result.items);
|
||||
|
||||
updatePaginator($.skinlib.page, result.total_pages || 1);
|
||||
}).then(() => {
|
||||
updateUrlQueryString();
|
||||
updateBreadCrumb();
|
||||
});
|
||||
}
|
||||
|
||||
function requestSkinlibData() {
|
||||
return Promise.resolve($.ajax({
|
||||
type: 'GET',
|
||||
url: url('skinlib/data'),
|
||||
dataType: 'json',
|
||||
data: $.skinlib,
|
||||
error: showAjaxError
|
||||
}));
|
||||
}
|
||||
|
||||
function renderSkinlibItemComponent(item) {
|
||||
let title = "";
|
||||
let anonymous = "";
|
||||
let liked = item.liked ? 'liked' : '';
|
||||
|
||||
if (item.liked === undefined) {
|
||||
// If user haven't logged in
|
||||
title = trans('skinlib.anonymous');
|
||||
anonymous = 'anonymous';
|
||||
} else {
|
||||
title = item.liked ? trans('skinlib.removeFromCloset') : trans('skinlib.addToCloset');
|
||||
}
|
||||
|
||||
return `<a href="${ url('skinlib/show/' + item.tid) }">
|
||||
<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>${ trans("skinlib.filter." + item.type) }</small>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<a title="${title}" class="more like ${liked} ${anonymous}" tid="${ item.tid }" href="javascript:;" data-placement="top" data-toggle="tooltip"><i class="fa fa-heart"></i></a>
|
||||
|
||||
<small class="more private-label ${(item.public == 0) ? '' : 'hide'}" tid="${ item.tid }">
|
||||
${ trans('skinlib.private') }
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</a>`;
|
||||
}
|
||||
|
||||
function updatePaginator(currentPage, totalPages) {
|
||||
$.skinlib.page = currentPage;
|
||||
|
||||
$('p.pagination').text(trans('general.pagination', {
|
||||
page: currentPage,
|
||||
total: totalPages
|
||||
}));
|
||||
|
||||
let paginator = $('#skinlib-paginator');
|
||||
|
||||
if (paginator.html().length == 0) {
|
||||
// init paginator
|
||||
$('#skinlib-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
|
||||
currentPage: parseInt(currentPage),
|
||||
totalPages: parseInt(totalPages),
|
||||
onPageChange: onPageChange
|
||||
}));
|
||||
} else {
|
||||
$('#skinlib-paginator').jqPaginator('option', {
|
||||
currentPage: parseInt(currentPage),
|
||||
totalPages: parseInt(totalPages)
|
||||
});
|
||||
}
|
||||
|
||||
let pageSelectElement = $('select.pagination').html('');
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pageSelectElement.append(`
|
||||
<option value="${i}" ${ (i == currentPage) ? 'selected' : '' }>${i}</option>
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
function onPageChange(page, type) {
|
||||
$.skinlib.page = page;
|
||||
updateBreadCrumb();
|
||||
|
||||
if (type == "init") {
|
||||
console.log('Init paginator', page);
|
||||
} else {
|
||||
$('.overlay').show();
|
||||
reloadSkinlib();
|
||||
|
||||
console.log('Rendering page', page);
|
||||
}
|
||||
}
|
||||
|
||||
$('select.pagination').on('change', function () {
|
||||
onPageChange(parseInt($(this).val()));
|
||||
});
|
||||
|
||||
$(document).on('click', '.more.like', function () {
|
||||
let tid = $(this).attr('tid');
|
||||
|
||||
if ($(this).hasClass('anonymous'))
|
||||
return;
|
||||
|
||||
if ($(this).hasClass('liked')) {
|
||||
removeFromCloset(tid);
|
||||
} else {
|
||||
addToCloset(tid);
|
||||
}
|
||||
});
|
||||
|
||||
$('.filter').click(function (e) {
|
||||
e.preventDefault();
|
||||
let selectedFilter = $(this).data('filter');
|
||||
|
||||
if (selectedFilter == "uploader") {
|
||||
$.skinlib.uploader = $(this).data('uid');
|
||||
console.log('Show items uploaded by uid ' + $.skinlib.uploader);
|
||||
} else {
|
||||
$.skinlib.filter = selectedFilter;
|
||||
console.log('Filter by ' + $.skinlib.filter);
|
||||
}
|
||||
|
||||
reloadSkinlib();
|
||||
});
|
||||
|
||||
$('.sort').click(function (e) {
|
||||
e.preventDefault();
|
||||
$.skinlib.sort = $(this).data('sort');
|
||||
|
||||
console.log('Sort by ' + $.skinlib.sort);
|
||||
reloadSkinlib();
|
||||
});
|
||||
|
||||
$('#search-form').submit(function (e) {
|
||||
e.preventDefault();
|
||||
$.skinlib.keyword = $('#navbar-search-input').val();
|
||||
|
||||
console.log('Search keyword: ' + $.skinlib.keyword);
|
||||
reloadSkinlib();
|
||||
});
|
||||
|
||||
function updateUrlQueryString() {
|
||||
let query = $.param($.skinlib);
|
||||
|
||||
window.history.pushState(null, null, url(`skinlib?${query}`));
|
||||
}
|
||||
|
||||
function updateBreadCrumb() {
|
||||
if ($.skinlib.filter == "cape") {
|
||||
$('#filter-indicator').html(trans('general.cape'));
|
||||
} else {
|
||||
$('#filter-indicator').html(trans('general.skin') + `<small>
|
||||
${ trans('skinlib.filter.' + $.skinlib.filter) }
|
||||
</small>`);
|
||||
}
|
||||
|
||||
if ($.skinlib.uploader != 0) {
|
||||
$('#uploader-indicator').html(trans('skinlib.filter.uploader', {uid: $.skinlib.uploader}));
|
||||
} else {
|
||||
$('#uploader-indicator').html(trans('skinlib.filter.allUsers'));
|
||||
}
|
||||
|
||||
$('#sort-indicator').html(trans('skinlib.sort.' + $.skinlib.sort));
|
||||
|
||||
if ($.skinlib.keyword != "") {
|
||||
$('#search-indicator').html(trans('general.searchResult', {
|
||||
keyword: decodeURI($.skinlib.keyword)
|
||||
}));
|
||||
|
||||
$('#navbar-search-input').val(decodeURI($.skinlib.keyword));
|
||||
}
|
||||
}
|
||||
|
||||
function addToCloset(tid) {
|
||||
$.getJSON(url(`skinlib/info/${tid}`), (json) => {
|
||||
swal({
|
||||
title: trans('skinlib.setItemName'),
|
||||
inputValue: json.name,
|
||||
input: 'text',
|
||||
showCancelButton: true,
|
||||
inputValidator: (value) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
value ? resolve() : reject(trans('skinlib.emptyItemName'));
|
||||
});
|
||||
}
|
||||
}).then((result) => ajaxAddToCloset(tid, result));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update button action & likes of texture.
|
||||
*
|
||||
* @param {int} tid
|
||||
* @param {string} action add|remove
|
||||
* @return {null}
|
||||
*/
|
||||
function updateTextureStatus(tid, action) {
|
||||
let likes = parseInt($('#likes').html()) + (action == "add" ? 1 : -1);
|
||||
action = (action == "add") ? 'removeFromCloset' : 'addToCloset';
|
||||
|
||||
$(`a[tid=${tid}]`).attr('href', `javascript:${action}(${tid});`).attr('title', trans('skinlib.' + action)).toggleClass('liked');
|
||||
$('#'+tid).attr('href', `javascript:${action}(${tid});`).html(trans('skinlib.' + action));
|
||||
$('#likes').html(likes);
|
||||
}
|
||||
|
||||
function ajaxAddToCloset(tid, name) {
|
||||
// remove interference of modal which is hide
|
||||
$('.modal').each(function () {
|
||||
return ($(this).css('display') == "none") ? $(this).remove() : null;
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url("user/closet/add"),
|
||||
dataType: "json",
|
||||
data: { 'tid': tid, 'name': name },
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
|
||||
$('.modal').modal('hide');
|
||||
updateTextureStatus(tid, 'add');
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function removeFromCloset(tid) {
|
||||
swal({
|
||||
text: trans('user.removeFromClosetNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonColor: '#d33'
|
||||
}).then(() => {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url("/user/closet/remove"),
|
||||
dataType: "json",
|
||||
data: { 'tid' : tid },
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
|
||||
updateTextureStatus(tid, 'remove');
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$('body').on('change', '#file', () => handleFiles()).on('ifToggled', '#type-cape', () => {
|
||||
MSP.clear();
|
||||
handleFiles();
|
||||
});
|
||||
|
||||
// Real-time preview
|
||||
function handleFiles(files, type) {
|
||||
|
||||
files = files || $('#file').prop('files');
|
||||
type = type || $('#type-cape').prop('checked') ? "cape" : "skin";
|
||||
|
||||
if (files.length > 0) {
|
||||
let file = files[0];
|
||||
|
||||
if (file.type === "image/png" || file.type === "image/x-png") {
|
||||
let reader = new FileReader();
|
||||
|
||||
reader.onload = function (e) {
|
||||
let img = new Image();
|
||||
|
||||
img.onload = () => {
|
||||
|
||||
(type == "skin") ? MSP.changeSkin(img.src) : MSP.changeCape(img.src);
|
||||
let domTextureName = $('#name');
|
||||
if (domTextureName.val() === '' || domTextureName.val() === domTextureName.attr('data-last-file-name')) {
|
||||
const fileName = file.name.replace(/\.[Pp][Nn][Gg]$/, '');
|
||||
domTextureName.attr('data-last-file-name', fileName);
|
||||
domTextureName.val(fileName);
|
||||
}
|
||||
};
|
||||
img.onerror = () => toastr.warning(trans('skinlib.fileExtError'));
|
||||
|
||||
img.src = this.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
toastr.warning(trans('skinlib.encodingError'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function upload() {
|
||||
let form = new FormData();
|
||||
let file = $('#file').prop('files')[0];
|
||||
|
||||
form.append('name', $('#name').val());
|
||||
form.append('file', file);
|
||||
form.append('public', ! $('#private').prop('checked'));
|
||||
|
||||
if ($('#type-skin').prop('checked')) {
|
||||
form.append('type', $('#skin-type').val());
|
||||
} else if ($('#type-cape').prop('checked')) {
|
||||
form.append('type', 'cape');
|
||||
} else {
|
||||
return toastr.info(trans('skinlib.emptyTextureType'));
|
||||
}
|
||||
|
||||
if (file === undefined) {
|
||||
toastr.info(trans('skinlib.emptyUploadFile'));
|
||||
$('#file').focus();
|
||||
} else if ($('#name').val() == "") {
|
||||
toastr.info(trans('skinlib.emptyTextureName'));
|
||||
$('#name').focus();
|
||||
} else if (file.type !== "image/png") {
|
||||
toastr.warning(trans('skinlib.fileExtError'));
|
||||
$('#file').focus();
|
||||
} else {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url("skinlib/upload"),
|
||||
contentType: false,
|
||||
dataType: "json",
|
||||
data: form,
|
||||
processData: false,
|
||||
beforeSend: () => {
|
||||
$('#upload-button').html('<i class="fa fa-spinner fa-spin"></i> ' + trans('skinlib.uploading')).prop('disabled', 'disabled');
|
||||
},
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
let redirect = function () {
|
||||
toastr.info(trans('skinlib.redirecting'));
|
||||
|
||||
window.setTimeout(() => {
|
||||
window.location = url(`skinlib/show/${json.tid}`);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// always redirect
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(redirect, redirect);
|
||||
|
||||
} else {
|
||||
swal({
|
||||
type: 'warning',
|
||||
html: json.msg
|
||||
}).then(() => {
|
||||
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
|
||||
});
|
||||
}
|
||||
},
|
||||
error: (json) => {
|
||||
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
|
||||
showAjaxError(json);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function changeTextureName(tid, oldName) {
|
||||
swal({
|
||||
text: trans('skinlib.setNewTextureName'),
|
||||
input: 'text',
|
||||
inputValue: oldName,
|
||||
showCancelButton: true,
|
||||
inputValidator: (value) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
(value) ? resolve() : reject(trans('skinlib.emptyNewTextureName'));
|
||||
});
|
||||
}
|
||||
}).then((new_name) => {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url("skinlib/rename"),
|
||||
dataType: "json",
|
||||
data: { 'tid': tid, 'new_name': new_name },
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
$('#name').text(new_name);
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '.private-label', function () {
|
||||
swal({
|
||||
text: trans('skinlib.setPublicNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => {
|
||||
changePrivacy($(this).attr('tid'));
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
|
||||
function changePrivacy(tid) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url(`skinlib/privacy`),
|
||||
dataType: "json",
|
||||
data: { 'tid': tid },
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
if (json.public == "0")
|
||||
$('a:contains("' + trans('skinlib.setAsPrivate') + '")').html(trans('skinlib.setAsPublic'));
|
||||
else
|
||||
$('a:contains("' + trans('skinlib.setAsPublic') + '")').html(trans('skinlib.setAsPrivate'));
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function deleteTexture(tid) {
|
||||
swal({
|
||||
text: trans('skinlib.deleteNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url("skinlib/delete"),
|
||||
dataType: "json",
|
||||
data: { 'tid': tid },
|
||||
success: (json) => {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(() => window.location = url('skinlib') );
|
||||
} else {
|
||||
swal({
|
||||
type: 'warning',
|
||||
html: json.msg
|
||||
});
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
215
resources/assets/src/js/skinlib/index.js
Normal file
215
resources/assets/src/js/skinlib/index.js
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
'use strict';
|
||||
|
||||
$.skinlib = {
|
||||
page: getQueryString('page', 1),
|
||||
filter: getQueryString('filter', 'skin'),
|
||||
sort: getQueryString('sort', 'time'),
|
||||
uploader: getQueryString('uploader', 0),
|
||||
keyword: decodeURI(getQueryString('keyword', ''))
|
||||
};
|
||||
|
||||
$(document).ready(() => {
|
||||
if ($('#skinlib-container').length != 0) {
|
||||
// Initially render skinlib
|
||||
requestSkinlibData().then(result => {
|
||||
renderSkinlib(result.items);
|
||||
|
||||
updatePaginator(
|
||||
$.skinlib.page,
|
||||
result.total_pages || 1
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('select.pagination').on('change', function () {
|
||||
onPageChange(parseInt($(this).val()));
|
||||
});
|
||||
|
||||
$('.filter').click(function (e) {
|
||||
e.preventDefault();
|
||||
let selectedFilter = $(this).data('filter');
|
||||
|
||||
if (selectedFilter == 'uploader') {
|
||||
$.skinlib.uploader = $(this).data('uid');
|
||||
console.log('Show items uploaded by uid ' + $.skinlib.uploader);
|
||||
} else {
|
||||
$.skinlib.filter = selectedFilter;
|
||||
console.log('Filter by ' + $.skinlib.filter);
|
||||
}
|
||||
|
||||
reloadSkinlib();
|
||||
});
|
||||
|
||||
$('.sort').click(function (e) {
|
||||
e.preventDefault();
|
||||
$.skinlib.sort = $(this).data('sort');
|
||||
|
||||
console.log('Sort by ' + $.skinlib.sort);
|
||||
reloadSkinlib();
|
||||
});
|
||||
|
||||
$('#search-form').submit(function (e) {
|
||||
e.preventDefault();
|
||||
$.skinlib.keyword = $('#navbar-search-input').val();
|
||||
|
||||
console.log('Search keyword: ' + $.skinlib.keyword);
|
||||
reloadSkinlib();
|
||||
});
|
||||
|
||||
function renderSkinlib(items) {
|
||||
let container = $('#skinlib-container').html('');
|
||||
|
||||
if (items.length === 0) {
|
||||
$('#skinlib-paginator').hide();
|
||||
|
||||
container.html(`<p style="text-align: center; margin: 30px 0;">
|
||||
${ trans('general.noResult') }
|
||||
</p>`);
|
||||
} else {
|
||||
$('#skinlib-paginator').show();
|
||||
|
||||
for (const item of items) {
|
||||
container.append(renderSkinlibItemComponent(item));
|
||||
}
|
||||
}
|
||||
|
||||
$('.overlay').hide();
|
||||
}
|
||||
|
||||
function reloadSkinlib() {
|
||||
requestSkinlibData().then(result => {
|
||||
$('.overlay').show();
|
||||
renderSkinlib(result.items);
|
||||
|
||||
updatePaginator($.skinlib.page, result.total_pages || 1);
|
||||
}).then(() => {
|
||||
updateUrlQueryString();
|
||||
updateBreadCrumb();
|
||||
});
|
||||
}
|
||||
|
||||
function requestSkinlibData() {
|
||||
return fetch({
|
||||
type: 'GET',
|
||||
url: url('skinlib/data'),
|
||||
dataType: 'json',
|
||||
data: $.skinlib,
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function renderSkinlibItemComponent(item) {
|
||||
let title = '';
|
||||
let anonymous = '';
|
||||
let liked = item.liked ? 'liked' : '';
|
||||
|
||||
if (item.liked === undefined) {
|
||||
// If user haven't logged in
|
||||
title = trans('skinlib.anonymous');
|
||||
anonymous = 'anonymous';
|
||||
} else {
|
||||
title = item.liked ? trans('skinlib.removeFromCloset') : trans('skinlib.addToCloset');
|
||||
}
|
||||
|
||||
return `<a href="${ url('skinlib/show/' + item.tid) }">
|
||||
<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>${ trans('skinlib.filter.' + item.type) }</small>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<a title="${title}" class="more like ${liked} ${anonymous}" tid="${ item.tid }" href="javascript:;" data-placement="top" data-toggle="tooltip"><i class="fa fa-heart"></i></a>
|
||||
|
||||
<small class="more private-label ${(item.public == 0) ? '' : 'hide'}" tid="${ item.tid }">
|
||||
${ trans('skinlib.private') }
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</a>`;
|
||||
}
|
||||
|
||||
function updatePaginator(currentPage, totalPages) {
|
||||
$.skinlib.page = currentPage;
|
||||
|
||||
$('p.pagination').text(trans('general.pagination', {
|
||||
page: currentPage,
|
||||
total: totalPages
|
||||
}));
|
||||
|
||||
let paginator = $('#skinlib-paginator');
|
||||
|
||||
if (paginator.html().length == 0) {
|
||||
// init paginator
|
||||
$('#skinlib-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
|
||||
currentPage: parseInt(currentPage),
|
||||
totalPages: parseInt(totalPages),
|
||||
onPageChange: onPageChange
|
||||
}));
|
||||
} else {
|
||||
$('#skinlib-paginator').jqPaginator('option', {
|
||||
currentPage: parseInt(currentPage),
|
||||
totalPages: parseInt(totalPages)
|
||||
});
|
||||
}
|
||||
|
||||
let pageSelectElement = $('select.pagination').html('');
|
||||
|
||||
for (let i = 1; i <= totalPages; i++) {
|
||||
pageSelectElement.append(`
|
||||
<option value="${i}" ${ (i == currentPage) ? 'selected' : '' }>${i}</option>
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
function onPageChange(page, type) {
|
||||
$.skinlib.page = page;
|
||||
updateBreadCrumb();
|
||||
|
||||
if (type == 'init') {
|
||||
console.log('Init paginator', page);
|
||||
} else {
|
||||
$('.overlay').show();
|
||||
reloadSkinlib();
|
||||
|
||||
console.log('Rendering page', page);
|
||||
}
|
||||
}
|
||||
|
||||
function updateUrlQueryString() {
|
||||
let query = $.param($.skinlib);
|
||||
|
||||
window.history.pushState(null, null, url(`skinlib?${query}`));
|
||||
}
|
||||
|
||||
function updateBreadCrumb() {
|
||||
if ($.skinlib.filter == 'cape') {
|
||||
$('#filter-indicator').html(trans('general.cape'));
|
||||
} else {
|
||||
$('#filter-indicator').html(trans('general.skin') + `<small>
|
||||
${ trans('skinlib.filter.' + $.skinlib.filter) }
|
||||
</small>`);
|
||||
}
|
||||
|
||||
if ($.skinlib.uploader != 0) {
|
||||
$('#uploader-indicator').html(trans('skinlib.filter.uploader', { uid: $.skinlib.uploader }));
|
||||
} else {
|
||||
$('#uploader-indicator').html(trans('skinlib.filter.allUsers'));
|
||||
}
|
||||
|
||||
$('#sort-indicator').html(trans('skinlib.sort.' + $.skinlib.sort));
|
||||
|
||||
if ($.skinlib.keyword != '') {
|
||||
$('#search-indicator').html(trans('general.searchResult', {
|
||||
keyword: decodeURI($.skinlib.keyword)
|
||||
}));
|
||||
|
||||
$('#navbar-search-input').val(decodeURI($.skinlib.keyword));
|
||||
}
|
||||
}
|
||||
173
resources/assets/src/js/skinlib/operations.js
Normal file
173
resources/assets/src/js/skinlib/operations.js
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/* exported changeTextureName, deleteTexture */
|
||||
|
||||
'use strict';
|
||||
|
||||
$(document).on('click', '.more.like', function () {
|
||||
let tid = $(this).attr('tid');
|
||||
|
||||
if ($(this).hasClass('anonymous'))
|
||||
return;
|
||||
|
||||
if ($(this).hasClass('liked')) {
|
||||
removeFromCloset(tid);
|
||||
} else {
|
||||
addToCloset(tid);
|
||||
}
|
||||
});
|
||||
|
||||
function addToCloset(tid) {
|
||||
$.getJSON(url(`skinlib/info/${tid}`), ({ name }) => {
|
||||
swal({
|
||||
title: trans('skinlib.setItemName'),
|
||||
inputValue: name,
|
||||
input: 'text',
|
||||
showCancelButton: true,
|
||||
inputValidator: value => (new Promise((resolve, reject) => {
|
||||
value ? resolve() : reject(trans('skinlib.emptyItemName'));
|
||||
}))
|
||||
}).then((result) => ajaxAddToCloset(tid, result));
|
||||
});
|
||||
}
|
||||
|
||||
function ajaxAddToCloset(tid, name) {
|
||||
// Remove interference of modal which is hide
|
||||
$('.modal').each(function () {
|
||||
return ($(this).css('display') == 'none') ? $(this).remove() : null;
|
||||
});
|
||||
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/closet/add'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid, name: name }
|
||||
}).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
swal({ type: 'success', html: msg });
|
||||
|
||||
$('.modal').modal('hide');
|
||||
updateTextureStatus(tid, 'add');
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function removeFromCloset(tid) {
|
||||
swal({
|
||||
text: trans('user.removeFromClosetNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonColor: '#d33'
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('/user/closet/remove'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
swal({ type: 'success', html: msg });
|
||||
|
||||
updateTextureStatus(tid, 'remove');
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changeTextureName(tid, oldName) {
|
||||
let newTextureName = '';
|
||||
|
||||
swal({
|
||||
text: trans('skinlib.setNewTextureName'),
|
||||
input: 'text',
|
||||
inputValue: oldName,
|
||||
showCancelButton: true,
|
||||
inputValidator: value => (new Promise((resolve, reject) => {
|
||||
(newTextureName = value) ? resolve() : reject(trans('skinlib.emptyNewTextureName'));
|
||||
}))
|
||||
}).then(name => fetch({
|
||||
type: 'POST',
|
||||
url: url('skinlib/rename'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid, new_name: name }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
$('#name').text(newTextureName);
|
||||
toastr.success(msg);
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update button action & likes of texture.
|
||||
*
|
||||
* @param {int} tid
|
||||
* @param {string} action add|remove
|
||||
* @return {null}
|
||||
*/
|
||||
function updateTextureStatus(tid, action) {
|
||||
let likes = parseInt($('#likes').html()) + (action == 'add' ? 1 : -1);
|
||||
action = (action == 'add') ? 'removeFromCloset' : 'addToCloset';
|
||||
|
||||
$(`a[tid=${tid}]`).attr('href', `javascript:${action}(${tid});`).attr('title', trans(`skinlib.${action}`)).toggleClass('liked');
|
||||
$(`#${tid}`).attr('href', `javascript:${action}(${tid});`).html(trans(`skinlib.${action}`));
|
||||
$('#likes').html(likes);
|
||||
}
|
||||
|
||||
$(document).on('click', '.private-label', function () {
|
||||
swal({
|
||||
text: trans('skinlib.setPublicNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => {
|
||||
changePrivacy($(this).attr('tid'));
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
|
||||
function changePrivacy(tid) {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('skinlib/privacy'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid }
|
||||
}).then(result => {
|
||||
let { errno, msg } = result;
|
||||
|
||||
if (errno == 0) {
|
||||
toastr.success(msg);
|
||||
|
||||
if (result.public == '0') {
|
||||
$(`a:contains("${trans('skinlib.setAsPrivate')}")`).html(trans('skinlib.setAsPublic'));
|
||||
} else {
|
||||
$(`a:contains("${trans('skinlib.setAsPublic')}")`).html(trans('skinlib.setAsPrivate'));
|
||||
}
|
||||
} else {
|
||||
toastr.warning(msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function deleteTexture(tid) {
|
||||
swal({
|
||||
text: trans('skinlib.deleteNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('skinlib/delete'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid }
|
||||
})).then(({ errno, msg }) => {
|
||||
if (errno == 0) {
|
||||
swal({ type: 'success', html: msg }).then(() => {
|
||||
window.location = url('skinlib');
|
||||
});
|
||||
} else {
|
||||
swal({ type: 'warning', html: msg });
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
130
resources/assets/src/js/skinlib/upload.js
Normal file
130
resources/assets/src/js/skinlib/upload.js
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/* global MSP */
|
||||
/* exported upload */
|
||||
|
||||
'use strict';
|
||||
|
||||
$('#private').on('ifToggled', function () {
|
||||
$(this).prop('checked') ? $('#msg').show() : $('#msg').hide();
|
||||
});
|
||||
|
||||
$('#type-skin').on('ifToggled', function () {
|
||||
$(this).prop('checked') ? $('#skin-type').show() : $('#skin-type').hide();
|
||||
});
|
||||
|
||||
$('body').on('change', '#file', () => handleFiles()).on('ifToggled', '#type-cape', () => {
|
||||
MSP.clear();
|
||||
handleFiles();
|
||||
});
|
||||
|
||||
// Real-time preview
|
||||
function handleFiles(files, type) {
|
||||
|
||||
files = files || $('#file').prop('files');
|
||||
type = type || $('#type-cape').prop('checked') ? 'cape' : 'skin';
|
||||
|
||||
if (files.length > 0) {
|
||||
let file = files[0];
|
||||
|
||||
if (file.type === 'image/png' || file.type === 'image/x-png') {
|
||||
let reader = new FileReader();
|
||||
|
||||
reader.onload = function () {
|
||||
let img = new Image();
|
||||
|
||||
img.onload = () => {
|
||||
let $name = $('#name');
|
||||
|
||||
(type == 'skin') ? MSP.changeSkin(img.src) : MSP.changeCape(img.src);
|
||||
|
||||
if ($name.val() === '' || $name.val() === $name.attr('data-last-file-name')) {
|
||||
// Remove png extension in filename
|
||||
const fileName = file.name.replace(/\.[Pp][Nn][Gg]$/, '');
|
||||
|
||||
$name.attr('data-last-file-name', fileName);
|
||||
$name.val(fileName);
|
||||
}
|
||||
};
|
||||
|
||||
img.onerror = () => toastr.warning(trans('skinlib.fileExtError'));
|
||||
|
||||
img.src = this.result;
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
toastr.warning(trans('skinlib.encodingError'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function upload() {
|
||||
let form = new FormData();
|
||||
let file = $('#file').prop('files')[0];
|
||||
|
||||
form.append('name', $('#name').val());
|
||||
form.append('file', file);
|
||||
form.append('public', ! $('#private').prop('checked'));
|
||||
|
||||
if ($('#type-skin').prop('checked')) {
|
||||
form.append('type', $('#skin-type').val());
|
||||
} else if ($('#type-cape').prop('checked')) {
|
||||
form.append('type', 'cape');
|
||||
} else {
|
||||
return toastr.info(trans('skinlib.emptyTextureType'));
|
||||
}
|
||||
|
||||
(function validate(form, file, callback) {
|
||||
if (file === undefined) {
|
||||
toastr.info(trans('skinlib.emptyUploadFile'));
|
||||
$('#file').focus();
|
||||
} else if ($('#name').val() == '') {
|
||||
toastr.info(trans('skinlib.emptyTextureName'));
|
||||
$('#name').focus();
|
||||
} else if (file.type !== 'image/png') {
|
||||
toastr.warning(trans('skinlib.fileExtError'));
|
||||
$('#file').focus();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
})(form, file, () => {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('skinlib/upload'),
|
||||
contentType: false,
|
||||
dataType: 'json',
|
||||
data: form,
|
||||
processData: false,
|
||||
beforeSend: () => {
|
||||
$('#upload-button').html(
|
||||
'<i class="fa fa-spinner fa-spin"></i> ' + trans('skinlib.uploading')
|
||||
).prop('disabled', 'disabled');
|
||||
}
|
||||
}).then(({ errno, msg, tid }) => {
|
||||
if (errno == 0) {
|
||||
let redirect = function () {
|
||||
toastr.info(trans('skinlib.redirecting'));
|
||||
|
||||
window.setTimeout(() => {
|
||||
window.location = url(`skinlib/show/${tid}`);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// Always redirect
|
||||
swal({
|
||||
type: 'success',
|
||||
html: msg
|
||||
}).then(redirect, redirect);
|
||||
} else {
|
||||
swal({
|
||||
type: 'warning',
|
||||
html: msg
|
||||
}).then(() => {
|
||||
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
|
||||
});
|
||||
}
|
||||
}).catch(err => {
|
||||
showAjaxError(err);
|
||||
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -1,685 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
$('body').on('click', '.player', function () {
|
||||
$('.player-selected').removeClass('player-selected');
|
||||
$(this).addClass('player-selected');
|
||||
|
||||
showPlayerTexturePreview(this.id);
|
||||
});
|
||||
|
||||
$('body').on('click', '#preview-switch', () => {
|
||||
TexturePreview.previewType == '3D' ? TexturePreview.show2dPreview() : TexturePreview.show3dPreview();
|
||||
});
|
||||
|
||||
let selectedTextures = [];
|
||||
|
||||
$('body').on('click', '.item-body', function () {
|
||||
$('.item-selected').parent().removeClass('item-selected');
|
||||
$(this).parent().addClass('item-selected');
|
||||
|
||||
const tid = parseInt($(this).parent().attr('tid'));
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "../skinlib/info/" + tid,
|
||||
dataType: "json",
|
||||
success: (json) => {
|
||||
if (json.type == "cape") {
|
||||
MSP.changeCape('../textures/' + json.hash);
|
||||
selectedTextures['cape'] = tid;
|
||||
} else {
|
||||
MSP.changeSkin('../textures/' + json.hash);
|
||||
selectedTextures['skin'] = tid;
|
||||
}
|
||||
|
||||
if (selectedTextures['skin'] !== undefined && selectedTextures['cape'] !== undefined)
|
||||
$('#textures-indicator').text(`${trans('general.skin')} & ${trans('general.cape')}`);
|
||||
else if (selectedTextures['skin'] != undefined)
|
||||
$('#textures-indicator').text(trans('general.skin'));
|
||||
else if (selectedTextures['cape'] != undefined)
|
||||
$('#textures-indicator').text(trans('general.cape'));
|
||||
},
|
||||
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) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url('user/player/show'),
|
||||
dataType: "json",
|
||||
data: { "pid": pid },
|
||||
success: (json) => {
|
||||
|
||||
['steve', 'alex', 'cape'].forEach((type) => {
|
||||
let tid = json[`tid_${type}`];
|
||||
let preview = new TexturePreview(type, tid, json.preference);
|
||||
|
||||
if (tid) {
|
||||
preview.change2dPreview().change3dPreview();
|
||||
} else {
|
||||
preview.showNotUploaded();
|
||||
}
|
||||
});
|
||||
|
||||
if ((json.preference == "default" && !json.tid_steve) || (json.preference == "slim" && !json.tid_alex)) {
|
||||
// show default skin
|
||||
MSP.changeSkin(defaultSkin);
|
||||
}
|
||||
|
||||
console.log(`Texture previews of player ${json.player_name} rendered.`);
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function renameClosetItem(tid, oldName) {
|
||||
swal({
|
||||
title: trans('user.renameClosetItem'),
|
||||
input: 'text',
|
||||
inputValue: oldName,
|
||||
showCancelButton: true,
|
||||
inputValidator: function(value) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (value) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(trans('skinlib.emptyNewTextureName'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}).then(function(new_name) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./closet/rename",
|
||||
dataType: "json",
|
||||
data: { 'tid': tid, 'new_name': new_name },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
$("[tid="+tid+"]>.item-footer>.texture-name>span").html(new_name);
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function removeFromCloset(tid) {
|
||||
swal({
|
||||
text: trans('user.removeFromClosetNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./closet/remove",
|
||||
dataType: "json",
|
||||
data: { 'tid' : tid },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
|
||||
$('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 {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setAsAvatar(tid) {
|
||||
swal({
|
||||
title: trans('user.setAvatar'),
|
||||
text: trans('user.setAvatarNotice'),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
}).then(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./profile/avatar",
|
||||
dataType: "json",
|
||||
data: { "tid": tid },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
// refersh avatars
|
||||
$('[alt="User Image"]').each(function() {
|
||||
$(this).prop('src', $(this).attr('src') + '?' + new Date().getTime());
|
||||
})
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('input[type=radio]').iCheck({
|
||||
radioClass: 'iradio_square-blue'
|
||||
});
|
||||
swal.setDefaults({
|
||||
confirmButtonText: trans('general.confirm'),
|
||||
cancelButtonText: trans('general.cancel')
|
||||
});
|
||||
|
||||
if (window.location.pathname.includes('/user/closet')) {
|
||||
Promise.resolve($.ajax({
|
||||
type: 'GET',
|
||||
url: url('/user/closet-data'),
|
||||
dataType: 'json'
|
||||
})).then(result => {
|
||||
renderCloset(result.items, result.category);
|
||||
$('#closet-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
|
||||
totalPages: result.total_pages,
|
||||
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() {
|
||||
var pid = 0;
|
||||
|
||||
$('input[name="player"]').each(function(){
|
||||
if (this.checked) pid = this.id;
|
||||
});
|
||||
|
||||
if (!pid) {
|
||||
toastr.info(trans('user.emptySelectedPlayer'));
|
||||
} else if (selectedTextures['skin'] == undefined && selectedTextures['cape'] == undefined) {
|
||||
toastr.info(trans('user.emptySelectedTexture'));
|
||||
} else {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url('user/player/set'),
|
||||
dataType: "json",
|
||||
data: {
|
||||
'pid': pid,
|
||||
'tid[skin]': selectedTextures['skin'],
|
||||
'tid[cape]': selectedTextures['cape']
|
||||
},
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
$('#modal-use-as').modal('hide');
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$('body').on('change', '#preference', function() {
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url('user/player/preference'),
|
||||
dataType: "json",
|
||||
data: { 'pid' : $(this).attr('pid'), 'preference' : $(this).val() },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
toastr.success(json.msg);
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
|
||||
function changePlayerName(pid, current_player_name) {
|
||||
swal({
|
||||
title: trans('user.changePlayerName'),
|
||||
text: $('#player_name').attr('placeholder'),
|
||||
inputValue: current_player_name,
|
||||
input: 'text',
|
||||
showCancelButton: true,
|
||||
inputValidator: function(value) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (value) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(trans('user.emptyPlayerName'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}).then(function(new_player_name) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url('user/player/rename'),
|
||||
dataType: "json",
|
||||
data: { 'pid' : pid, 'new_player_name' : new_player_name },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
$('td:contains("'+pid+'")').next().html(new_player_name);
|
||||
} else {
|
||||
swal({
|
||||
type: 'error',
|
||||
html: json.msg
|
||||
});
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function clearTexture(pid) {
|
||||
let dom = `
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="clear-steve"> Default (Steve)
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="clear-alex"> Slim (Alex)
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="clear-cape"> ${trans('general.cape')}
|
||||
</div>
|
||||
<script>
|
||||
$('input[type=checkbox]').iCheck({ checkboxClass: 'icheckbox_square-blue' });
|
||||
</script>
|
||||
`;
|
||||
showModal(dom, trans('user.chooseClearTexture'), 'default', { callback: `ajaxClearTexture(${pid})` });
|
||||
return;
|
||||
}
|
||||
|
||||
function ajaxClearTexture(pid) {
|
||||
$('.modal').each(function () {
|
||||
if ($(this).css('display') == "none")
|
||||
$(this).remove();
|
||||
});
|
||||
|
||||
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: url('user/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) {
|
||||
swal({
|
||||
title: trans('user.deletePlayer'),
|
||||
text: trans('user.deletePlayerNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonColor: '#d33'
|
||||
}).then(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url('user/player/delete'),
|
||||
dataType: "json",
|
||||
data: { 'pid' : pid },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(function() {
|
||||
$('tr#'+pid).remove();
|
||||
});
|
||||
} else {
|
||||
swal({
|
||||
type: 'error',
|
||||
html: json.msg
|
||||
});
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addNewPlayer() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url('user/player/add'),
|
||||
dataType: "json",
|
||||
data: { 'player_name' : $('#player_name').val() },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(function() {
|
||||
location.reload();
|
||||
});
|
||||
$('#modal-add-player').modal('hide');
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function changeNickName() {
|
||||
var new_nickname = $('#new-nickname').val();
|
||||
|
||||
if (!new_nickname) {
|
||||
swal({
|
||||
type: 'error',
|
||||
html: trans('user.emptyNewNickName')
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
swal({
|
||||
text: trans('user.changeNickName', { new_nickname: new_nickname }),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
}).then(function() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./profile?action=nickname",
|
||||
dataType: "json",
|
||||
data: { 'new_nickname' : new_nickname },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
$('.nickname').each(function() {
|
||||
$(this).html(new_nickname);
|
||||
});
|
||||
} else {
|
||||
swal({
|
||||
type: 'warning',
|
||||
html: json.msg
|
||||
});
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function changePassword() {
|
||||
let domOldPwd = $('#password');
|
||||
let domNewPwd = $('#new-passwd');
|
||||
let domConfirmPwd = $('#confirm-pwd');
|
||||
|
||||
let password = domOldPwd.val();
|
||||
let new_passwd = domNewPwd.val();
|
||||
|
||||
if (password == "") {
|
||||
toastr.info(trans('user.emptyPassword'));
|
||||
domOldPwd.focus();
|
||||
} else if (new_passwd == "") {
|
||||
toastr.info(trans('user.emptyNewPassword'));
|
||||
domNewPwd.focus();
|
||||
} else if (domConfirmPwd.val() == "") {
|
||||
toastr.info(trans('auth.emptyConfirmPwd'));
|
||||
domConfirmPwd.focus();
|
||||
} else if (new_passwd != domConfirmPwd.val()) {
|
||||
toastr.warning(trans('auth.invalidConfirmPwd'));
|
||||
domConfirmPwd.focus();
|
||||
} else {
|
||||
Promise.resolve($.ajax({
|
||||
type: "POST",
|
||||
url: "./profile?action=password",
|
||||
dataType: "json",
|
||||
data: { 'current_password': password, 'new_password': new_passwd }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
return swal({ type: 'success', text: result.msg })
|
||||
.then(() => {
|
||||
return logout();
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
window.location = url('auth/login');
|
||||
}
|
||||
}).catch(error => showAjaxError);
|
||||
} else {
|
||||
return swal({ type: 'warning', text: result.msg });
|
||||
}
|
||||
}).catch(error => showAjaxError);
|
||||
}
|
||||
}
|
||||
|
||||
$('#new-email').focusin(function() {
|
||||
$('#current-password').parent().show();
|
||||
}).focusout(function() {
|
||||
window.setTimeout(function() {
|
||||
if (!$('#current-password').is(':focus'))
|
||||
$('#current-password').parent().hide();
|
||||
}, 10);
|
||||
})
|
||||
|
||||
function changeEmail() {
|
||||
var new_email = $('#new-email').val();
|
||||
|
||||
if (!new_email) {
|
||||
swal({
|
||||
type: 'error',
|
||||
html: trans('user.emptyNewEmail')
|
||||
});
|
||||
return;
|
||||
}
|
||||
// check valid email address
|
||||
if (!/\S+@\S+\.\S+/.test(new_email)) {
|
||||
swal({
|
||||
type: 'warning',
|
||||
html: trans('auth.invalidEmail')
|
||||
}); return;
|
||||
}
|
||||
|
||||
swal({
|
||||
text: trans('user.changeEmail', { new_email: new_email }),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
}).then(() => {
|
||||
return Promise.resolve($.ajax({
|
||||
type: 'POST',
|
||||
url: './profile?action=email',
|
||||
dataType: 'json',
|
||||
data: { 'new_email': new_email, 'password': $('#current-password').val() }
|
||||
}));
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
return swal({ type: 'success', text: result.msg })
|
||||
.then(() => {
|
||||
return logout();
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
window.location = url('auth/login');
|
||||
}
|
||||
}).catch(error => showAjaxError);
|
||||
} else {
|
||||
return swal({ type: 'warning', text: result.msg });
|
||||
}
|
||||
}).catch(error => showAjaxError);
|
||||
}
|
||||
|
||||
function deleteAccount() {
|
||||
var password = $('.modal-body>#password').val();
|
||||
|
||||
if (!password) {
|
||||
swal({
|
||||
type: 'warning',
|
||||
html: trans('user.emptyDeletePassword')
|
||||
}); return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./profile?action=delete",
|
||||
dataType: "json",
|
||||
data: { 'password' : password },
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
}).then(function() {
|
||||
window.location = "../auth/login";
|
||||
});
|
||||
} else {
|
||||
swal({
|
||||
type: 'warning',
|
||||
html: json.msg
|
||||
});
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
|
||||
function signIn() {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "./user/sign-in",
|
||||
dataType: "json",
|
||||
success: function(json) {
|
||||
if (json.errno == 0) {
|
||||
$('#score').html(json.score);
|
||||
var dom = '<i class="fa fa-calendar-check-o"></i> ' + trans('user.signInRemainingTime', { time: String(json.remaining_time) });
|
||||
$('#sign-in-button').attr('disabled', 'disabled').html(dom);
|
||||
|
||||
if (json.storage.used > 1024) {
|
||||
$('#user-storage').html(`<b>${Math.round(json.storage.used)}</b>/ ${Math.round(json.storage.total)} MB`);
|
||||
} else {
|
||||
$('#user-storage').html(`<b>${Math.round(json.storage.used)}</b>/ ${Math.round(json.storage.total)} KB`);
|
||||
}
|
||||
|
||||
$('#user-storage-bar').css('width', `${json.storage.percentage}%`)
|
||||
|
||||
swal({
|
||||
type: 'success',
|
||||
html: json.msg
|
||||
});
|
||||
} else {
|
||||
toastr.warning(json.msg);
|
||||
}
|
||||
},
|
||||
error: showAjaxError
|
||||
});
|
||||
}
|
||||
240
resources/assets/src/js/user/closet.js
Normal file
240
resources/assets/src/js/user/closet.js
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/* global MSP */
|
||||
/* exported renameClosetItem, removeFromCloset, setAsAvatar */
|
||||
|
||||
'use strict';
|
||||
|
||||
var selectedTextures = [];
|
||||
|
||||
$(document).ready(function () {
|
||||
if (! window.location.pathname.includes('/user/closet'))
|
||||
return;
|
||||
|
||||
fetch({
|
||||
type: 'GET',
|
||||
url: url('/user/closet-data'),
|
||||
dataType: 'json'
|
||||
}).then(result => {
|
||||
renderCloset(result.items, result.category);
|
||||
|
||||
$('#closet-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
|
||||
totalPages: result.total_pages,
|
||||
onPageChange: page => reloadCloset(
|
||||
$('#skin-category').hasClass('active') ? 'skin' : 'cape',
|
||||
page, $('input[name=q]').val()
|
||||
)
|
||||
}));
|
||||
}).catch(err => showAjaxError(err));
|
||||
|
||||
$('input[name=q]').on('input', debounce(() => {
|
||||
let category = $('#skin-category').hasClass('active') ? 'skin' : 'cape';
|
||||
reloadCloset(category, 1, $('input[name=q]').val());
|
||||
}, 350));
|
||||
});
|
||||
|
||||
$('body').on('click', '.item-body', function () {
|
||||
$('.item-selected').parent().removeClass('item-selected');
|
||||
let $item = $(this).parent();
|
||||
|
||||
$item.addClass('item-selected');
|
||||
|
||||
let tid = parseInt($item.attr('tid'));
|
||||
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url(`skinlib/info/${tid}`),
|
||||
dataType: 'json'
|
||||
}).then(result => {
|
||||
if (result.type == 'cape') {
|
||||
MSP.changeCape(url(`textures/${result.hash}`));
|
||||
selectedTextures['cape'] = tid;
|
||||
} else {
|
||||
MSP.changeSkin(url(`textures/${result.hash}`));
|
||||
selectedTextures['skin'] = tid;
|
||||
}
|
||||
|
||||
let skin = selectedTextures['skin'],
|
||||
cape = selectedTextures['cape'];
|
||||
|
||||
let $indicator = $('#textures-indicator');
|
||||
|
||||
if (skin !== undefined && cape !== undefined) {
|
||||
$indicator.text(`${trans('general.skin')} & ${trans('general.cape')}`);
|
||||
} else if (skin != undefined) {
|
||||
$indicator.text(trans('general.skin'));
|
||||
} else if (cape != undefined) {
|
||||
$indicator.text(trans('general.cape'));
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
});
|
||||
|
||||
$('body').on('click', '.category-switch', () => {
|
||||
let category = $('a[href="#skin-category"]').parent().hasClass('active') ? 'cape' : 'skin';
|
||||
let search = $('input[name=q]').val();
|
||||
let page = parseInt($('#closet-paginator').attr(`last-${category}-page`));
|
||||
|
||||
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>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render closet with giving items & category.
|
||||
*
|
||||
* @param {array} items
|
||||
* @param {string} category
|
||||
*/
|
||||
function renderCloset(items, category) {
|
||||
let search = $('input[name=q]').val();
|
||||
let container = $(`#${category}-category`).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 (let item of items) {
|
||||
container.append(renderClosetItemComponent(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload and render closet.
|
||||
*
|
||||
* @param {string} category
|
||||
* @param {integer} page
|
||||
* @param {string} search
|
||||
*/
|
||||
function reloadCloset(category, page, search) {
|
||||
fetch({
|
||||
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(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function renameClosetItem(tid, oldName) {
|
||||
let newTextureName = '';
|
||||
|
||||
swal({
|
||||
title: trans('user.renameClosetItem'),
|
||||
input: 'text',
|
||||
inputValue: oldName,
|
||||
showCancelButton: true,
|
||||
inputValidator: value => (new Promise((resolve, reject) => {
|
||||
(newTextureName = value) ? resolve() : reject(trans('skinlib.emptyNewTextureName'));
|
||||
}))
|
||||
}).then(name => fetch({
|
||||
type: 'POST',
|
||||
url: url('closet/rename'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid, new_name: name }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
$(`[tid=${tid}]>.item-footer>.texture-name>span`).html(newTextureName);
|
||||
toastr.success(result.msg);
|
||||
} else {
|
||||
toastr.warning(result.msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function removeFromCloset(tid) {
|
||||
swal({
|
||||
text: trans('user.removeFromClosetNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('closet/remove'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
swal({ type: 'success', html: result.msg });
|
||||
|
||||
$(`div[tid=${tid}]`).remove();
|
||||
|
||||
['skin', 'cape'].forEach(type => {
|
||||
let container = $(`#${type}-category`);
|
||||
|
||||
if ($.trim(container.html()) == '') {
|
||||
let msg = trans('user.emptyClosetMsg', { url: url(`skinlib?filter=${type}`) });
|
||||
container.html(`<div class="empty-msg">${msg}</div>`);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
toastr.warning(result.msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function setAsAvatar(tid) {
|
||||
swal({
|
||||
title: trans('user.setAvatar'),
|
||||
text: trans('user.setAvatarNotice'),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('profile/avatar'),
|
||||
dataType: 'json',
|
||||
data: { tid: tid }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
toastr.success(result.msg);
|
||||
|
||||
// Refersh avatars
|
||||
$('[alt="User Image"]').each(function () {
|
||||
$(this).prop('src', $(this).attr('src') + '?' + new Date().getTime());
|
||||
});
|
||||
} else {
|
||||
toastr.warning(result.msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
213
resources/assets/src/js/user/player.js
Normal file
213
resources/assets/src/js/user/player.js
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/* global MSP, defaultSkin, selectedTextures */
|
||||
/* exported changePlayerName, clearTexture, ajaxClearTexture, addNewPlayer, deletePlayer, setTexture */
|
||||
|
||||
'use strict';
|
||||
|
||||
$('body').on('click', '.player', function () {
|
||||
$('.player-selected').removeClass('player-selected');
|
||||
$(this).addClass('player-selected');
|
||||
|
||||
showPlayerTexturePreview(this.id);
|
||||
});
|
||||
|
||||
$('body').on('click', '#preview-switch', () => {
|
||||
TexturePreview.previewType == '3D' ? TexturePreview.show2dPreview() : TexturePreview.show3dPreview();
|
||||
});
|
||||
|
||||
function showPlayerTexturePreview(pid) {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/player/show'),
|
||||
dataType: 'json',
|
||||
data: { pid: pid }
|
||||
}).then(result => {
|
||||
// Render skin preview of selected player
|
||||
['steve', 'alex', 'cape'].forEach((type) => {
|
||||
let tid = result[`tid_${type}`];
|
||||
let preview = new TexturePreview(type, tid, result.preference);
|
||||
|
||||
if (tid) {
|
||||
preview.change2dPreview().change3dPreview();
|
||||
} else {
|
||||
preview.showNotUploaded();
|
||||
}
|
||||
});
|
||||
|
||||
if ((result.preference == 'default' && !result.tid_steve) ||
|
||||
(result.preference == 'slim' && !result.tid_alex))
|
||||
{
|
||||
// show default skin
|
||||
MSP.changeSkin(defaultSkin);
|
||||
}
|
||||
|
||||
console.log(`Texture previews of player ${result.player_name} rendered.`);
|
||||
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
$('body').on('change', '#preference', function () {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/player/preference'),
|
||||
dataType: 'json',
|
||||
data: { pid: $(this).attr('pid'), preference: $(this).val() }
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
toastr.success(result.msg);
|
||||
} else {
|
||||
toastr.warning(result.msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
});
|
||||
|
||||
function changePlayerName(pid, currentPlayerName) {
|
||||
let newPlayerName = '';
|
||||
|
||||
swal({
|
||||
title: trans('user.changePlayerName'),
|
||||
text: $('#player_name').attr('placeholder'),
|
||||
inputValue: currentPlayerName,
|
||||
input: 'text',
|
||||
showCancelButton: true,
|
||||
inputValidator: value => (new Promise((resolve, reject) => {
|
||||
(newPlayerName = value) ? resolve() : reject(trans('skinlib.emptyPlayerName'));
|
||||
}))
|
||||
}).then(name => fetch({
|
||||
type: 'POST',
|
||||
url: url('user/player/rename'),
|
||||
dataType: 'json',
|
||||
data: { pid: pid, new_player_name: name }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
swal({ type: 'success', html: result.msg });
|
||||
|
||||
$(`td:contains("${pid}")`).next().html(newPlayerName);
|
||||
} else {
|
||||
swal({ type: 'error', html: result.msg });
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function clearTexture(pid) {
|
||||
let dom = `<div class="form-group">
|
||||
<input type="checkbox" id="clear-steve"> Default (Steve)
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="clear-alex"> Slim (Alex)
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="clear-cape"> ${trans('general.cape')}
|
||||
</div>
|
||||
<script>
|
||||
$('input[type=checkbox]').iCheck({ checkboxClass: 'icheckbox_square-blue' });
|
||||
</script>`;
|
||||
|
||||
return showModal(dom, trans('user.chooseClearTexture'), 'default', {
|
||||
callback: `ajaxClearTexture(${pid})`
|
||||
});
|
||||
}
|
||||
|
||||
function ajaxClearTexture(pid) {
|
||||
$('.modal').each(function () {
|
||||
if ($(this).css('display') == 'none') $(this).remove();
|
||||
});
|
||||
|
||||
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) {
|
||||
return toastr.warning(trans('user.noClearChoice'));
|
||||
}
|
||||
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/player/texture/clear'),
|
||||
dataType: 'json',
|
||||
data: data
|
||||
}).then(result => {
|
||||
swal({ type: result.errno == 0 ? 'success' : 'error', html: result.msg });
|
||||
$('.modal').modal('hide');
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function deletePlayer(pid) {
|
||||
swal({
|
||||
title: trans('user.deletePlayer'),
|
||||
text: trans('user.deletePlayerNotice'),
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
cancelButtonColor: '#3085d6',
|
||||
confirmButtonColor: '#d33'
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('user/player/delete'),
|
||||
dataType: 'json',
|
||||
data: { pid: pid }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: result.msg
|
||||
}).then(() => $(`tr#${pid}`).remove());
|
||||
} else {
|
||||
swal({ type: 'error', html: result.msg });
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function addNewPlayer() {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/player/add'),
|
||||
dataType: 'json',
|
||||
data: { player_name: $('#player_name').val() }
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
swal({
|
||||
type: 'success',
|
||||
html: result.msg
|
||||
}).then(() => location.reload());
|
||||
|
||||
$('#modal-add-player').modal('hide');
|
||||
} else {
|
||||
toastr.warning(result.msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function setTexture() {
|
||||
let pid = 0,
|
||||
skin = selectedTextures['skin'],
|
||||
cape = selectedTextures['cape'];
|
||||
|
||||
$('input[name="player"]').each(function(){
|
||||
if (this.checked) pid = this.id;
|
||||
});
|
||||
|
||||
if (! pid) {
|
||||
toastr.info(trans('user.emptySelectedPlayer'));
|
||||
} else if (skin == undefined && cape == undefined) {
|
||||
toastr.info(trans('user.emptySelectedTexture'));
|
||||
} else {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/player/set'),
|
||||
dataType: 'json',
|
||||
data: {
|
||||
'pid': pid,
|
||||
'tid[skin]': skin,
|
||||
'tid[cape]': cape
|
||||
}
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
swal({ type: 'success', html: result.msg });
|
||||
$('#modal-use-as').modal('hide');
|
||||
} else {
|
||||
toastr.warning(result.msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
}
|
||||
153
resources/assets/src/js/user/profile.js
Normal file
153
resources/assets/src/js/user/profile.js
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/* exported changeNickName, changePassword, changeEmail, deleteAccount, deleteAccount */
|
||||
|
||||
'use strict';
|
||||
|
||||
function changeNickName() {
|
||||
let name = $('#new-nickname').val();
|
||||
|
||||
if (! name) {
|
||||
return swal({ type: 'error', html: trans('user.emptyNewNickName') });
|
||||
}
|
||||
|
||||
swal({
|
||||
text: trans('user.changeNickName', { new_nickname: name }),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('user/profile?action=nickname'),
|
||||
dataType: 'json',
|
||||
data: { new_nickname: name }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
|
||||
$('.nickname').each(function () {
|
||||
$(this).html(name);
|
||||
});
|
||||
|
||||
return swal({ type: 'success', html: result.msg });
|
||||
} else {
|
||||
return swal({ type: 'warning', html: result.msg });
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function changePassword() {
|
||||
let $oldPasswd = $('#password'),
|
||||
$newPasswd = $('#new-passwd'),
|
||||
$confirmPwd = $('#confirm-pwd');
|
||||
|
||||
let password = $oldPasswd.val(),
|
||||
newPasswd = $newPasswd.val();
|
||||
|
||||
if (password == '') {
|
||||
toastr.info(trans('user.emptyPassword'));
|
||||
$oldPasswd.focus();
|
||||
} else if (newPasswd == '') {
|
||||
toastr.info(trans('user.emptyNewPassword'));
|
||||
$newPasswd.focus();
|
||||
} else if ($confirmPwd.val() == '') {
|
||||
toastr.info(trans('auth.emptyConfirmPwd'));
|
||||
$confirmPwd.focus();
|
||||
} else if (newPasswd != $confirmPwd.val()) {
|
||||
toastr.warning(trans('auth.invalidConfirmPwd'));
|
||||
$confirmPwd.focus();
|
||||
} else {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/profile?action=password'),
|
||||
dataType: 'json',
|
||||
data: { 'current_password': password, 'new_password': newPasswd }
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
return swal({
|
||||
type: 'success',
|
||||
text: result.msg }
|
||||
).then(() => {
|
||||
return logout();
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
window.location = url('auth/login');
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
} else {
|
||||
return swal({ type: 'warning', text: result.msg });
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
}
|
||||
|
||||
$('#new-email').focusin(() => {
|
||||
$('#current-password').parent().show();
|
||||
}).focusout(debounce(() => {
|
||||
let dom = $('#current-password');
|
||||
|
||||
if (! dom.is(':focus')) {
|
||||
dom.parent().hide();
|
||||
}
|
||||
}, 10));
|
||||
|
||||
function changeEmail() {
|
||||
var newEmail = $('#new-email').val();
|
||||
|
||||
if (! newEmail) {
|
||||
return swal({ type: 'error', html: trans('user.emptyNewEmail') });
|
||||
}
|
||||
|
||||
// check valid email address
|
||||
if (!/\S+@\S+\.\S+/.test(newEmail)) {
|
||||
return swal({ type: 'warning', html: trans('auth.invalidEmail') });
|
||||
}
|
||||
|
||||
swal({
|
||||
text: trans('user.changeEmail', { new_email: newEmail }),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
}).then(() => fetch({
|
||||
type: 'POST',
|
||||
url: url('user/profile?action=email'),
|
||||
dataType: 'json',
|
||||
data: { new_email: newEmail, password: $('#current-password').val() }
|
||||
})).then(result => {
|
||||
if (result.errno == 0) {
|
||||
return swal({
|
||||
type: 'success',
|
||||
text: result.msg
|
||||
}).then(() => {
|
||||
return logout();
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
window.location = url('auth/login');
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
} else {
|
||||
return swal({ type: 'warning', text: result.msg });
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
|
||||
function deleteAccount() {
|
||||
let password = $('.modal-body>#password').val();
|
||||
|
||||
if (! password) {
|
||||
return swal({ type: 'warning', html: trans('user.emptyDeletePassword') });
|
||||
}
|
||||
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/profile?action=delete'),
|
||||
dataType: 'json',
|
||||
data: { password: password }
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
return swal({
|
||||
type: 'success',
|
||||
html: result.msg
|
||||
}).then(() => {
|
||||
window.location = url('auth/login');
|
||||
});
|
||||
} else {
|
||||
return swal({ type: 'warning', html: result.msg });
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
27
resources/assets/src/js/user/sign.js
Normal file
27
resources/assets/src/js/user/sign.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* exported signIn */
|
||||
|
||||
function signIn() {
|
||||
fetch({
|
||||
type: 'POST',
|
||||
url: url('user/sign-in'),
|
||||
dataType: 'json'
|
||||
}).then(result => {
|
||||
if (result.errno == 0) {
|
||||
$('#score').html(result.score);
|
||||
var dom = '<i class="fa fa-calendar-check-o"></i> ' + trans('user.signInRemainingTime', { time: String(result.remaining_time) });
|
||||
$('#sign-in-button').attr('disabled', 'disabled').html(dom);
|
||||
|
||||
if (result.storage.used > 1024) {
|
||||
$('#user-storage').html(`<b>${Math.round(result.storage.used)}</b>/ ${Math.round(result.storage.total)} MB`);
|
||||
} else {
|
||||
$('#user-storage').html(`<b>${Math.round(result.storage.used)}</b>/ ${Math.round(result.storage.total)} KB`);
|
||||
}
|
||||
|
||||
$('#user-storage-bar').css('width', `${result.storage.percentage}%`);
|
||||
|
||||
return swal({ type: 'success', html: result.msg });
|
||||
} else {
|
||||
toastr.warning(result.msg);
|
||||
}
|
||||
}).catch(err => showAjaxError(err));
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user