Use async/await and update tests

This commit is contained in:
Pig Fang 2017-11-08 13:27:35 +08:00
parent 0f065ef202
commit 42a42ef8c7
26 changed files with 1539 additions and 762 deletions

View File

@ -11,6 +11,7 @@ var gulp = require('gulp'),
zip = require('gulp-zip'),
replace = require('gulp-batch-replace'),
notify = require('gulp-notify'),
merge = require('merge2'),
runSequence = require('run-sequence');
var version = require('./package.json').version;
@ -30,10 +31,13 @@ var vendorScripts = [
'es6-promise/dist/es6-promise.auto.min.js',
'sweetalert2/dist/sweetalert2.min.js',
'jqPaginator/dist/1.2.0/jqPaginator.min.js',
'regenerator-runtime/runtime.js',
'resources/assets/dist/js/common.js',
];
var vendorScriptsToBeMinified = [
'regenerator-runtime/runtime.js',
];
var vendorStyles = [
'bootstrap/dist/css/bootstrap.min.css',
'admin-lte/dist/css/AdminLTE.min.css',
@ -95,9 +99,12 @@ gulp.task('lint', () => {
// Concentrate all vendor scripts & styles to one dist file
gulp.task('publish-vendor', ['compile-es6'], callback => {
// JavaScript files
gulp.src(convertNpmRelativePath(vendorScripts))
var js = gulp.src(convertNpmRelativePath(vendorScripts))
.pipe(replace(scriptReplacements));
var jsToBeMinified = gulp.src(convertNpmRelativePath(vendorScriptsToBeMinified))
.pipe(uglify());
merge(js, jsToBeMinified)
.pipe(concat('app.js'))
.pipe(replace(scriptReplacements))
.pipe(gulp.dest(`${distPath}/js/`));
// CSS files
gulp.src(convertNpmRelativePath(vendorStyles))
@ -164,6 +171,7 @@ gulp.task('zip', () => {
'!node_modules/**/*.*',
'!storage/textures/**/*.*',
'!.env',
'!.babelrc',
'!.bowerrc',
'!.gitignore',
'!.git/**/*.*',
@ -201,7 +209,7 @@ gulp.task('watch', () => {
// watch .scss files
gulp.watch(`${srcPath}/sass/*.scss`, ['compile-sass'], () => notify('Sass files compiled!'));
// watch .js files
gulp.watch(`${srcPath}/js/*.js`, ['compile-es6'], () => notify('ES6 scripts compiled!'));
gulp.watch(`${srcPath}/js/**/*.js`, ['compile-es6'], () => notify('ES6 scripts compiled!'));
gulp.watch(`${srcPath}/js/general.js`, ['publish-vendor']);
});

View File

@ -34,6 +34,7 @@
"gulp-uglify": "^3.0.0",
"gulp-zip": "^4.0.0",
"jest": "^20.0.4",
"merge2": "^1.2.0",
"node-sass": "^4.5.3",
"run-sequence": "^2.0.0"
},

View File

@ -3,6 +3,8 @@
const $ = require('jquery');
window.$ = window.jQuery = $;
jest.useFakeTimers();
describe('tests for "customize" module', () => {
const modulePath = '../admin/customize';
@ -26,7 +28,8 @@ describe('tests for "customize" module', () => {
it('submit information of skin', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject(new Error));
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
@ -53,16 +56,33 @@ describe('tests for "customize" module', () => {
await submitColor();
expect(toastr.warning).toBeCalledWith('warning');
await submitColor();
expect(window.showAjaxError).toBeCalled();
});
});
describe('tests for "players" module', () => {
const modulePath = '../admin/players';
it('change player reference', async () => {
it('show "change player texture" modal dialog', () => {
const trans = jest.fn(key => key);
const showModal = jest.fn();
window.trans = trans;
window.showModal = showModal;
const changeTexture = require(modulePath).changeTexture;
changeTexture(1, 'name');
const args = showModal.mock.calls[0];
expect(args.includes('admin.changePlayerTexture')).toBe(true);
expect(args.includes('default')).toBe(true);
});
it('change player preference', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject(new Error));
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
@ -98,23 +118,28 @@ describe('tests for "players" module', () => {
await $('select').trigger('change');
expect(toastr.warning).toBeCalledWith('warning');
await $('select').trigger('change');
expect(window.showAjaxError).toBeCalled();
});
it('submit changed texture information', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const modal = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.$.fn.modal = modal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div class="modal" style="display: none" id="shouldBeRemoved"></div>
@ -141,27 +166,35 @@ describe('tests for "players" module', () => {
await ajaxChangeTexture(1);
expect(toastr.warning).toBeCalledWith('warning');
await ajaxChangeTexture(1);
expect(showAjaxError).toBeCalled();
});
it('change player name', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const swal = jest.fn(options => {
options.inputValidator('newName');
return Promise.resolve('newName');
});
const swal = jest.fn()
.mockImplementationOnce(() => Promise.reject())
.mockImplementationOnce(options => {
options.inputValidator('newName');
return Promise.resolve('newName');
});
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -177,6 +210,9 @@ describe('tests for "players" module', () => {
`;
const changePlayerName = require(modulePath).changePlayerName;
await changePlayerName(1, 'oldName');
expect(fetch).not.toBeCalled();
await changePlayerName(1, 'oldName');
expect(swal).toBeCalledWith(expect.objectContaining({
text: 'admin.changePlayerNameNotice',
@ -189,16 +225,22 @@ describe('tests for "players" module', () => {
dataType: 'json',
data: { pid: 1, name: 'newName' }
});
await changePlayerName(1, 'oldName');
expect($('tr#1 > td:nth-child(3)').text()).toBe('newName');
expect(toastr.warning).not.toBeCalled();
expect(toastr.success).toBeCalledWith('success');
await changePlayerName(1, 'oldName');
expect(toastr.warning).toBeCalledWith('warning');
await changePlayerName(1, 'oldName');
expect(showAjaxError).toBeCalled();
});
it('change owner', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject(new Error));
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
@ -207,13 +249,14 @@ describe('tests for "players" module', () => {
const trans = jest.fn(key => key);
const swal = jest.fn().mockReturnValue(Promise.resolve(2));
const debounce = jest.fn(fn => fn);
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.debounce = debounce;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -248,28 +291,38 @@ describe('tests for "players" module', () => {
data: { pid: 1, uid: 2 }
});
await changeOwner(1, 'oldName');
expect($('tr#1 > td:nth-child(2)').text()).toBe((2).toString());
expect($('tr#1 > td:nth-child(2)').text()).toBe('2');
expect(toastr.warning).not.toBeCalled();
expect(toastr.success).toBeCalledWith('success');
await changeOwner(1, 'oldName');
expect(toastr.warning).toBeCalledWith('warning');
await changeOwner(1, 'oldName');
expect(showAjaxError).toBeCalled();
});
it('delete player', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const swal = jest.fn().mockReturnValue(Promise.resolve('newName'));
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -282,6 +335,9 @@ describe('tests for "players" module', () => {
`;
const deletePlayer = require(modulePath).deletePlayer;
await deletePlayer(1);
expect(fetch).not.toBeCalled();
await deletePlayer(1);
expect(swal).toBeCalledWith({
text: 'admin.deletePlayerNotice',
@ -294,10 +350,15 @@ describe('tests for "players" module', () => {
dataType: 'json',
data: { pid: 1 }
});
await deletePlayer(1);
expect(document.getElementById('1')).toBeNull();
expect(toastr.warning).not.toBeCalled();
expect(toastr.success).toBeCalledWith('success');
await deletePlayer(1);
expect(toastr.warning).toBeCalledWith('warning');
await deletePlayer(1);
expect(showAjaxError).toBeCalled();
});
});
@ -307,17 +368,19 @@ describe('tests for "plugins" module', () => {
it('enable a plugin', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const reloadTable = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
$.pluginsTable = {
ajax: {
reload: reloadTable
@ -338,22 +401,27 @@ describe('tests for "plugins" module', () => {
await enablePlugin('plugin');
expect(toastr.warning).toBeCalledWith('warning');
await enablePlugin('plugin');
expect(showAjaxError).toBeCalled();
});
it('disable a plugin', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const reloadTable = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
$.pluginsTable = {
ajax: {
reload: reloadTable
@ -374,22 +442,30 @@ describe('tests for "plugins" module', () => {
await disablePlugin('plugin');
expect(toastr.warning).toBeCalledWith('warning');
await disablePlugin('plugin');
expect(showAjaxError).toBeCalled();
});
it('delete a plugin', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const reloadTable = jest.fn();
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
$.pluginsTable = {
ajax: {
reload: reloadTable
@ -399,6 +475,9 @@ describe('tests for "plugins" module', () => {
const deletePlugin = require(modulePath).deletePlugin;
await deletePlugin('plugin');
expect(fetch).not.toBeCalled();
await deletePlugin('plugin');
expect(swal).toBeCalledWith({
text: 'admin.confirmDeletion',
@ -410,10 +489,15 @@ describe('tests for "plugins" module', () => {
url: 'admin/plugins/manage?action=delete&name=plugin',
dataType: 'json'
});
await deletePlugin('plugin');
expect(toastr.warning).not.toBeCalled();
expect(toastr.success).toBeCalledWith('success');
expect(reloadTable).toBeCalledWith(null, false);
await deletePlugin('plugin');
expect(toastr.warning).toBeCalledWith('warning');
await deletePlugin('plugin');
expect(showAjaxError).toBeCalled();
});
});
@ -502,23 +586,28 @@ describe('tests for "users" module', () => {
it('change user email', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const swal = jest.fn(options => {
options.inputValidator('a@b.c');
return Promise.resolve('a@b.c');
});
const swal = jest.fn()
.mockImplementationOnce(() => Promise.reject())
.mockImplementationOnce(options => {
options.inputValidator('a@b.c');
return Promise.resolve('a@b.c');
});
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -532,6 +621,9 @@ describe('tests for "users" module', () => {
`;
const changeUserEmail = require(modulePath).changeUserEmail;
await changeUserEmail(1);
expect(fetch).not.toBeCalled();
await changeUserEmail(1);
expect(swal).toBeCalledWith(expect.objectContaining({
text: 'admin.newUserEmail',
@ -545,30 +637,40 @@ describe('tests for "users" module', () => {
dataType: 'json',
data: { uid: 1, email: 'a@b.c' }
});
await changeUserEmail(1);
expect($('tr > td:nth-child(2)').text()).toBe('a@b.c');
expect(toastr.success).toBeCalledWith('success');
await changeUserEmail(1);
expect(toastr.warning).toBeCalledWith('warning');
await changeUserEmail(1);
expect(showAjaxError).toBeCalled();
});
it('change user nick name', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const swal = jest.fn(options => {
options.inputValidator('foo');
return Promise.resolve('foo');
});
const swal = jest.fn()
.mockImplementationOnce(() => Promise.reject())
.mockImplementationOnce(options => {
options.inputValidator('foo');
return Promise.resolve('foo');
});
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -583,6 +685,9 @@ describe('tests for "users" module', () => {
`;
const changeUserNickName = require(modulePath).changeUserNickName;
await changeUserNickName(1);
expect(fetch).not.toBeCalled();
await changeUserNickName(1);
expect(swal).toBeCalledWith(expect.objectContaining({
text: 'admin.newUserNickname',
@ -596,30 +701,43 @@ describe('tests for "users" module', () => {
dataType: 'json',
data: { uid: 1, nickname: 'foo' }
});
await changeUserNickName(1);
expect($('tr > td:nth-child(3)').text()).toBe('foo');
expect(toastr.success).toBeCalledWith('success');
await changeUserNickName(1);
expect(toastr.warning).toBeCalledWith('warning');
await changeUserNickName(1);
expect(showAjaxError).toBeCalled();
});
it('change user password', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const swal = jest.fn().mockReturnValue(Promise.resolve('secret'));
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve('secret'));
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
const changeUserPwd = require(modulePath).changeUserPwd;
await changeUserPwd(1);
expect(fetch).not.toBeCalled();
await changeUserPwd(1);
expect(swal).toBeCalledWith(expect.objectContaining({
text: 'admin.newUserPassword',
@ -632,23 +750,30 @@ describe('tests for "users" module', () => {
dataType: 'json',
data: { uid: 1, password: 'secret' }
});
await changeUserPwd(1);
expect(toastr.success).toBeCalledWith('success');
await changeUserPwd(1);
expect(toastr.warning).toBeCalledWith('warning');
await changeUserPwd(1);
expect(showAjaxError).toBeCalled();
});
it('change user score', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -675,6 +800,9 @@ describe('tests for "users" module', () => {
await changeUserScore('user-1', 50);
expect(toastr.warning).toBeCalledWith('warning');
await changeUserScore('user-1', 50);
expect(showAjaxError).toBeCalled();
});
it('change ban status', async () => {
@ -689,18 +817,20 @@ describe('tests for "users" module', () => {
msg: 'success',
permission: -1
}))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -748,6 +878,9 @@ describe('tests for "users" module', () => {
await require(modulePath).changeBanStatus(1);
expect(toastr.warning).toBeCalledWith('warning');
await require(modulePath).changeBanStatus(1);
expect(showAjaxError).toBeCalled();
});
it('change admin status', async () => {
@ -762,18 +895,20 @@ describe('tests for "users" module', () => {
msg: 'success',
permission: 1
}))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<table>
@ -821,28 +956,39 @@ describe('tests for "users" module', () => {
await require(modulePath).changeAdminStatus(1);
expect(toastr.warning).toBeCalledWith('warning');
await require(modulePath).changeAdminStatus(1);
expect(showAjaxError).toBeCalled();
});
it('delete a user', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const trans = jest.fn(key => key);
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = '<tr id="user-1"></tr>';
const deleteUserAccount = require(modulePath).deleteUserAccount;
await deleteUserAccount(1);
expect(fetch).not.toBeCalled();
await deleteUserAccount(1);
expect(swal).toBeCalledWith({
text: 'admin.deleteUserNotice',
@ -855,8 +1001,13 @@ describe('tests for "users" module', () => {
dataType: 'json',
data: { uid: 1 }
});
await deleteUserAccount(1);
expect(document.getElementById('user-1')).toBeNull();
await deleteUserAccount(1);
expect(toastr.warning).toBeCalledWith('warning');
await deleteUserAccount(1);
expect(showAjaxError).toBeCalled();
});
it('"input" element should be focused out when press enter key', () => {

View File

@ -40,17 +40,20 @@ describe('tests for "login" module', () => {
))
.mockImplementationOnce(() => Promise.resolve(
{ errno: 1, msg: 'warning2', login_fails: 4 }
));
))
.mockImplementationOnce(() => Promise.reject());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn();
const refreshCaptcha = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.swal = swal;
window.showMsg = jest.fn();
window.refreshCaptcha = refreshCaptcha;
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<input id="identification" />
@ -108,6 +111,9 @@ describe('tests for "login" module', () => {
expect(swal).toBeCalledWith({ type: 'error', html: 'auth.tooManyFails' });
expect($('#captcha-form').css('display')).not.toBe('none');
expect(showMsg).toBeCalledWith('warning2', 'warning');
await $('button').click();
expect(showAjaxError).toBeCalled();
});
});
@ -126,18 +132,21 @@ describe('tests for "register" module', () => {
})
.mockImplementationOnce(() => Promise.resolve(
{ errno: 1, msg: 'warning' }
));
))
.mockImplementationOnce(() => Promise.reject(new Error));
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn().mockImplementation(() => Promise.resolve());
const showMsg = jest.fn();
const refreshCaptcha = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.swal = swal;
window.showMsg = showMsg;
window.refreshCaptcha = refreshCaptcha;
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<input id="email" />
@ -232,6 +241,9 @@ describe('tests for "register" module', () => {
expect(refreshCaptcha).toBeCalled();
expect(showMsg).toBeCalledWith('warning', 'warning');
expect($('button').html()).toBe('auth.register');
await $('button').click();
expect(showAjaxError).toBeCalled();
});
});
@ -246,18 +258,21 @@ describe('tests for "forgot" module', () => {
})
.mockImplementationOnce(() => Promise.resolve(
{ errno: 1, msg: 'warning' }
));
))
.mockImplementationOnce(() => Promise.reject(new Error));
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn();
const showMsg = jest.fn();
const refreshCaptcha = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.swal = swal;
window.showMsg = showMsg;
window.refreshCaptcha = refreshCaptcha;
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<input id="email" />
@ -302,6 +317,11 @@ describe('tests for "forgot" module', () => {
expect(refreshCaptcha).toBeCalled();
expect(showMsg).toBeCalledWith('warning', 'warning');
expect($('button').html()).toBe('auth.send');
await $('button').click();
expect($('button').html()).toBe('auth.send');
expect($('button').prop('disabled')).toBe(false);
expect(showAjaxError).toBeCalled();
});
});
@ -316,12 +336,14 @@ describe('tests for "reset" module', () => {
})
.mockImplementationOnce(() => Promise.resolve(
{ errno: 1, msg: 'warning' }
));
))
.mockImplementationOnce(() => Promise.reject(new Error));
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn().mockReturnValue(Promise.resolve());
const showMsg = jest.fn();
const getQueryString = jest.fn().mockReturnValue('token');
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
@ -329,6 +351,7 @@ describe('tests for "reset" module', () => {
window.showMsg = showMsg;
window.refreshCaptcha = jest.fn();
window.getQueryString = getQueryString;
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<input id="uid" value="1" />
@ -389,5 +412,9 @@ describe('tests for "reset" module', () => {
await $('button').click();
expect(showMsg).toBeCalledWith('warning', 'warning');
expect($('button').html()).toBe('auth.reset');
await $('button').click();
expect($('button').html()).toBe('auth.reset');
expect(showAjaxError).toBeCalled();
});
});

View File

@ -3,6 +3,43 @@
const $ = require('jquery');
window.jQuery = window.$ = $;
describe('tests for "cookie" module', () => {
it('operates cookies', () => {
const cookies = require('../common/cookie');
expect(cookies.hasItem('key1')).toBe(false);
expect(cookies.getItem('key1')).toBeNull();
expect(cookies.setItem('key1', 'value1')).toBe(true);
expect(document.cookie).toBe('key1=value1');
expect(cookies.setItem('key2', 'value2')).toBe(true);
expect(document.cookie).toBe('key1=value1; key2=value2');
expect(cookies.hasItem('key1')).toBe(true);
expect(cookies.getItem('key1')).toBe('value1');
expect(cookies.hasItem('key2')).toBe(true);
expect(cookies.getItem('key2')).toBe('value2');
expect(cookies.keys()).toEqual(['key1', 'key2']);
expect(cookies.setItem('domain', 'value')).toBe(false);
expect(cookies.removeItem('key0')).toBe(false);
expect(cookies.removeItem('key2')).toBe(true);
expect(cookies.hasItem('key2')).toBe(false);
expect(document.cookie).toBe('key1=value1');
expect(cookies.removeItem('key1')).toBe(true);
expect(cookies.setItem('key3', 'value3', 50));
expect(cookies.getItem('key3')).toBe('value3');
expect(cookies.setItem('key3', 'value3', Infinity));
expect(cookies.getItem('key3')).toBe('value3');
expect(cookies.setItem('key3', 'value3', '60'));
expect(cookies.getItem('key3')).toBe('value3');
expect(cookies.setItem('key4', 'value3', new Date));
expect(cookies.removeItem('key3')).toBe(true);
expect(document.cookie).toBe('');
});
});
describe('tests for "i18n" module', () => {
const modulePath = '../common/i18n';
@ -21,6 +58,11 @@ describe('tests for "i18n" module', () => {
it('get translated text', () => {
const trans = require(modulePath).trans;
$.currentLocale = undefined; // Should load locale automatically
$.locales = {
en: { text: 'text', nested: { sth: ':sth here!' } }
};
expect(trans('text')).toBe('text');
expect(trans('text.nothing')).toBe('text.nothing');
expect(trans('nested.sth')).toBe(':sth here!');
@ -28,22 +70,32 @@ describe('tests for "i18n" module', () => {
});
});
jest.useFakeTimers();
describe('tests for "logout" module', () => {
const modulePath = '../common/logout';
it('logout', async () => {
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const trans = jest.fn(key => key);
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ msg: 'success' }))
.mockReturnValueOnce(Promise.reject());
const showAjaxError = jest.fn();
window.swal = swal;
window.trans = trans;
window.fetch = fetch;
window.url = jest.fn(path => path);
window.showAjaxError = showAjaxError;
document.body.innerHTML = '<button id="logout-button"></button>';
require(modulePath);
await $('button').click();
expect(fetch).not.toBeCalled();
await $('button').click();
expect(swal).toBeCalledWith({
text: 'general.confirmLogout',
@ -57,11 +109,19 @@ describe('tests for "logout" module', () => {
url: 'auth/logout',
dataType: 'json'
});
jest.runAllTimers();
expect(url).toBeCalled();
await $('button').click();
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
await $('button').click();
expect(showAjaxError).toBeCalled();
});
});
jest.useRealTimers();
describe('tests for "notify" module', () => {
const modulePath = '../common/notify';
@ -87,6 +147,7 @@ describe('tests for "notify" module', () => {
const warn = jest.fn();
window.console.warn = warn;
window.trans = jest.fn(key => key);
$.fn.modal = jest.fn();
const showAjaxError = require(modulePath).showAjaxError;
@ -95,6 +156,9 @@ describe('tests for "notify" module', () => {
showAjaxError({});
expect(warn).toBeCalledWith('Empty Ajax response body.');
showAjaxError({ responseText: 'error' });
expect(window.trans).toBeCalledWith('general.fatalError');
});
it('show modal dialog', () => {
@ -146,6 +210,9 @@ describe('tests for "utils" module', () => {
expect(isEmpty('')).toBe(true);
expect(isEmpty({})).toBe(true);
expect(isEmpty({ sth: '' })).toBe(false);
expect(isEmpty([])).toBe(true);
expect(isEmpty([1])).toBe(false);
expect(isEmpty('something')).toBe(false);
});
it('fake fetch', () => {
@ -159,7 +226,8 @@ describe('tests for "utils" module', () => {
it('make a debounced function', done => {
const func = jest.fn();
const debounced = require(modulePath).debounce(func, 100);
const debounce = require(modulePath).debounce;
const debounced = debounce(func, 100);
debounced();
debounced();
@ -168,6 +236,9 @@ describe('tests for "utils" module', () => {
expect(func.mock.calls.length).toBe(1);
done();
}, 100);
expect(() => debounce(func, 'string')).toThrow();
expect(() => debounce('not a function', 100)).toThrow();
});
it('get a absolute url', () => {

View File

@ -157,13 +157,14 @@ describe('tests for "index" module', () => {
});
it('reload skin library', async () => {
const fetch = jest.fn().mockReturnValue(Promise.resolve({
const fetch = jest.fn().mockReturnValueOnce(Promise.resolve({
items: []
}));
})).mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div id="skinlib-paginator"></div>
`;
@ -241,7 +242,8 @@ describe('tests for "operations" module', () => {
it('add to closet (by ajax)', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
window.fetch = fetch;
const url = jest.fn(path => path);
window.url = url;
@ -255,6 +257,8 @@ describe('tests for "operations" module', () => {
warning: jest.fn()
};
window.toastr = toastr;
const showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
$.fn.modal = modal;
document.body.innerHTML = `
@ -277,17 +281,24 @@ describe('tests for "operations" module', () => {
await ajaxAddToCloset(1, 'name');
expect(toastr.warning).toBeCalledWith('warning');
await ajaxAddToCloset(1, 'name');
expect(showAjaxError).toBeCalled();
});
it('remove from closet', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
window.fetch = fetch;
const url = jest.fn(path => path);
window.url = url;
const trans = jest.fn(key => key);
window.trans = trans;
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
window.swal = swal;
const modal = jest.fn();
const toastr = {
@ -295,9 +306,14 @@ describe('tests for "operations" module', () => {
warning: jest.fn()
};
window.toastr = toastr;
const showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
const removeFromCloset = require(modulePath).removeFromCloset;
await removeFromCloset(1);
expect(fetch).not.toBeCalled();
await removeFromCloset(1);
expect(swal).toBeCalledWith({
text: 'user.removeFromClosetNotice',
@ -312,22 +328,31 @@ describe('tests for "operations" module', () => {
dataType: 'json',
data: { tid: 1 }
});
await removeFromCloset(1);
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
await removeFromCloset(1);
expect(toastr.warning).toBeCalledWith('warning');
await removeFromCloset(1);
expect(showAjaxError).toBeCalled();
});
it('change texture name', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
window.fetch = fetch;
const url = jest.fn(path => path);
window.url = url;
const trans = jest.fn(key => key);
window.trans = trans;
const swal = jest.fn(option => {
option.inputValidator('new-name');
return Promise.resolve('new-name');
});
const swal = jest.fn()
.mockImplementationOnce(() => Promise.reject())
.mockImplementationOnce(option => {
option.inputValidator('new-name');
return Promise.resolve('new-name');
});
window.swal = swal;
const modal = jest.fn();
const toastr = {
@ -335,10 +360,15 @@ describe('tests for "operations" module', () => {
warning: jest.fn()
};
window.toastr = toastr;
const showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = '<div id="name"></div>';
const changeTextureName = require(modulePath).changeTextureName;
await changeTextureName(1, 'oldName');
expect(fetch).not.toBeCalled();
await changeTextureName(1, 'oldName');
expect(swal).toBeCalledWith(expect.objectContaining({
text: 'skinlib.setNewTextureName',
@ -352,9 +382,14 @@ describe('tests for "operations" module', () => {
dataType: 'json',
data: { tid: 1, new_name: 'new-name' }
});
await changeTextureName(1, 'oldName');
expect($('div').text()).toBe('new-name');
expect(toastr.success).toBeCalledWith('success');
await changeTextureName(1, 'oldName');
expect(toastr.warning).toBeCalledWith('warning');
await changeTextureName(1, 'oldName');
expect(showAjaxError).toBeCalled();
});
it('update texture status', () => {
@ -416,7 +451,8 @@ describe('tests for "operations" module', () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success', public: '0' }))
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
window.fetch = fetch;
const url = jest.fn(path => path);
window.url = url;
@ -430,6 +466,8 @@ describe('tests for "operations" module', () => {
warning: jest.fn()
};
window.toastr = toastr;
const showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<a id="1">skinlib.setAsPrivate</a>
@ -453,17 +491,24 @@ describe('tests for "operations" module', () => {
await changePrivacy(1);
expect(toastr.warning).toBeCalledWith('warning');
await changePrivacy(1);
expect(showAjaxError).toBeCalled();
});
it('delete texture', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
window.fetch = fetch;
const url = jest.fn(path => path);
window.url = url;
const trans = jest.fn(key => key);
window.trans = trans;
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
window.swal = swal;
const modal = jest.fn();
const toastr = {
@ -471,9 +516,14 @@ describe('tests for "operations" module', () => {
warning: jest.fn()
};
window.toastr = toastr;
const showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
const deleteTexture = require(modulePath).deleteTexture;
await deleteTexture(1);
expect(fetch).not.toBeCalled();
await deleteTexture(1);
expect(swal).toBeCalledWith({
text: 'skinlib.deleteNotice',
@ -486,7 +536,13 @@ describe('tests for "operations" module', () => {
dataType: 'json',
data: { tid: 1 }
});
await deleteTexture(1);
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
expect(url).toBeCalledWith('skinlib');
await deleteTexture(1);
expect(swal).toBeCalledWith({ type: 'warning', html: 'warning' });
await deleteTexture(1);
expect(showAjaxError).toBeCalled();
});
});

View File

@ -11,18 +11,20 @@ describe('tests for "closet" module', () => {
it('preview textures', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ type: 'skin', hash: 1 }))
.mockReturnValueOnce(Promise.resolve({ type: 'cape', hash: 2 }));
.mockReturnValueOnce(Promise.resolve({ type: 'cape', hash: 2 }))
.mockReturnValueOnce(Promise.reject());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const MSP = {
changeSkin: jest.fn(),
changeCape: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.MSP = MSP;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div id="textures-indicator"></div>
@ -54,7 +56,6 @@ describe('tests for "closet" module', () => {
<div class="item-body"></div>
</div>
`;
window.selectedTextures = [];
await $('#next > .item-body').click();
expect(fetch).toBeCalledWith({
@ -65,6 +66,9 @@ describe('tests for "closet" module', () => {
expect($('#next').hasClass('item-selected')).toBe(true);
expect(MSP.changeCape).toBeCalledWith('textures/2');
expect($('#textures-indicator').text()).toBe('general.skin & general.cape');
await $('#next > .item-body').click();
expect(showAjaxError).toBeCalled();
});
it('render closet', () => {
@ -107,14 +111,14 @@ describe('tests for "closet" module', () => {
it('reload closet', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({
.mockReturnValueOnce(Promise.resolve({
items: [],
category: 'skin',
total_pages: 1
}));
}))
.mockReturnValueOnce(Promise.reject());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn().mockReturnValue(Promise.resolve('name'));
const toastr = {
success: jest.fn(),
warning: jest.fn()
@ -123,12 +127,12 @@ describe('tests for "closet" module', () => {
changeSkin: jest.fn(),
changeCape: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.swal = swal;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div id="skin-category">
@ -157,6 +161,9 @@ describe('tests for "closet" module', () => {
}
});
expect($('#closet-paginator').attr('last-skin-page')).toBe('1');
await reloadCloset('skin', 1, 'q');
expect(showAjaxError).toBeCalled();
});
it('calculate capacity of closet', () => {
@ -172,10 +179,17 @@ describe('tests for "closet" module', () => {
it('rename item', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn().mockReturnValue(Promise.resolve('name'));
const swal = jest.fn()
.mockImplementationOnce(() => Promise.reject())
.mockImplementationOnce(({ inputValidator }) => {
inputValidator('name');
return Promise.resolve('name');
});
const toastr = {
success: jest.fn(),
warning: jest.fn()
@ -184,12 +198,13 @@ describe('tests for "closet" module', () => {
changeSkin: jest.fn(),
changeCape: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.swal = swal;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div id="skin-category">
@ -204,6 +219,9 @@ describe('tests for "closet" module', () => {
`;
const renameClosetItem = require(modulePath).renameClosetItem;
await renameClosetItem(1, 'oldName');
expect(fetch).not.toBeCalled();
await renameClosetItem(1, 'oldName');
expect(swal).toBeCalledWith(expect.objectContaining({
title: trans('user.renameClosetItem'),
@ -217,18 +235,26 @@ describe('tests for "closet" module', () => {
dataType: 'json',
data: { tid: 1, new_name: 'name' }
});
await renameClosetItem(1, 'oldName');
expect(toastr.success).toBeCalledWith('success');
expect($('span').html('name'));
await renameClosetItem(1, 'oldName');
expect(toastr.warning).toBeCalledWith('warning');
await renameClosetItem(1, 'oldName');
expect(showAjaxError).toBeCalled();
});
it('remove item from closet', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const toastr = {
success: jest.fn(),
warning: jest.fn()
@ -237,12 +263,13 @@ describe('tests for "closet" module', () => {
changeSkin: jest.fn(),
changeCape: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.swal = swal;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div id="skin-category">
@ -251,6 +278,9 @@ describe('tests for "closet" module', () => {
`;
const removeFromCloset = require(modulePath).removeFromCloset;
await removeFromCloset(1);
expect(fetch).not.toBeCalled();
await removeFromCloset(1);
expect(swal).toBeCalledWith({
text: 'user.removeFromClosetNotice',
@ -263,22 +293,30 @@ describe('tests for "closet" module', () => {
dataType: 'json',
data: { tid: 1 }
});
await removeFromCloset(1);
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
expect(document.getElementById('shouldBeRemoved')).toBeNull();
expect(trans).toBeCalledWith('user.emptyClosetMsg', { url: url('skinlib?filter=skin') });
expect($('#skin-category').html()).toBe(
'<div class="empty-msg">user.emptyClosetMsg</div>'
);
await removeFromCloset(1);
expect(toastr.warning).toBeCalledWith('warning');
await removeFromCloset(1);
expect(showAjaxError).toBeCalled();
});
it('set avatar', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const toastr = {
success: jest.fn(),
warning: jest.fn()
@ -287,18 +325,22 @@ describe('tests for "closet" module', () => {
changeSkin: jest.fn(),
changeCape: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.trans = trans;
window.url = url;
window.swal = swal;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<img alt="User Image" src="src" />
`;
const setAsAvatar = require(modulePath).setAsAvatar;
await setAsAvatar(1);
expect(fetch).not.toBeCalled();
await setAsAvatar(1);
expect(swal).toBeCalledWith({
title: 'user.setAvatar',
@ -312,10 +354,14 @@ describe('tests for "closet" module', () => {
dataType: 'json',
data: { tid: 1 }
});
await setAsAvatar(1);
expect(toastr.success).toBeCalledWith('success');
expect($('img').attr('src').endsWith('src')).toBe(false);
await setAsAvatar(1);
expect(toastr.warning).toBeCalledWith('warning');
await setAsAvatar(1);
expect(showAjaxError).toBeCalled();
});
});
@ -325,27 +371,32 @@ describe('tests for "player" module', () => {
it('show player texture preview', async () => {
const url = jest.fn(path => path);
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({
.mockReturnValueOnce(Promise.resolve({
tid_steve: 1,
tid_alex: 2,
tid_cape: 3,
preference: 'steve',
preference: 'default',
player_name: 'name'
}));
window.url = url;
window.fetch = fetch;
window.showAjaxError = jest.fn();
window.TexturePreview = require('../common/texture-preview');
window.MSP = {
}))
.mockReturnValueOnce(Promise.reject());
const showAjaxError = jest.fn();
const MSP = {
changeSkin: jest.fn(),
changeCape: jest.fn(),
setStatus: jest.fn(),
getStatus: jest.fn()
};
window.url = url;
window.fetch = fetch;
window.showAjaxError = showAjaxError;
window.TexturePreview = require('../common/texture-preview');
window.MSP = MSP;
window.defaultSkin = 'steve_base64';
document.body.innerHTML = `
<div id="1" class="player-selected player"></div>
<div id="2" class="player"></div>
<div id="preview-switch"></div>
`;
require(modulePath);
@ -358,21 +409,29 @@ describe('tests for "player" module', () => {
dataType: 'json',
data: { pid: '2' }
});
await $('#2').click();
expect(showAjaxError).toBeCalled();
$('#preview-switch').click();
expect(window.TexturePreview.previewType).toBe('2D');
});
it('change player reference', async () => {
it('change player preference', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<select id="preference" pid="1">
@ -397,11 +456,16 @@ describe('tests for "player" module', () => {
await $('select').trigger('change');
expect(toastr.warning).toBeCalledWith('warning');
await $('select').trigger('change');
expect(showAjaxError).toBeCalled();
});
it('change player name', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const trans = jest.fn(key => key);
const toastr = {
@ -409,17 +473,18 @@ describe('tests for "player" module', () => {
warning: jest.fn()
};
const swal = jest.fn()
.mockImplementationOnce(() => Promise.reject())
.mockImplementationOnce(options => {
options.inputValidator('name');
return Promise.resolve('name');
})
.mockImplementation(() => Promise.resolve());
});
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.trans = trans;
window.toastr = toastr;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<input id="player_name" placeholder="placeholder" />
@ -432,6 +497,9 @@ describe('tests for "player" module', () => {
`;
const changePlayerName = require(modulePath).changePlayerName;
await changePlayerName(1);
expect(fetch).not.toBeCalled();
await changePlayerName(1);
expect(swal).toBeCalledWith(expect.objectContaining({
title: 'user.changePlayerName',
@ -446,27 +514,47 @@ describe('tests for "player" module', () => {
dataType: 'json',
data: { pid: 1, new_player_name: 'name' }
});
await changePlayerName(1);
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
expect($('#player-name').html()).toBe('name');
await changePlayerName(1);
expect(swal).toBeCalledWith({ type: 'warning', html: 'warning' });
await changePlayerName(1);
expect(showAjaxError).toBeCalled();
});
it('show "clear texture" modal dialog', () => {
const { clearTexture } = require(modulePath);
const trans = jest.fn(key => key);
const showModal = jest.fn();
window.trans = trans;
window.showModal = showModal;
clearTexture();
const args = showModal.mock.calls[0];
expect(args.includes('user.chooseClearTexture')).toBe(true);
expect(args.includes('default')).toBe(true);
});
it('submit clearing texture request', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const trans = jest.fn(key => key);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const showAjaxError = jest.fn();
const modal = jest.fn();
window.fetch = fetch;
window.url = url;
window.trans = trans;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
$.fn.modal = modal;
document.body.innerHTML = `
@ -496,28 +584,39 @@ describe('tests for "player" module', () => {
await ajaxClearTexture(1);
expect(swal).lastCalledWith({ type: 'error', html: 'warning' });
await ajaxClearTexture(1);
expect(showAjaxError).toBeCalled();
});
it('delete player', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<tr id="1"></tr>
`;
const deletePlayer = require(modulePath).deletePlayer;
await deletePlayer(1);
expect(fetch).not.toBeCalled();
await deletePlayer(1);
expect(swal).toBeCalledWith({
title: 'user.deletePlayer',
@ -533,16 +632,21 @@ describe('tests for "player" module', () => {
dataType: 'json',
data: { pid: 1 }
});
await deletePlayer(1);
expect(swal).lastCalledWith({ type: 'success', html: 'success' });
expect(document.getElementById('1')).toBeNull();
await deletePlayer(1);
expect(toastr.warning).toBeCalledWith('warning');
await deletePlayer(1);
expect(showAjaxError).toBeCalled();
});
it('add a new player', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
@ -550,11 +654,12 @@ describe('tests for "player" module', () => {
};
const swal = jest.fn().mockReturnValue(Promise.resolve());
const modal = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
$.fn.modal = modal;
document.body.innerHTML = `
@ -570,31 +675,36 @@ describe('tests for "player" module', () => {
data: { player_name: 'name' }
});
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
expect(modal).toBeCalled();
await addNewPlayer();
expect(toastr.warning).toBeCalledWith('warning');
expect(modal.mock.calls.length).toBe(1);
await addNewPlayer();
expect(showAjaxError).toBeCalled();
});
it('set texture', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const url = jest.fn(path => path);
const toastr = {
success: jest.fn(),
warning: jest.fn(),
info: jest.fn()
};
const swal = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn();
const modal = jest.fn();
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.toastr = toastr;
window.swal = swal;
$.fn.modal = modal;
window.selectedTextures = {};
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<input name="player" id="1" />
@ -622,6 +732,9 @@ describe('tests for "player" module', () => {
await setTexture();
expect(toastr.warning).toBeCalledWith('warning');
expect(modal.mock.calls.length).toBe(1);
await setTexture();
expect(showAjaxError).toBeCalled();
});
});
@ -630,16 +743,22 @@ describe('tests for "profile" module', () => {
it('change nickname', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
const swal = jest.fn().mockReturnValue(Promise.resolve());
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const swal = jest.fn()
.mockReturnValueOnce(Promise.resolve())
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const showAjaxError = jest.fn();
window.fetch = fetch;
window.swal = swal;
window.trans = trans;
window.url = url;
window.debounce = jest.fn(fn => fn);
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div class="nickname"></div>
@ -649,8 +768,12 @@ describe('tests for "profile" module', () => {
await changeNickName();
expect(swal).toBeCalledWith({ type: 'error', html: 'user.emptyNewNickName' });
expect(fetch).not.toBeCalled();
$('input').val('name');
await changeNickName();
expect(fetch).not.toBeCalled();
await changeNickName();
expect(trans).toBeCalledWith('user.changeNickName', { new_nickname: 'name' });
expect(swal).toBeCalledWith({
@ -664,17 +787,22 @@ describe('tests for "profile" module', () => {
dataType: 'json',
data: { new_nickname: 'name' }
});
await changeNickName();
expect($('.nickname').text()).toBe('name');
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
await changeNickName();
expect(swal).toBeCalled();
await changeNickName();
expect(showAjaxError).toBeCalled();
});
it('change password', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
.mockReturnValueOnce(Promise.reject());
const swal = jest.fn().mockReturnValue(Promise.resolve());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
@ -682,13 +810,20 @@ describe('tests for "profile" module', () => {
info: jest.fn(),
warning: jest.fn()
};
const showAjaxError = jest.fn();
const docCookies = {
removeItem: jest.fn()
};
window.fetch = fetch;
window.swal = swal;
window.trans = trans;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.logout = jest.fn().mockReturnValue(Promise.resolve({ errno: 0 }));
window.showAjaxError = showAjaxError;
window.logout = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0 }))
.mockReturnValueOnce(Promise.reject());
window.docCookies = docCookies;
document.body.innerHTML = `
<input id="password" />
@ -725,32 +860,49 @@ describe('tests for "profile" module', () => {
dataType: 'json',
data: { current_password: 'password', new_password: 'new-password' }
});
expect(logout).toBeCalled();
await changePassword();
expect(docCookies.removeItem).toBeCalledWith('token');
await changePassword();
expect(swal).toBeCalledWith({ type: 'warning', text: 'warning' });
await changePassword();
expect(logout).toBeCalled();
expect(showAjaxError).toBeCalled();
});
it('change email', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
const swal = jest.fn().mockReturnValue(Promise.resolve());
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const swal = jest.fn()
.mockReturnValueOnce(Promise.resolve())
.mockReturnValueOnce(Promise.resolve())
.mockReturnValueOnce(Promise.reject())
.mockReturnValue(Promise.resolve());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const toastr = {
info: jest.fn(),
warning: jest.fn()
};
const showAjaxError = jest.fn();
const docCookies = {
removeItem: jest.fn()
};
window.fetch = fetch;
window.swal = swal;
window.trans = trans;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.logout = jest.fn().mockReturnValue(Promise.resolve({ errno: 0 }));
window.showAjaxError = showAjaxError;
window.logout = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0 }))
.mockReturnValueOnce(Promise.reject());
window.docCookies = docCookies;
document.body.innerHTML = `
<input id="new-email" />
@ -758,14 +910,17 @@ describe('tests for "profile" module', () => {
`;
const changeEmail = require(modulePath).changeEmail;
changeEmail();
await changeEmail();
expect(swal).toBeCalledWith({ type: 'error', html: 'user.emptyNewEmail' });
expect(fetch).not.toBeCalled();
$('#new-email').val('email');
changeEmail();
await changeEmail();
expect(swal).toBeCalledWith({ type: 'warning', html: 'auth.invalidEmail' });
$('#new-email').val('a@b.c');
await changeEmail(); // Suppose the user cancelled changing email
await changeEmail();
expect(trans).toBeCalledWith('user.changeEmail', { new_email: 'a@b.c' });
expect(swal).toBeCalledWith({
@ -779,12 +934,24 @@ describe('tests for "profile" module', () => {
dataType: 'json',
data: { new_email: 'a@b.c', password: 'pwd' }
});
expect(swal).toBeCalledWith({ type: 'success', text: 'success' });
expect(logout).toBeCalled();
await changeEmail();
expect(docCookies.removeItem).toBeCalled();
await changeEmail();
expect(swal).toBeCalledWith({ type: 'warning', text: 'warning' });
await changeEmail();
expect(showAjaxError).toBeCalled();
});
it('delete account', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
const swal = jest.fn().mockReturnValue(Promise.resolve());
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
@ -792,12 +959,13 @@ describe('tests for "profile" module', () => {
info: jest.fn(),
warning: jest.fn()
};
const showAjaxError = jest.fn();
window.fetch = fetch;
window.swal = swal;
window.trans = trans;
window.url = url;
window.toastr = toastr;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<div class="modal-body">
@ -806,7 +974,7 @@ describe('tests for "profile" module', () => {
`;
const deleteAccount = require(modulePath).deleteAccount;
deleteAccount();
await deleteAccount();
expect(swal).toBeCalledWith({ type: 'warning', html: 'user.emptyDeletePassword' });
$('#password').val('password');
@ -818,9 +986,13 @@ describe('tests for "profile" module', () => {
data: { password: 'password' }
});
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
expect(url).toBeCalledWith('auth/login');
await deleteAccount();
expect(swal).toBeCalledWith({ type: 'warning', html: 'warning' });
await deleteAccount();
expect(showAjaxError).toBeCalled();
});
});
@ -835,11 +1007,12 @@ describe('tests for "sign" module', () => {
};
const trans = jest.fn(key => key);
const swal = jest.fn().mockReturnValue(Promise.resolve());
const showAjaxError = jest.fn();
window.url = url;
window.toastr = toastr;
window.trans = trans;
window.swal = swal;
window.showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
window.debounce = fn => fn;
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({
@ -864,7 +1037,8 @@ describe('tests for "sign" module', () => {
percentage: 50
}
}))
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }));
.mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' }))
.mockReturnValueOnce(Promise.reject());
window.fetch = fetch;
document.body.innerHTML = `
@ -903,5 +1077,8 @@ describe('tests for "sign" module', () => {
await sign();
expect(toastr.warning).toBeCalledWith('warning');
await sign();
expect(showAjaxError).toBeCalled();
});
});

View File

@ -23,27 +23,30 @@ $(document).ready(() => {
}
});
function sendFeedback() {
async function sendFeedback() {
if (docCookies.getItem('feedback_sent') !== null)
return;
fetch({
url: 'https://work.prinzeugen.net/statistics/feedback',
type: 'POST',
dataType: 'json',
data: {
site_name: blessing.site_name,
site_url: blessing.base_url,
version: blessing.version
}
}).then(({ errno }) => {
try {
const { errno } = await fetch({
url: 'https://work.prinzeugen.net/statistics/feedback',
type: 'POST',
dataType: 'json',
data: {
site_name: blessing.site_name,
site_url: blessing.base_url,
version: blessing.version
}
});
if (errno === 0) {
// Will be expired when current session ends
docCookies.setItem('feedback_sent', Date.now());
console.log('Feedback sent. Thank you!');
}
});
} catch (error) {
//
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -9,15 +9,18 @@ $('#layout-skins-list [data-skin]').click(function (e) {
current_skin = skin_name;
});
function submitColor() {
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(showAjaxError);
async function submitColor() {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/customize?action=color'),
dataType: 'json',
data: { color_scheme: current_skin }
});
errno == 0 ? toastr.success(msg) : toastr.warning(msg);
} catch (error) {
showAjaxError(error);
}
}
$('#color-submit').click(submitColor);

View File

@ -1,17 +1,20 @@
'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(showAjaxError);
async function changePreference() {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/players?action=preference'),
dataType: 'json',
data: {
pid: $(this).parent().parent().attr('id'),
preference: $(this).val()
}
});
errno == 0 ? toastr.success(msg) : toastr.warning(msg);
} catch (error) {
showAjaxError(error);
}
}
function changeTexture(pid, playerName) {
@ -35,21 +38,22 @@ function changeTexture(pid, playerName) {
return;
}
function ajaxChangeTexture(pid) {
async 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();
const model = $('#model').val();
const tid = $('#tid').val();
fetch({
type: 'POST',
url: url('admin/players?action=texture'),
dataType: 'json',
data: { pid: pid, model: model, tid: tid }
}).then(({ errno, msg }) => {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/players?action=texture'),
dataType: 'json',
data: { pid: pid, model: model, tid: tid }
});
if (errno == 0) {
$(`#${pid}-${model}`).attr('src', url(`preview/64/${tid}.png`));
$('.modal').modal('hide');
@ -58,26 +62,35 @@ function ajaxChangeTexture(pid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function changePlayerName(pid, oldName) {
async function changePlayerName(pid, oldName) {
let dom = $(`tr#${pid} > td:nth-child(3)`);
let newPlayerName = '';
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 }) => {
try {
newPlayerName = await swal({
text: trans('admin.changePlayerNameNotice'),
input: 'text',
inputValue: oldName,
inputValidator: name => (new Promise((resolve, reject) => {
name ? resolve() : reject(trans('admin.emptyPlayerName'));
}))
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/players?action=name'),
dataType: 'json',
data: { pid: pid, name: newPlayerName }
});
if (errno == 0) {
dom.text(newPlayerName);
@ -85,7 +98,9 @@ function changePlayerName(pid, oldName) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function changeOwner(pid) {
@ -97,68 +112,81 @@ function changeOwner(pid) {
input: 'number',
inputValue: dom.text(),
showCancelButton: true
}).then(uid => {
}).then(async 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);
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/players?action=owner'),
dataType: 'json',
data: { pid, uid }
});
if (errno == 0) {
dom.text(owner);
toastr.success(msg);
} else {
toastr.warning(msg);
}
} catch (error) {
showAjaxError(error);
}
}).catch(showAjaxError);
});
$('.swal2-input').on('input', debounce(() => {
$('.swal2-input').on('input', debounce(async () => {
let uid = $('.swal2-input').val();
if (isNaN(uid) || uid <= 0)
return;
fetch({
type: 'GET',
url: url(`admin/user/${uid}`),
dataType: 'json'
}).then(result => {
try {
const { user } = await fetch({
type: 'GET',
url: url(`admin/user/${uid}`),
dataType: 'json'
});
$('.swal2-content').html(
trans('admin.changePlayerOwner') +
'<small style="display: block; margin-top: .5em;">' +
trans('admin.targetUser', { nickname: result.user.nickname }) +
trans('admin.targetUser', { nickname: user.nickname }) +
'</small>'
);
}).catch(() => {
} catch (error) {
$('.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 }) => {
async function deletePlayer(pid) {
try {
await swal({
text: trans('admin.deletePlayerNotice'),
type: 'warning',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/players?action=delete'),
dataType: 'json',
data: { pid: pid }
});
if (errno == 0) {
$(`tr#${pid}`).remove();
toastr.success(msg);
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -1,11 +1,12 @@
'use strict';
function enablePlugin(name) {
fetch({
type: 'POST',
url: url(`admin/plugins/manage?action=enable&name=${name}`),
dataType: 'json'
}).then(({ errno, msg }) => {
async function enablePlugin(name) {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url(`admin/plugins/manage?action=enable&name=${name}`),
dataType: 'json'
});
if (errno == 0) {
toastr.success(msg);
@ -13,15 +14,18 @@ function enablePlugin(name) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function disablePlugin(name) {
fetch({
type: 'POST',
url: url(`admin/plugins/manage?action=disable&name=${name}`),
dataType: 'json'
}).then(({ errno, msg }) => {
async function disablePlugin(name) {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url(`admin/plugins/manage?action=disable&name=${name}`),
dataType: 'json'
});
if (errno == 0) {
toastr.success(msg);
@ -29,19 +33,28 @@ function disablePlugin(name) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function deletePlugin(name) {
swal({
text: trans('admin.confirmDeletion'),
type: 'warning',
showCancelButton: true
}).then(() => fetch({
type: 'POST',
url: url(`admin/plugins/manage?action=delete&name=${name}`),
dataType: 'json'
})).then(({ errno, msg }) => {
async function deletePlugin(name) {
try {
await swal({
text: trans('admin.confirmDeletion'),
type: 'warning',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url(`admin/plugins/manage?action=delete&name=${name}`),
dataType: 'json'
});
if (errno == 0) {
toastr.success(msg);
@ -49,7 +62,9 @@ function deletePlugin(name) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -88,14 +88,17 @@ function downloadUpdates() {
}
function checkForUpdates() {
fetch({ url: url('admin/update/check') }).then(data => {
async function checkForUpdates() {
try {
const data = await fetch({ url: url('admin/update/check') });
if (data.available == true) {
let dom = `<span class="label label-primary pull-right">v${data.latest}</span>`;
$(`[href="${url('admin/update')}"]`).append(dom);
}
});
} catch (error) {
//
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -1,23 +1,31 @@
'use strict';
function changeUserEmail(uid) {
async 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 }) => {
try {
newUserEmail = await swal({
text: trans('admin.newUserEmail'),
showCancelButton: true,
input: 'text',
inputValue: dom.text(),
inputValidator: value => (new Promise((resolve, reject) => {
value ? resolve() : reject(trans('auth.emptyEmail'));
}))
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/users?action=email'),
dataType: 'json',
data: { uid: uid, email: newUserEmail }
});
if (errno == 0) {
dom.text(newUserEmail);
@ -25,27 +33,36 @@ function changeUserEmail(uid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function changeUserNickName(uid) {
async 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 }) => {
try {
newNickName = await swal({
text: trans('admin.newUserNickname'),
showCancelButton: true,
input: 'text',
inputValue: dom.text(),
inputValidator: value => (new Promise((resolve, reject) => {
value ? resolve() : reject(trans('auth.emptyNickname'));
}))
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/users?action=nickname'),
dataType: 'json',
data: { uid: uid, nickname: newNickName }
});
if (errno == 0) {
dom.text(newNickName);
@ -53,43 +70,60 @@ function changeUserNickName(uid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
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(showAjaxError);
async function changeUserPwd(uid) {
let password;
try {
password = await swal({
text: trans('admin.newUserPassword'),
showCancelButton: true,
input: 'password',
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/users?action=password'),
dataType: 'json',
data: { uid: uid, password: password }
});
errno == 0 ? toastr.success(msg) : toastr.warning(msg);
} catch (error) {
showAjaxError(error);
}
}
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(showAjaxError);
async function changeUserScore(uid, score) {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/users?action=score'),
dataType: 'json',
// Handle id formatted as '#user-1234'
data: { uid: uid.slice(5), score: score }
});
errno == 0 ? toastr.success(msg) : toastr.warning(msg);
} catch (error) {
showAjaxError(error);
}
}
function changeBanStatus(uid) {
fetch({
type: 'POST',
url: url('admin/users?action=ban'),
dataType: 'json',
data: { uid: uid }
}).then(({ errno, msg, permission }) => {
async function changeBanStatus(uid) {
try {
const { errno, msg, permission } = await fetch({
type: 'POST',
url: url('admin/users?action=ban'),
dataType: 'json',
data: { uid: uid }
});
if (errno == 0) {
let dom = $(`#ban-${uid}`);
@ -107,16 +141,20 @@ function changeBanStatus(uid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function changeAdminStatus(uid) {
fetch({
type: 'POST',
url: url('admin/users?action=admin'),
dataType: 'json',
data: { uid: uid }
}).then(({ errno, msg, permission }) => {
async function changeAdminStatus(uid) {
try {
const { errno, msg, permission } = await fetch({
type: 'POST',
url: url('admin/users?action=admin'),
dataType: 'json',
data: { uid: uid }
});
if (errno == 0) {
let dom = $(`#admin-${uid}`);
@ -134,27 +172,39 @@ function changeAdminStatus(uid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
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 }) => {
async function deleteUserAccount(uid) {
try {
await swal({
text: trans('admin.deleteUserNotice'),
type: 'warning',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('admin/users?action=delete'),
dataType: 'json',
data: { uid: uid }
});
if (errno == 0) {
$('tr#user-' + uid).remove();
toastr.success(msg);
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
$('body').on('keypress', '.score', function(event){

View File

@ -22,18 +22,19 @@ $('#forgot-button').click(e => {
} 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 }) => {
})(data, async () => {
try {
const { errno, msg } = await 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');
}
});
if (errno == 0) {
showMsg(msg, 'success');
$('#forgot-button').html(trans('auth.send')).prop('disabled', 'disabled');
@ -42,9 +43,9 @@ $('#forgot-button').click(e => {
refreshCaptcha();
$('#forgot-button').html(trans('auth.send')).prop('disabled', '');
}
}).catch(err => {
showAjaxError(err);
} catch (error) {
showAjaxError(error);
$('#forgot-button').html(trans('auth.send')).prop('disabled', '');
});
}
});
});

View File

@ -2,7 +2,7 @@
'use strict';
$('#login-button').click(e => {
$('#login-button').click(async e => {
e.preventDefault();
let data = {
@ -29,21 +29,22 @@ $('#login-button').click(e => {
}
}
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 }) => {
try {
const { errno, msg, login_fails } = await 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');
}
});
if (errno == 0) {
swal({ type: 'success', html: msg });
window.setTimeout(() => {
setTimeout(() => {
window.location = url(blessing.redirect_to || 'user');
}, 1000);
} else {
@ -60,9 +61,9 @@ $('#login-button').click(e => {
showMsg(msg, 'warning');
$('#login-button').html(trans('auth.login')).prop('disabled', '');
}
}).catch(err => {
showAjaxError(err);
} catch (error) {
showAjaxError(error);
$('#login-button').html(trans('auth.login')).prop('disabled', '');
});
}
}
});

View File

@ -43,18 +43,19 @@ $('#register-button').click(e => {
}
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, redirect }) => {
})(data, async () => {
try {
const { errno, msg, redirect } = await 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');
}
});
if (errno == 0) {
swal({ type: 'success', html: msg })
.then(() => window.location = url('user'));
@ -69,9 +70,9 @@ $('#register-button').click(e => {
refreshCaptcha();
$('#register-button').html(trans('auth.register')).prop('disabled', '');
}
}).catch(err => {
showAjaxError(err);
} catch (error) {
showAjaxError(error);
$('#register-button').html(trans('auth.register')).prop('disabled', '');
});
}
});
});

View File

@ -25,18 +25,19 @@ $('#reset-button').click(e => {
} 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 }) => {
})(data, async () => {
try {
const { errno, msg } = await 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');
}
});
if (errno == 0) {
swal({
type: 'success',
@ -46,9 +47,9 @@ $('#reset-button').click(e => {
showMsg(msg, 'warning');
$('#reset-button').html(trans('auth.reset')).prop('disabled', '');
}
}).catch(err => {
showAjaxError(err);
} catch (error) {
showAjaxError(error);
$('#reset-button').html(trans('auth.reset')).prop('disabled', '');
});
}
});
});

View File

@ -1,21 +1,28 @@
'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);
async function confirmLogout() {
try {
await swal({
text: trans('general.confirmLogout'),
type: 'warning',
showCancelButton: true,
confirmButtonText: trans('general.confirm'),
cancelButtonText: trans('general.cancel')
});
});
} catch (error) {
return;
}
try {
const { msg } = await logout();
setTimeout(() => window.location = url(), 1000);
swal({
type: 'success',
html: msg
});
} catch (error) {
showAjaxError(error);
}
}
function logout() {

View File

@ -79,16 +79,20 @@ function renderSkinlib(items) {
$('.overlay').hide();
}
function reloadSkinlib() {
requestSkinlibData().then(result => {
async function reloadSkinlib() {
try {
const result = await requestSkinlibData();
$('.overlay').show();
renderSkinlib(result.items);
updatePaginator($.skinlib.page, result.total_pages || 1);
}).then(() => {
updateUrlQueryString();
updateBreadCrumb();
});
} catch (error) {
showAjaxError(error);
}
}
function requestSkinlibData() {

View File

@ -14,31 +14,38 @@ $(document).on('click', '.more.like', function () {
});
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));
$.getJSON(url(`skinlib/info/${tid}`), async ({ name }) => {
try {
const result = await swal({
title: trans('skinlib.setItemName'),
inputValue: name,
input: 'text',
showCancelButton: true,
inputValidator: value => (new Promise((resolve, reject) => {
value ? resolve() : reject(trans('skinlib.emptyItemName'));
}))
});
ajaxAddToCloset(tid, result);
} catch (error) {
//
}
});
}
function ajaxAddToCloset(tid, name) {
async 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 }) => {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/closet/add'),
dataType: 'json',
data: { tid: tid, name: name }
});
if (errno == 0) {
swal({ type: 'success', html: msg });
@ -47,22 +54,32 @@ function ajaxAddToCloset(tid, name) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
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 }) => {
async function removeFromCloset(tid) {
try {
await swal({
text: trans('user.removeFromClosetNotice'),
type: 'warning',
showCancelButton: true,
cancelButtonColor: '#3085d6',
confirmButtonColor: '#d33'
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('/user/closet/remove'),
dataType: 'json',
data: { tid: tid }
});
if (errno == 0) {
swal({ type: 'success', html: msg });
@ -70,33 +87,45 @@ function removeFromCloset(tid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function changeTextureName(tid, oldName) {
async 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 }) => {
try {
newTextureName = await swal({
text: trans('skinlib.setNewTextureName'),
input: 'text',
inputValue: oldName,
showCancelButton: true,
inputValidator: value => (new Promise((resolve, reject) => {
value ? resolve() : reject(trans('skinlib.emptyNewTextureName'));
}))
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('skinlib/rename'),
dataType: 'json',
data: { tid: tid, new_name: newTextureName }
});
if (errno == 0) {
$('#name').text(newTextureName);
toastr.success(msg);
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
/**
@ -120,25 +149,30 @@ function updateTextureStatus(tid, action) {
$('#likes').html(likes);
}
$(document).on('click', '.private-label', function () {
swal({
text: trans('skinlib.setPublicNotice'),
type: 'warning',
showCancelButton: true
}).then(() => {
$(document).on('click', '.private-label', async function () {
try {
await swal({
text: trans('skinlib.setPublicNotice'),
type: 'warning',
showCancelButton: true
});
changePrivacy($(this).attr('tid'));
$(this).remove();
});
} catch (error) {
//
}
});
function changePrivacy(tid) {
fetch({
type: 'POST',
url: url('skinlib/privacy'),
dataType: 'json',
data: { tid: tid }
}).then(result => {
let { errno, msg } = result;
async function changePrivacy(tid) {
try {
const result = await fetch({
type: 'POST',
url: url('skinlib/privacy'),
dataType: 'json',
data: { tid: tid }
});
const { errno, msg } = result;
if (errno == 0) {
toastr.success(msg);
@ -151,28 +185,39 @@ function changePrivacy(tid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
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 }) => {
async function deleteTexture(tid) {
try {
await swal({
text: trans('skinlib.deleteNotice'),
type: 'warning',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('skinlib/delete'),
dataType: 'json',
data: { tid: tid }
});
if (errno == 0) {
swal({ type: 'success', html: msg }).then(() => {
window.location = url('skinlib');
});
await swal({ type: 'success', html: msg });
window.location = url('skinlib');
} else {
swal({ type: 'warning', html: msg });
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -85,25 +85,27 @@ function upload() {
} 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 }) => {
})(form, file, async () => {
try {
const { errno, msg, tid } = await 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');
}
});
if (errno == 0) {
let redirect = function () {
toastr.info(trans('skinlib.redirecting'));
window.setTimeout(() => {
setTimeout(() => {
window.location = url(`skinlib/show/${tid}`);
}, 1000);
};
@ -114,17 +116,16 @@ function upload() {
html: msg
}).then(redirect, redirect);
} else {
swal({
await swal({
type: 'warning',
html: msg
}).then(() => {
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
});
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
}
}).catch(err => {
showAjaxError(err);
} catch (error) {
showAjaxError(error);
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
});
}
});
}

View File

@ -4,17 +4,24 @@
var selectedTextures = [];
$(document).ready(function () {
$(document).ready(async function () {
if (! window.location.pathname.includes('/user/closet'))
return;
fetch({
type: 'GET',
url: url('/user/closet-data'),
dataType: 'json'
}).then(({ items, category, total_pages }) => {
renderCloset(items, category);
$('input[name=q]').on('input', debounce(() => {
let category = $('#skin-category').hasClass('active') ? 'skin' : 'cape';
reloadCloset(category, 1, $('input[name=q]').val());
}, 350));
try {
const { items, category, total_pages } = await fetch({
type: 'GET',
url: url('/user/closet-data'),
dataType: 'json'
});
renderCloset(items, category);
$('#closet-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
totalPages: total_pages,
onPageChange: page => reloadCloset(
@ -22,15 +29,12 @@ $(document).ready(function () {
page, $('input[name=q]').val()
)
}));
}).catch(showAjaxError);
$('input[name=q]').on('input', debounce(() => {
let category = $('#skin-category').hasClass('active') ? 'skin' : 'cape';
reloadCloset(category, 1, $('input[name=q]').val());
}, 350));
} catch (error) {
showAjaxError(error);
}
});
$('body').on('click', '.item-body', function () {
$('body').on('click', '.item-body', async function () {
$('.item-selected').parent().removeClass('item-selected');
let $item = $(this).parent();
@ -38,11 +42,13 @@ $('body').on('click', '.item-body', function () {
let tid = parseInt($item.attr('tid'));
fetch({
type: 'POST',
url: url(`skinlib/info/${tid}`),
dataType: 'json'
}).then(({ type, hash }) => {
try {
const { type, hash } = await fetch({
type: 'POST',
url: url(`skinlib/info/${tid}`),
dataType: 'json'
});
if (type == 'cape') {
MSP.changeCape(url(`textures/${hash}`));
selectedTextures['cape'] = tid;
@ -63,7 +69,9 @@ $('body').on('click', '.item-body', function () {
} else if (cape != undefined) {
$indicator.text(trans('general.cape'));
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
});
$('body').on('click', '.category-switch', () => {
@ -131,31 +139,35 @@ function renderCloset(items, category) {
* Reload and render closet.
*
* @param {string} category
* @param {integer} page
* @param {number} page
* @param {string} search
*/
function reloadCloset(category, page, search) {
fetch({
type: 'GET',
url: url('user/closet-data'),
dataType: 'json',
data: {
category: category,
page: page,
perPage: getCapacityOfCloset(),
q: search
}
}).then(({ items, category, total_pages }) => {
async function reloadCloset(textureCategory, page, search) {
try {
const { items, category, total_pages } = await fetch({
type: 'GET',
url: url('user/closet-data'),
dataType: 'json',
data: {
category: textureCategory,
page: page,
perPage: getCapacityOfCloset(),
q: search
}
});
renderCloset(items, category);
let paginator = $('#closet-paginator');
paginator.attr(`last-${category}-page`, page);
paginator.jqPaginator('option', {
currentPage: page,
totalPages: total_pages
});
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
/**
@ -170,23 +182,31 @@ function getCapacityOfCloset() {
) * 2;
}
function renameClosetItem(tid, oldName) {
async 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('user/closet/rename'),
dataType: 'json',
data: { tid: tid, new_name: name }
})).then(({ errno, msg }) => {
try {
newTextureName = await swal({
title: trans('user.renameClosetItem'),
input: 'text',
inputValue: oldName,
showCancelButton: true,
inputValidator: value => (new Promise((resolve, reject) => {
value ? resolve() : reject(trans('skinlib.emptyNewTextureName'));
}))
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/closet/rename'),
dataType: 'json',
data: { tid: tid, new_name: newTextureName }
});
if (errno == 0) {
const type = $(`[tid=${tid}]`).data('texture-type');
$(`[tid=${tid}]>.item-footer>.texture-name>span`).html(
@ -197,20 +217,30 @@ function renameClosetItem(tid, oldName) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function removeFromCloset(tid) {
swal({
text: trans('user.removeFromClosetNotice'),
type: 'warning',
showCancelButton: true
}).then(() => fetch({
type: 'POST',
url: url('user/closet/remove'),
dataType: 'json',
data: { tid: tid }
})).then(({ errno, msg }) => {
async function removeFromCloset(tid) {
try {
await swal({
text: trans('user.removeFromClosetNotice'),
type: 'warning',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/closet/remove'),
dataType: 'json',
data: { tid: tid }
});
if (errno == 0) {
swal({ type: 'success', html: msg });
@ -227,21 +257,31 @@ function removeFromCloset(tid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function setAsAvatar(tid) {
swal({
title: trans('user.setAvatar'),
text: trans('user.setAvatarNotice'),
type: 'question',
showCancelButton: true
}).then(() => fetch({
type: 'POST',
url: url('user/profile/avatar'),
dataType: 'json',
data: { tid: tid }
})).then(({ errno, msg }) => {
async function setAsAvatar(tid) {
try {
await swal({
title: trans('user.setAvatar'),
text: trans('user.setAvatarNotice'),
type: 'question',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/profile/avatar'),
dataType: 'json',
data: { tid: tid }
});
if (errno == 0) {
toastr.success(msg);
@ -252,7 +292,9 @@ function setAsAvatar(tid) {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -9,24 +9,29 @@ $('body').on('click', '.player', function () {
showPlayerTexturePreview(this.id);
}).on('click', '#preview-switch', () => {
TexturePreview.previewType == '3D' ? TexturePreview.show2dPreview() : TexturePreview.show3dPreview();
}).on('change', '#preference', function () {
fetch({
type: 'POST',
url: url('user/player/preference'),
dataType: 'json',
data: { pid: $(this).attr('pid'), preference: $(this).val() }
}).then(({ errno, msg }) => {
(errno == 0) ? toastr.success(msg) : toastr.warning(msg);
}).catch(showAjaxError);
}).on('change', '#preference', async function () {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/player/preference'),
dataType: 'json',
data: { pid: $(this).attr('pid'), preference: $(this).val() }
});
errno == 0 ? toastr.success(msg) : toastr.warning(msg);
} catch (error) {
showAjaxError(error);
}
});
function showPlayerTexturePreview(pid) {
fetch({
type: 'POST',
url: url('user/player/show'),
dataType: 'json',
data: { pid: pid }
}).then(result => {
async function showPlayerTexturePreview(pid) {
try {
const result = await fetch({
type: 'POST',
url: url('user/player/show'),
dataType: 'json',
data: { pid: pid }
});
// Render skin preview of selected player
['steve', 'alex', 'cape'].forEach((type) => {
let tid = result[`tid_${type}`];
@ -47,37 +52,48 @@ function showPlayerTexturePreview(pid) {
}
console.log(`Texture previews of player ${result.player_name} rendered.`);
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function changePlayerName(pid) {
async function changePlayerName(pid) {
let newPlayerName = '';
const $playerName = $(`td:contains("${pid}")`).next();
swal({
title: trans('user.changePlayerName'),
text: $('#player_name').attr('placeholder'),
inputValue: $playerName.html(),
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(({ errno, msg }) => {
try {
newPlayerName = await swal({
title: trans('user.changePlayerName'),
text: $('#player_name').attr('placeholder'),
inputValue: $playerName.html(),
input: 'text',
showCancelButton: true,
inputValidator: value => (new Promise((resolve, reject) => {
value ? resolve() : reject(trans('skinlib.emptyPlayerName'));
}))
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/player/rename'),
dataType: 'json',
data: { pid: pid, new_player_name: newPlayerName }
});
if (errno == 0) {
swal({ type: 'success', html: msg });
$playerName.html(newPlayerName);
} else {
swal({ type: 'error', html: msg });
swal({ type: 'warning', html: msg });
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function clearTexture(pid) {
@ -99,7 +115,7 @@ function clearTexture(pid) {
});
}
function ajaxClearTexture(pid) {
async function ajaxClearTexture(pid) {
$('.modal').each(function () {
if ($(this).css('display') == 'none') $(this).remove();
});
@ -114,49 +130,65 @@ function ajaxClearTexture(pid) {
return toastr.warning(trans('user.noClearChoice'));
}
fetch({
type: 'POST',
url: url('user/player/texture/clear'),
dataType: 'json',
data: data
}).then(({ errno, msg }) => {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/player/texture/clear'),
dataType: 'json',
data: data
});
swal({ type: errno == 0 ? 'success' : 'error', html: msg });
$('.modal').modal('hide');
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
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(({ errno, msg }) => {
async function deletePlayer(pid) {
try {
await swal({
title: trans('user.deletePlayer'),
text: trans('user.deletePlayerNotice'),
type: 'warning',
showCancelButton: true,
cancelButtonColor: '#3085d6',
confirmButtonColor: '#d33'
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/player/delete'),
dataType: 'json',
data: { pid: pid }
});
if (errno == 0) {
swal({
await swal({
type: 'success',
html: msg
}).then(() => $(`tr#${pid}`).remove());
});
$(`tr#${pid}`).remove();
} else {
swal({ type: 'error', html: msg });
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function addNewPlayer() {
fetch({
type: 'POST',
url: url('user/player/add'),
dataType: 'json',
data: { player_name: $('#player_name').val() }
}).then(({ errno, msg }) => {
async function addNewPlayer() {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/player/add'),
dataType: 'json',
data: { player_name: $('#player_name').val() }
});
if (errno == 0) {
swal({
type: 'success',
@ -167,10 +199,12 @@ function addNewPlayer() {
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function setTexture() {
async function setTexture() {
let pid = 0,
skin = selectedTextures['skin'],
cape = selectedTextures['cape'];
@ -184,23 +218,27 @@ function setTexture() {
} 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(({ errno, msg }) => {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/player/set'),
dataType: 'json',
data: {
'pid': pid,
'tid[skin]': skin,
'tid[cape]': cape
}
});
if (errno == 0) {
swal({ type: 'success', html: msg });
$('#modal-use-as').modal('hide');
} else {
toastr.warning(msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
}

View File

@ -1,22 +1,30 @@
'use strict';
function changeNickName() {
async 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(({ errno, msg }) => {
try {
await swal({
text: trans('user.changeNickName', { new_nickname: name }),
type: 'question',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/profile?action=nickname'),
dataType: 'json',
data: { new_nickname: name }
});
if (errno == 0) {
$('.nickname').each(function () {
@ -27,10 +35,12 @@ function changeNickName() {
} else {
return swal({ type: 'warning', html: msg });
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function changePassword() {
async function changePassword() {
let $oldPasswd = $('#password'),
$newPasswd = $('#new-passwd'),
$confirmPwd = $('#confirm-pwd');
@ -51,25 +61,33 @@ function changePassword() {
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(({ errno, msg }) => {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/profile?action=password'),
dataType: 'json',
data: { 'current_password': password, 'new_password': newPasswd }
});
if (errno == 0) {
return swal({
type: 'success',
text: msg
}).then(() => logout()).catch(err => {
docCookies.removeItem('token') && console.warn(err);
}).then(() => {
try {
await swal({
type: 'success',
text: msg
});
await logout();
} catch (error) {
docCookies.removeItem('token') && console.warn(error);
} finally {
window.location = url('auth/login');
});
}
return;
} else {
return swal({ type: 'warning', text: msg });
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
}
@ -83,8 +101,8 @@ $('#new-email').focusin(() => {
}
}, 10));
function changeEmail() {
var newEmail = $('#new-email').val();
async function changeEmail() {
const newEmail = $('#new-email').val();
if (! newEmail) {
return swal({ type: 'error', html: trans('user.emptyNewEmail') });
@ -95,55 +113,72 @@ function changeEmail() {
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(({ errno, msg }) => {
try {
await swal({
text: trans('user.changeEmail', { new_email: newEmail }),
type: 'question',
showCancelButton: true
});
} catch (error) {
return;
}
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/profile?action=email'),
dataType: 'json',
data: { new_email: newEmail, password: $('#current-password').val() }
});
if (errno == 0) {
return swal({
await swal({
type: 'success',
text: msg
}).then(() => logout()).catch(err => {
docCookies.removeItem('token') && console.warn(err);
}).then(() => {
window.location = url('auth/login');
});
try {
await logout();
} catch (error) {
docCookies.removeItem('token') && console.warn(error);
} finally {
window.location = url('auth/login');
}
} else {
return swal({ type: 'warning', text: msg });
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
function deleteAccount() {
async 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(({ errno, msg }) => {
try {
const { errno, msg } = await fetch({
type: 'POST',
url: url('user/profile?action=delete'),
dataType: 'json',
data: { password: password }
});
if (errno == 0) {
return swal({
await swal({
type: 'success',
html: msg
}).then(() => {
window.location = url('auth/login');
});
window.location = url('auth/login');
} else {
return swal({ type: 'warning', html: msg });
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -1,9 +1,11 @@
function sign() {
fetch({
type: 'POST',
url: url('user/sign'),
dataType: 'json'
}).then(result => {
async function sign() {
try {
const result = await fetch({
type: 'POST',
url: url('user/sign'),
dataType: 'json'
});
if (result.errno == 0) {
$('#score').html(result.score);
const dom = '<i class="fa fa-calendar-check-o"></i> &nbsp;' + trans(
@ -29,7 +31,9 @@ function sign() {
} else {
toastr.warning(result.msg);
}
}).catch(showAjaxError);
} catch (error) {
showAjaxError(error);
}
}
if (typeof require !== 'undefined' && typeof module !== 'undefined') {

View File

@ -2978,6 +2978,10 @@ meow@^3.7.0:
redent "^1.0.0"
trim-newlines "^1.0.0"
merge2@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.0.tgz#0f882151d988b1f3d0758945404fa73ee5923d3f"
merge@^1.1.3:
version "1.2.0"
resolved "http://registry.npm.taobao.org/merge/download/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"