Remove unused files

This commit is contained in:
Pig Fang 2018-08-16 16:36:19 +08:00
parent deda5cf11c
commit 71cd20052b
7 changed files with 0 additions and 1647 deletions

View File

@ -1,659 +0,0 @@
/* eslint no-unused-vars: "off" */
const $ = require('jquery');
window.$ = window.jQuery = $;
window.getQueryString = jest.fn((key, defaultValue) => defaultValue);
describe('tests for "index" module', () => {
const modulePath = '../skinlib/index';
it('initialize skin library', () => {
const fetch = jest.fn().mockReturnValue(Promise.resolve({ items: [] }));
const url = jest.fn(path => path);
const trans = jest.fn(key => key);
const showAjaxError = jest.fn();
window.fetch = fetch;
window.url = url;
window.trans = trans;
window.showAjaxError = showAjaxError;
$.fn.jqPaginator = jest.fn();
const { initSkinlib } = require(modulePath);
initSkinlib();
expect(fetch).not.toBeCalled();
document.body.innerHTML = `
<div id="skinlib-container"></div>
<div id="skinlib-paginator"></div>
<div class="sort"></div>
`;
initSkinlib();
expect(fetch).toBeCalled();
});
it('render skin library', () => {
const trans = jest.fn(key => key);
const url = jest.fn(path => path);
const jqPaginator = jest.fn();
window.trans = trans;
window.url = url;
$.fn.jqPaginator = jqPaginator;
document.body.innerHTML = `
<div class="overlay"></div>
<div id="skinlib-container"></div>
<div id="skinlib-paginator"></div>
`;
const renderSkinlib = require(modulePath).renderSkinlib;
renderSkinlib([]);
expect($('#skinlib-container').html()).toBe(
'<p style="text-align: center; margin: 30px 0;">general.noResult</p>'
);
expect($('#skinlib-paginator').css('display')).toBe('none');
expect($('.overlay').css('display')).toBe('none');
renderSkinlib([{
tid: 1,
name: 'name',
type: 'steve',
public: false
}]);
expect($('#skinlib-paginator').css('display')).not.toBe('none');
expect($('.item').attr('tid')).toBe('1');
expect($('.item-body > img').attr('src')).toBe('preview/1.png');
expect($('.texture-name > span').attr('title')).toBe('name');
expect($('.texture-name > span > small').text()).toBe('skinlib.filter.steve');
expect($('a.more.like').attr('title')).toBe('skinlib.anonymous');
expect($('a.more.like').hasClass('liked')).toBe(false);
expect($('a.more.like').hasClass('anonymous')).toBe(true);
expect($('small.more').hasClass('hide')).toBe(false);
expect($('small.private-label').text().trim()).toBe('skinlib.private');
renderSkinlib([{
tid: 1,
name: 'name',
type: 'steve',
public: false,
liked: true
}]);
expect($('a.more.like').attr('title')).toBe('skinlib.removeFromCloset');
expect($('a.more.like').hasClass('liked')).toBe(true);
expect($('a.more.like').hasClass('anonymous')).toBe(false);
expect($('small.more').hasClass('hide')).toBe(false);
expect($('small.private-label').text().trim()).toBe('skinlib.private');
renderSkinlib([{
tid: 1,
name: 'name',
type: 'steve',
public: false,
liked: false
}]);
expect($('a.more.like').attr('title')).toBe('skinlib.addToCloset');
expect($('a.more.like').hasClass('liked')).toBe(false);
expect($('a.more.like').hasClass('anonymous')).toBe(false);
expect($('small.more').hasClass('hide')).toBe(false);
expect($('small.private-label').text().trim()).toBe('skinlib.private');
renderSkinlib([{
tid: 1,
name: 'name',
type: 'steve',
public: true,
liked: false
}]);
expect($('small.more').hasClass('hide')).toBe(true);
});
it('update paginator', () => {
const trans = jest.fn(key => key);
const jqPaginator = jest.fn();
window.trans = trans;
$.fn.jqPaginator = jqPaginator;
document.body.innerHTML = `
<p class="pagination"></p>
<div id="skinlib-paginator"></div>
<select class="pagination"></select>
`;
const updatePaginator = require(modulePath).updatePaginator;
updatePaginator(2, 2);
expect(trans).toBeCalledWith('general.pagination', { page: 2, total: 2 });
expect(jqPaginator).toBeCalledWith(expect.objectContaining({
currentPage: 2,
totalPages: 2
}));
expect($('option').length).toBe(2);
expect($('option[value=1]').prop('selected')).toBe(false);
expect($('option[value=2]').prop('selected')).toBe(true);
$('#skinlib-paginator').html('something');
updatePaginator(2, 2);
expect(jqPaginator).toBeCalledWith('option', {
currentPage: 2,
totalPages: 2
});
});
it('update breadcrumb', () => {
const trans = jest.fn(key => key);
const jqPaginator = jest.fn();
window.trans = trans;
$.fn.jqPaginator = jqPaginator;
document.body.innerHTML = `
<div id="filter-indicator"></div>
<div id="uploader-indicator"></div>
<div id="sort-indicator"></div>
<div id="search-indicator"></div>
<input id="navbar-search-input" />
`;
const updateBreadCrumb = require(modulePath).updateBreadCrumb;
updateBreadCrumb();
expect($('#filter-indicator').html().replace(/\s/g, '')).toBe(
'general.skin<small>skinlib.filter.skin</small>'
);
$.skinlib.filter = 'cape';
updateBreadCrumb();
expect($('#filter-indicator').html()).toBe('general.cape');
expect($('#uploader-indicator').html()).toBe('skinlib.filter.allUsers');
$.skinlib.uploader = 1;
updateBreadCrumb();
expect(trans).toBeCalledWith('skinlib.filter.uploader', { uid: 1 });
expect($('#uploader-indicator').html()).toBe('skinlib.filter.uploader');
expect($('#sort-indicator').html()).toBe('skinlib.sort.time');
$.skinlib.keyword = '%20q';
updateBreadCrumb();
expect(trans).lastCalledWith(
'general.searchResult',
{ keyword: ' q' }
);
expect($('#search-indicator').html()).toBe('general.searchResult');
expect($('#navbar-search-input').val()).toBe(' q');
});
it('reload skin library', async () => {
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 = showAjaxError;
document.body.innerHTML = `
<div id="skinlib-paginator"></div>
`;
const reloadSkinlib = require(modulePath).reloadSkinlib;
window.history.pushState = jest.fn();
await reloadSkinlib();
expect(fetch).toBeCalledWith(expect.objectContaining({
type: 'GET',
url: 'skinlib/data',
dataType: 'json',
data: {
page: 2,
filter: 'cape',
sort: 'time',
uploader: 1,
keyword: '%20q'
}
}));
await reloadSkinlib();
expect(showAjaxError).toBeCalled();
});
it('update query string', () => {
const url = jest.fn(path => path);
window.url = url;
document.body.innerHTML = `
<ul>
<li class="locale" data-code="zh_CN"><a></a></li>
<li class="locale" data-code="en"><a></a></li>
</ul>
`;
const updateUrlQueryString = require(modulePath).updateUrlQueryString;
window.history.pushState = jest.fn();
const query = 'page=2&filter=cape&sort=time&uploader=1&keyword=%2520q';
updateUrlQueryString();
expect(window.history.pushState).toBeCalledWith(
null,
null,
'skinlib?' + query);
expect($('li[data-code=zh_CN] > a').prop('href')).toBe(`?lang=zh_CN&${query}`);
expect($('li[data-code=en] > a').prop('href')).toBe(`?lang=en&${query}`);
});
it('change page', () => {
document.body.innerHTML = `
<div class="overlay" style="display: none"></div>
<select class="pagination">
<option value="2"></option>
</select>
`;
const { onPageChange } = require(modulePath);
onPageChange(1, 'init');
expect($.skinlib.page).toBe(1);
//onPageChange(2);
$('select').trigger('change');
expect($('div').css('display')).not.toBe('none');
expect($.skinlib.page).toBe(2);
});
it('update filter', () => {
document.body.innerHTML = `
<div data-filter="skin"></div>
`;
const { updateFilter } = require(modulePath);
updateFilter.call($('div'), new Event('click'));
expect($.skinlib.filter).toBe('skin');
$('div').data('filter', 'uploader').data('uid', 4);
updateFilter.call($('div'), new Event('click'));
expect($.skinlib.uploader).toBe(4);
});
it('change sort type', () => {
const fetch = jest.fn().mockReturnValue(Promise.resolve());
window.fetch = fetch;
document.body.innerHTML = `
<a class="sort" data-sort="likes"></a>
`;
require(modulePath);
$('a').click();
expect(fetch).toBeCalled();
expect($.skinlib.sort).toBe('likes');
});
it('search texture', async () => {
const fetch = jest.fn().mockReturnValue(Promise.resolve());
window.fetch = fetch;
document.body.innerHTML = `
<form id="search-form">
<input id="navbar-search-input" name="q" value="keyword">
</form>
`;
$('#search-form').trigger('submit');
expect(fetch).toBeCalled();
expect($.skinlib.keyword).toBe('keyword');
});
});
describe('tests for "operations" module', () => {
const modulePath = '../skinlib/operations';
it('toggle liked', async () => {
const fetch = jest.fn().mockReturnValue(Promise.resolve());
const swal = jest.fn().mockReturnValue(Promise.resolve());
const url = jest.fn(path => path);
window.fetch = fetch;
window.swal = swal;
window.url = url;
document.body.innerHTML = `
<a tid="5" class="anonymous"></a>
`;
const { toggleLiked } = require(modulePath);
await toggleLiked.call($('a'));
expect(fetch).not.toBeCalled();
$('a').removeClass('anonymous');
const originGetJson = $.getJSON;
$.getJSON = jest.fn();
await toggleLiked.call($('a'));
expect($.getJSON).toBeCalled();
$.getJSON = originGetJson;
$('a').addClass('liked');
await toggleLiked.call($('a'));
expect(fetch).toBeCalled();
});
it('add to closet', async () => {
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('custom');
return Promise.resolve('custom');
});
window.swal = swal;
$.getJSON = jest.fn((option, cb) => {
cb({ name: 'name' });
});
const addToCloset = require(modulePath).addToCloset;
await addToCloset(1);
expect($.getJSON.mock.calls[0][0]).toBe('skinlib/info/1');
expect(swal).toBeCalledWith(expect.objectContaining({
title: 'skinlib.setItemName',
inputValue: 'name',
input: 'text',
showCancelButton: true,
}));
});
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.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());
window.swal = swal;
const modal = jest.fn();
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
window.toastr = toastr;
const showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
$.fn.modal = modal;
document.body.innerHTML = `
<div class="modal" style="display: none" id="shouldBeRemoved"></div>
<div class="modal" id="shouldNotBeRemoved"></div>
`;
const ajaxAddToCloset = require(modulePath).ajaxAddToCloset;
await ajaxAddToCloset(1, 'name');
expect(document.getElementById('shouldBeRemoved')).toBeNull();
expect(document.getElementById('shouldNotBeRemoved')).not.toBeNull();
expect(fetch).toBeCalledWith({
type: 'POST',
url: 'user/closet/add',
dataType: 'json',
data: { tid: 1, name: 'name' }
});
expect(swal).toBeCalledWith({ type: 'success', html: 'success' });
expect(modal).toBeCalledWith('hide');
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()
.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()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
window.swal = swal;
const modal = jest.fn();
const toastr = {
success: jest.fn(),
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',
type: 'warning',
showCancelButton: true,
cancelButtonColor: '#3085d6',
confirmButtonColor: '#d33'
});
expect(fetch).toBeCalledWith({
type: 'POST',
url: '/user/closet/remove',
dataType: 'json',
data: { tid: 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()
.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()
.mockImplementationOnce(() => Promise.reject())
.mockImplementationOnce(option => {
option.inputValidator('new-name');
return Promise.resolve('new-name');
});
window.swal = swal;
const modal = jest.fn();
const toastr = {
success: jest.fn(),
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',
input: 'text',
inputValue: 'oldName',
showCancelButton: true,
}));
expect(fetch).toBeCalledWith({
type: 'POST',
url: 'skinlib/rename',
dataType: 'json',
data: { tid: 1, new_name: 'new-name' }
});
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', () => {
window.trans = jest.fn(key => key);
document.body.innerHTML = `
<div id="likes">5</div>
<a tid="1"></a>
<a id="1"></a>
`;
const updateTextureStatus = require(modulePath).updateTextureStatus;
updateTextureStatus(1, 'add');
expect($('a[tid=1]').attr('onclick')).toBe('removeFromCloset(1);');
expect($('a[tid=1]').attr('title')).toBe('skinlib.removeFromCloset');
expect($('a[tid=1]').hasClass('liked')).toBe(true);
expect($('#1').attr('onclick')).toBe('removeFromCloset(1);');
expect($('#1').html()).toBe('skinlib.removeFromCloset');
expect($('div').html()).toBe('6');
updateTextureStatus(1, 'remove');
expect($('a[tid=1]').attr('onclick')).toBe('addToCloset(1);');
expect($('a[tid=1]').attr('title')).toBe('skinlib.addToCloset');
expect($('a[tid=1]').hasClass('liked')).toBe(false);
expect($('#1').attr('onclick')).toBe('addToCloset(1);');
expect($('#1').html()).toBe('skinlib.addToCloset');
expect($('div').html()).toBe('5');
});
it('click changing privacy button', async () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'success' }));
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());
window.swal = swal;
const modal = jest.fn();
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
window.toastr = toastr;
document.body.innerHTML = '<a class="private-label"></a>';
require(modulePath);
await $('a').click();
expect(swal).toBeCalledWith({
text: 'skinlib.setPublicNotice',
type: 'warning',
showCancelButton: true
});
expect(document.getElementsByTagName('a').length).toBe(0);
});
it('change privacy', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success', public: false }))
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success', public: true }))
.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());
window.swal = swal;
const modal = jest.fn();
const toastr = {
success: jest.fn(),
warning: jest.fn()
};
window.toastr = toastr;
const showAjaxError = jest.fn();
window.showAjaxError = showAjaxError;
document.body.innerHTML = `
<a id="1">skinlib.setAsPrivate</a>
<a id="2">skinlib.setAsPublic</a>
`;
const changePrivacy = require(modulePath).changePrivacy;
await changePrivacy(1);
expect(fetch).toBeCalledWith({
type: 'POST',
url: 'skinlib/privacy',
dataType: 'json',
data: { tid: 1 }
});
expect(toastr.warning).not.toBeCalled();
expect(toastr.success).toBeCalledWith('success');
expect($('#1').html()).toBe('skinlib.setAsPublic');
await changePrivacy(1);
expect($('#2').html()).toBe('skinlib.setAsPrivate');
await changePrivacy(1);
expect(toastr.warning).toBeCalledWith('warning');
await changePrivacy(1);
expect(showAjaxError).toBeCalled();
});
it('delete texture', async () => {
const fetch = jest.fn()
.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()
.mockReturnValueOnce(Promise.reject())
.mockReturnValueOnce(Promise.resolve());
window.swal = swal;
const modal = jest.fn();
const toastr = {
success: jest.fn(),
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',
type: 'warning',
showCancelButton: true
});
expect(fetch).toBeCalledWith({
type: 'POST',
url: 'skinlib/delete',
dataType: 'json',
data: { tid: 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

@ -1,240 +0,0 @@
'use strict';
$.skinlib = {
page: getQueryString('page', 1),
filter: getQueryString('filter', 'skin'),
sort: getQueryString('sort', 'time'),
uploader: getQueryString('uploader', 0),
keyword: decodeURI(getQueryString('keyword', ''))
};
$(document).ready(initSkinlib);
$('body').on('change', 'select.pagination', function () {
onPageChange(parseInt($(this).val()));
});
$('.filter').click(updateFilter);
$('body').on('click', '.sort', function (e) {
e.preventDefault();
$.skinlib.sort = $(this).data('sort');
console.log('Sort by ' + $.skinlib.sort);
reloadSkinlib();
});
$('body').on('submit', '#search-form', function (e) {
e.preventDefault();
$.skinlib.keyword = $('#navbar-search-input').val();
console.log('Search keyword: ' + $.skinlib.keyword);
reloadSkinlib();
});
function initSkinlib() {
if ($('#skinlib-container').length !== 0) {
// Initially render skinlib
requestSkinlibData().then(result => {
renderSkinlib(result.items);
updatePaginator(
$.skinlib.page,
result.total_pages || 1
);
});
}
}
function renderSkinlib(items) {
const container = $('#skinlib-container').html('');
if (items.length === 0) {
$('#skinlib-paginator').hide();
container.html(
'<p style="text-align: center; margin: 30px 0;">' +
trans('general.noResult') +
'</p>'
);
} else {
$('#skinlib-paginator').show();
container.html(items.reduce((carry, item) => carry + renderSkinlibItemComponent(item), ''));
}
$('.overlay').hide();
}
async function reloadSkinlib() {
try {
const result = await requestSkinlibData();
$('.overlay').show();
renderSkinlib(result.items);
updatePaginator($.skinlib.page, result.total_pages || 1);
updateUrlQueryString();
updateBreadCrumb();
} catch (error) {
showAjaxError(error);
}
}
function requestSkinlibData() {
return fetch({
type: 'GET',
url: url('skinlib/data'),
dataType: 'json',
data: $.skinlib,
error: showAjaxError
});
}
function renderSkinlibItemComponent(item) {
let title = '';
let anonymous = '';
const liked = item.liked ? 'liked' : '';
if (item.liked === undefined) {
// If user haven't logged in
title = trans('skinlib.anonymous');
anonymous = 'anonymous';
} else {
title = item.liked ? trans('skinlib.removeFromCloset') : trans('skinlib.addToCloset');
}
return `<a href="${ url('skinlib/show/' + item.tid) }">
<div class="item" tid="${ item.tid }">
<div class="item-body">
<img src="${ url('preview/' + item.tid + '.png') }">
</div>
<div class="item-footer">
<p class="texture-name">
<span title="${ item.name }">${ item.name }
<small>${ trans('skinlib.filter.' + item.type) }</small>
</span>
</p>
<a title="${title}" class="more like ${liked} ${anonymous}" tid="${ item.tid }" href="javascript:;" data-placement="top" data-toggle="tooltip"><i class="fa fa-heart"></i></a>
<small class="more private-label ${(!item.public) ? '' : 'hide'}" tid="${ item.tid }">
${ trans('skinlib.private') }
</small>
</div>
</div>
</a>`;
}
function updatePaginator(currentPage, totalPages) {
$.skinlib.page = currentPage;
$('p.pagination').text(trans('general.pagination', {
page: currentPage,
total: totalPages
}));
const paginator = $('#skinlib-paginator');
if (paginator.html().length === 0) {
// init paginator
$('#skinlib-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
currentPage: parseInt(currentPage),
totalPages: parseInt(totalPages),
onPageChange: onPageChange
}));
} else {
$('#skinlib-paginator').jqPaginator('option', {
currentPage: parseInt(currentPage),
totalPages: parseInt(totalPages)
});
}
const pageSelectElement = $('select.pagination').html('');
for (let i = 1; i <= totalPages; i++) {
pageSelectElement.append(`
<option value="${i}" ${ (i === currentPage) ? 'selected' : '' }>${i}</option>
`);
}
}
function updateFilter(e) {
e.preventDefault();
const selectedFilter = $(this).data('filter');
if (selectedFilter === 'uploader') {
$.skinlib.uploader = $(this).data('uid');
console.log('Show items uploaded by uid ' + $.skinlib.uploader);
} else {
$.skinlib.filter = selectedFilter;
console.log('Filter by ' + $.skinlib.filter);
}
reloadSkinlib();
}
function onPageChange(page, type) {
$.skinlib.page = page;
updateBreadCrumb();
if (type === 'init') {
console.log('Init paginator', page);
} else {
$('.overlay').show();
reloadSkinlib();
console.log('Rendering page', page);
}
}
function updateUrlQueryString() {
const query = $.param($.skinlib);
window.history.pushState(null, null, url(`skinlib?${ query }`));
$('li.locale').each(function () {
$(this).find('a').prop('href', `?lang=${ $(this).data('code') }&${ query }`);
});
}
function updateBreadCrumb() {
if ($.skinlib.filter === 'cape') {
$('#filter-indicator').html(trans('general.cape'));
} else {
$('#filter-indicator').html(trans('general.skin') + `<small>
${ trans('skinlib.filter.' + $.skinlib.filter) }
</small>`);
}
if ($.skinlib.uploader !== 0) {
$('#uploader-indicator').html(trans('skinlib.filter.uploader', { uid: $.skinlib.uploader }));
} else {
$('#uploader-indicator').html(trans('skinlib.filter.allUsers'));
}
$('#sort-indicator').html(trans('skinlib.sort.' + $.skinlib.sort));
if ($.skinlib.keyword !== '') {
$('#search-indicator').text(trans('general.searchResult', {
keyword: decodeURI($.skinlib.keyword)
}));
$('#navbar-search-input').val(decodeURI($.skinlib.keyword));
}
}
if (process.env.NODE_ENV === 'test') {
module.exports = {
initSkinlib,
renderSkinlib,
reloadSkinlib,
updatePaginator,
updateBreadCrumb,
updateUrlQueryString,
onPageChange,
updateFilter,
};
}

View File

@ -1,236 +0,0 @@
'use strict';
$(document).on('click', '.more.like', toggleLiked);
function toggleLiked() {
const tid = $(this).attr('tid');
if ($(this).hasClass('anonymous'))
return;
if ($(this).hasClass('liked')) {
removeFromCloset(tid);
} else {
addToCloset(tid);
}
}
function addToCloset(tid) {
$.getJSON(url(`skinlib/info/${tid}`), 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) {
//
}
});
}
async function ajaxAddToCloset(tid, name) {
// Remove interference of modal which is hide
$('.modal').each(function () {
return ($(this).css('display') === 'none') ? $(this).remove() : null;
});
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 });
$('.modal').modal('hide');
updateTextureStatus(tid, 'add');
} else {
toastr.warning(msg);
}
} catch (error) {
showAjaxError(error);
}
}
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 });
updateTextureStatus(tid, 'remove');
} else {
toastr.warning(msg);
}
} catch (error) {
showAjaxError(error);
}
}
async function changeTextureName(tid, oldName) {
let newTextureName = '';
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 (error) {
showAjaxError(error);
}
}
/**
* Update button action & likes of texture.
*
* @param {number} tid
* @param {'add'|'remove'} action
* @return {null}
*/
function updateTextureStatus(tid, action) {
const likes = parseInt($('#likes').html()) + (action === 'add' ? 1 : -1);
action = (action === 'add') ? 'removeFromCloset' : 'addToCloset';
$(`a[tid=${tid}]`)
.attr('onclick', `${action}(${tid});`)
.attr('title', trans(`skinlib.${action}`))
.toggleClass('liked');
$(`#${tid}`)
.attr('onclick', `${action}(${tid});`)
.html(trans(`skinlib.${action}`));
$('#likes').html(likes);
}
$(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) {
//
}
});
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);
if (!result.public) {
$(`a:contains("${trans('skinlib.setAsPrivate')}")`).html(trans('skinlib.setAsPublic'));
} else {
$(`a:contains("${trans('skinlib.setAsPublic')}")`).html(trans('skinlib.setAsPrivate'));
}
} else {
toastr.warning(msg);
}
} catch (error) {
showAjaxError(error);
}
}
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) {
await swal({ type: 'success', html: msg });
window.location = url('skinlib');
} else {
swal({ type: 'warning', html: msg });
}
} catch (error) {
showAjaxError(error);
}
}
if (process.env.NODE_ENV === 'test') {
module.exports = {
toggleLiked,
addToCloset,
changePrivacy,
deleteTexture,
ajaxAddToCloset,
removeFromCloset,
changeTextureName,
updateTextureStatus,
};
}

View File

@ -1,179 +0,0 @@
/* global initSkinViewer, defaultSteveSkin, defaultAlexSkin */
// TODO: Help wanted. This file needs to be tested.
'use strict';
function initUploadListeners() {
if (trans('vendor.fileinput') !== 'vendor.fileinput') {
$.fn.fileinputLocales[blessing.locale] = trans('vendor.fileinput');
}
$('body')
.on('change', '#file', () => handleFiles())
.on('ifToggled', '#type-cape', () => handleFiles())
.on('change', '#skin-type', function () {
if ($('#file').prop('files').length === 0) {
$.msp.config.slim = ($(this).val() === 'alex');
$.msp.config.skinUrl = getDefaultSkin();
initSkinViewer();
}
handleFiles();
})
.on('ifToggled', '#type-skin', function () {
$(this).prop('checked') ? $('#skin-type').show() : $('#skin-type').hide();
})
.on('ifToggled', '#private', function () {
$(this).prop('checked') ? $('#msg').show() : $('#msg').hide();
});
$(document).ready(() => {
$.msp.config.skinUrl = defaultSteveSkin;
initSkinViewer();
$('[for="private"]').tooltip();
});
}
// Real-time preview
function handleFiles(files, type) {
files = files || $('#file').prop('files');
type = type || $('#type-cape').prop('checked') ? 'cape' : 'skin';
if (files.length > 0) {
const file = files[0];
if (file.type === 'image/png' || file.type === 'image/x-png') {
const reader = new FileReader();
reader.onload = function () {
const img = new Image();
img.onload = () => {
const $name = $('#name');
if (type === 'cape') {
$.msp.config.skinUrl = getDefaultSkin();
if (img.width / img.height === 2) {
$.msp.config.capeUrl = img.src;
} else {
$.msp.config.capeUrl = null;
toastr.warning(trans('skinlib.badCapeSize'));
}
} else {
// Check skin size
if (img.width === img.height || img.width / img.height === 2) {
$.msp.config.skinUrl = img.src;
$.msp.config.capeUrl = null;
} else {
$.msp.config.skinUrl = getDefaultSkin();
toastr.warning(trans('skinlib.badSkinSize'));
}
}
$.msp.config.slim = ($('#skin-type').val() === 'alex');
initSkinViewer();
if ($name.val() === '' || $name.val() === $name.attr('data-last-file-name')) {
// Remove png extension in filename
const fileName = file.name.replace(/\.[Pp][Nn][Gg]$/, '');
$name.attr('data-last-file-name', fileName);
$name.val(fileName);
}
};
img.onerror = () => toastr.warning(trans('skinlib.fileExtError'));
img.src = this.result;
};
reader.readAsDataURL(file);
} else {
toastr.warning(trans('skinlib.encodingError'));
}
}
}
function getDefaultSkin() {
return $('#skin-type').val() === 'alex' ? defaultAlexSkin : defaultSteveSkin;
}
function upload() {
const form = new FormData();
const file = $('#file').prop('files')[0];
form.append('name', $('#name').val());
form.append('file', file);
form.append('public', ! $('#private').prop('checked'));
if ($('#type-skin').prop('checked')) {
form.append('type', $('#skin-type').val());
} else if ($('#type-cape').prop('checked')) {
form.append('type', 'cape');
} else {
return toastr.info(trans('skinlib.emptyTextureType'));
}
(function validate(form, file, callback) {
if (file === undefined) {
toastr.info(trans('skinlib.emptyUploadFile'));
$('#file').focus();
} else if ($('#name').val() === '') {
toastr.info(trans('skinlib.emptyTextureName'));
$('#name').focus();
} else if (file.type !== 'image/png') {
toastr.warning(trans('skinlib.fileExtError'));
$('#file').focus();
} else {
callback();
}
})(form, file, 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) {
const redirect = function () {
toastr.info(trans('skinlib.redirecting'));
setTimeout(() => {
window.location = url(`skinlib/show/${tid}`);
}, 1000);
};
// Always redirect
swal({
type: 'success',
html: msg
}).then(redirect, redirect);
} else {
await swal({
type: 'warning',
html: msg
});
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
}
} catch (error) {
showAjaxError(error);
$('#upload-button').html(trans('skinlib.upload')).prop('disabled', '');
}
});
}
if (process.env.NODE_ENV === 'test') {
module.exports = { upload, initUploadListeners };
}

View File

@ -1,217 +0,0 @@
font_stack = Ubuntu, 'Segoe UI', 'Microsoft Yahei', 'Microsoft Jhenghei', sans-serif;
@font-face {
font-family: 'Ubuntu';
src: url('../fonts/ubuntu.woff2') format('woff2');
}
@font-face {
font-family: 'Minecraft';
src: url('../fonts/minecraft.eot');
src: url('../fonts/minecraft.eot') format('embedded-opentype'),
url('../fonts/minecraft.woff2') format('woff2'),
url('../fonts/minecraft.woff') format('woff'),
url('../fonts/minecraft.ttf') format('truetype'),
url('../fonts/minecraft.svg#minecraft') format('svg');
}
body, h1, h2, h3, h4, h5, h6, .logo {
font-family: font_stack !important;
}
.swal2-modal, .swal2-content {
font-family: font_stack;
font-weight: 400 !important;
}
.swal2-modal h2 {
font-size: 25px;
}
/* fucking webkit autofill */
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px #fff inset !important;
}
.login-page {
height: auto;
}
.item {
display: block;
background: #EFF1F0;
box-shadow: 0 1px 1px rgba(0,0,0,0.1);
border-radius: 2px;
float: left;
position: relative;
margin-right: 20px;
margin-bottom: 20px;
cursor: pointer;
width: 210px;
height: 196px;
-webkit-transition: box-shadow 0.1s ease-in-out 0s;
-moz-transition: box-shadow 0.1s ease-in-out 0s;
-o-transition: box-shadow 0.1s ease-in-out 0s;
-ms-transition: box-shadow 0.1s ease-in-out 0s;
transition: box-shadow 0.1s ease-in-out 0s;
}
.item-body {
height: 166px;
img {
max-width: 100%;
margin-left: 30px;
margin-top: 16px;
width: 150px;
}
}
@media (max-width: 756px) {
.item {
width: 45%;
margin-right: 5%;
}
.item-body > img {
margin-left: 25%;
}
.texture-name {
width: 65%;
}
}
@media (max-width: 520px) {
.item {
width: 100%;
}
.item-body > img {
margin-left: 30%;
}
.texture-name {
width: 80%;
}
}
@media (min-width: 992px) {
#preview-3d-container {
min-height: 500px;
}
}
#preview-3d-container canvas {
cursor: move;
}
.texture-name {
width: 65%;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.item:hover {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
}
.item-selected {
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
}
.item-footer {
background: #50b3ec;
color: #fff;
font-size: 16px;
height: 30px;
padding: 3px 8px;
.more {
float: right;
margin-left: 6px;
margin-right: 3px;
color: #fff;
}
.more:hover {
color: #dadada;
}
small {
font-size: 50%;
}
}
.operations {
display: inline; float: right;
i {
padding: .5em .5em;
display: inline !important;
}
i:hover {
color: #555;
cursor: pointer;
}
}
.skin2d {
float: right;
max-height: 64px;
width: 64px;
font-size: 16px;
}
#preview-2d-container > p {
height: 64px;
line-height: 64px;
}
#toast-container > div {
opacity: 1;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: "alpha(opacity=100)";
}
.captcha {
cursor: pointer;
}
.box-footer > p {
margin: 6px 15px 5px 0;
}
@media (max-width: 767px) {
.wrapper .main-header .navbar .dropdown-menu li.locale {
a {
color: #777;
}
a:hover {
background-color: #e1e3e9;
color: #333;
}
}
/* hide the text on mobile phone pages */
.description-text {
display: none;
}
}
.key {
vertical-align: middle !important;
}
.value {
width: 70%;
}
td[class='key'], td[class='value'] {
border-top: 0 !important;
}

View File

@ -1,98 +0,0 @@
@import "general.styl";
.navbar-nav {
.user-menu .user-image {
border-radius: 10%;
}
}
.main-header #navbar-search-input.form-control {
border-radius: 4px;
}
@media (min-width: 1200px) {
.item {
width: 250px;
}
.item-body > img {
margin-left: 50px;
}
.texture-name {
width: 65%;
}
}
.item-footer {
a {
color: #fff;
}
.like:hover,
.liked {
color: #e0353b;
}
}
.model-label {
font-weight: 500;
font-size: 15px;
}
label.pull-right {
font-weight: inherit;
}
div.likes {
background-color: #fff;
border-color: #fff;
color: #3e3e3e;
cursor: default;
}
div.likes:hover,
div.likes:active,
div.likes:focus,
div.likes:active:focus {
background-color: #fff;
border-color: #fff;
color: #e0353b;
}
table {
font-size: inherit;
}
.table > tbody > tr > td {
border-top: none;
}
select.pagination {
padding-left: 0;
margin: 0 20px 0 0;
border-radius: 4px;
padding: 5.5px 14px;
}
.overlay span {
position: absolute;
top: 50%;
left: 50%;
margin-left: -40px;
margin-top: 25px;
color: #000;
font-size: 20px;
}
#skinlib-container {
min-height: 20em;
}
.private-label {
margin-top: 2px;
}
.dropdown-menu .divider {
margin: 3px 0;
}

View File

@ -1,18 +0,0 @@
<div class="box box-danger">
{{-- Texture Manage Panel --}}
<div class="box-header with-border">
<h3 class="box-title">{{ $title }}</h3>
</div><!-- /.box-header -->
<div class="box-body">
<p>{{ $message }}</p>
</div><!-- /.box-body -->
<div class="box-footer">
@if ($texture->public == "1")
<a onclick="changePrivacy({{ $texture->tid }});" class="btn btn-warning">@lang('skinlib.privacy.set-as-private')</a>
@else
<a onclick="changePrivacy({{ $texture->tid }});" class="btn btn-warning">@lang('skinlib.privacy.set-as-public')</a>
@endif
<a onclick="deleteTexture({{ $texture->tid }});" class="btn btn-danger pull-right">@lang('skinlib.show.delete-texture')</a>
</div><!-- /.box-footer -->
</div><!-- /.box -->