diff --git a/resources/assets/src/js/__tests__/skinlib.test.js b/resources/assets/src/js/__tests__/skinlib.test.js
deleted file mode 100644
index 5a55b776..00000000
--- a/resources/assets/src/js/__tests__/skinlib.test.js
+++ /dev/null
@@ -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 = `
-
-
-
- `;
- 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 = `
-
-
-
- `;
- const renderSkinlib = require(modulePath).renderSkinlib;
-
- renderSkinlib([]);
- expect($('#skinlib-container').html()).toBe(
- 'general.noResult
'
- );
- 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 = `
-
-
-
- `;
- 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 = `
-
-
-
-
-
- `;
- const updateBreadCrumb = require(modulePath).updateBreadCrumb;
-
- updateBreadCrumb();
- expect($('#filter-indicator').html().replace(/\s/g, '')).toBe(
- 'general.skinskinlib.filter.skin'
- );
-
- $.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 = `
-
- `;
- 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 = `
-
- `;
- 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 = `
-
-
- `;
- 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 = `
-
- `;
- 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 = `
-
- `;
-
- 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 = `
-
- `;
-
- $('#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 = `
-
- `;
- 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 = `
-
-
- `;
- 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 = '';
- 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 = `
- 5
-
-
- `;
- 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 = '';
- 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 = `
- skinlib.setAsPrivate
- skinlib.setAsPublic
- `;
- 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();
- });
-});
diff --git a/resources/assets/src/js/skinlib/index.js b/resources/assets/src/js/skinlib/index.js
deleted file mode 100644
index ec718c94..00000000
--- a/resources/assets/src/js/skinlib/index.js
+++ /dev/null
@@ -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(
- '' +
- trans('general.noResult') +
- '
'
- );
- } 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 `
-
-
-
 })
-
-
-
-
- `;
-}
-
-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(`
-
- `);
- }
-}
-
-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') + `
- ${ trans('skinlib.filter.' + $.skinlib.filter) }
- `);
- }
-
- 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,
- };
-}
diff --git a/resources/assets/src/js/skinlib/operations.js b/resources/assets/src/js/skinlib/operations.js
deleted file mode 100644
index e4723fe2..00000000
--- a/resources/assets/src/js/skinlib/operations.js
+++ /dev/null
@@ -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,
- };
-}
diff --git a/resources/assets/src/js/skinlib/upload.js b/resources/assets/src/js/skinlib/upload.js
deleted file mode 100644
index a5104bba..00000000
--- a/resources/assets/src/js/skinlib/upload.js
+++ /dev/null
@@ -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(
- ' ' + 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 };
-}
diff --git a/resources/assets/src/stylus/general.styl b/resources/assets/src/stylus/general.styl
deleted file mode 100644
index 1ddfbfd5..00000000
--- a/resources/assets/src/stylus/general.styl
+++ /dev/null
@@ -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;
-}
diff --git a/resources/assets/src/stylus/skinlib.styl b/resources/assets/src/stylus/skinlib.styl
deleted file mode 100644
index 1dc217bd..00000000
--- a/resources/assets/src/stylus/skinlib.styl
+++ /dev/null
@@ -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;
-}
diff --git a/resources/views/common/manage-panel.tpl b/resources/views/common/manage-panel.tpl
deleted file mode 100644
index b1360aa4..00000000
--- a/resources/views/common/manage-panel.tpl
+++ /dev/null
@@ -1,18 +0,0 @@
-
- {{-- Texture Manage Panel --}}
-
-
-
-
-