diff --git a/app/Http/Controllers/ClosetController.php b/app/Http/Controllers/ClosetController.php index 5f07b80b..7e35742c 100644 --- a/app/Http/Controllers/ClosetController.php +++ b/app/Http/Controllers/ClosetController.php @@ -25,43 +25,40 @@ class ClosetController extends Controller $this->closet = new Closet(session('uid')); } - public function index(Request $request) + public function index() + { + return view('user.closet')->with('user', app('user.current')); + } + + public function getClosetData(Request $request) { $category = $request->input('category', 'skin'); - $page = $request->input('page', 1); - $page = $page <= 0 ? 1 : $page; + $page = abs($request->input('page', 1)); $q = $request->input('q', null); $items = []; if ($q) { - foreach (['skin', 'cape'] as $category) { - // do search - foreach ($this->closet->getItems($category) as $item) { - if (strstr($item->name, $q)) { - $items[$category][] = $item; - } + // do search + foreach ($this->closet->getItems($category) as $item) { + if (stristr($item->name, $q)) { + $items[] = $item; } } } else { - $items['skin'] = $this->closet->getItems('skin'); - $items['cape'] = $this->closet->getItems('cape'); + $items = $this->closet->getItems($category); } // pagination - $total_pages = []; + $total_pages = ceil(count($items) / 6); - foreach ($items as $key => $value) { - $total_pages[] = ceil(count($items[$key]) / 6); - $items[$key] = array_slice($value, ($page-1)*6, 6); - } + $items = array_slice($items, ($page - 1) * 6, 6); - return view('user.closet')->with('items', $items) - ->with('page', $page) - ->with('q', $q) - ->with('category', $category) - ->with('total_pages', $total_pages ? max($total_pages) : 0) - ->with('user', app('user.current')); + return response()->json([ + 'category' => $category, + 'items' => $items, + 'total_pages' => $total_pages + ]); } public function info() diff --git a/app/Http/Routes/web.php b/app/Http/Routes/web.php index b512ae65..d2b2dad1 100644 --- a/app/Http/Routes/web.php +++ b/app/Http/Routes/web.php @@ -65,6 +65,7 @@ Route::group(['middleware' => 'auth', 'prefix' => 'user'], function () // Closet Route::get ('/closet', 'ClosetController@index'); + Route::get ('/closet-data', 'ClosetController@getClosetData'); Route::post('/closet/add', 'ClosetController@add'); Route::post('/closet/remove', 'ClosetController@remove'); Route::post('/closet/rename', 'ClosetController@rename'); diff --git a/bower.json b/bower.json index 867479f8..c4771d4e 100644 --- a/bower.json +++ b/bower.json @@ -24,6 +24,11 @@ "font-awesome": "Font-Awesome#^4.6.3", "bootstrap-fileinput": "^4.3.3", "bootstrap": "^3.3.6", - "sweetalert2": "^4.1.6" + "sweetalert2": "^4.1.6", + "jqPaginator": "^1.2.0", + "lodash": "^4.17.4" + }, + "resolutions": { + "jquery": "1.9.1 - 3" } } diff --git a/gulpfile.js b/gulpfile.js index d1a8c8af..836178e9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -25,6 +25,7 @@ var srcPath = 'resources/assets/src/'; var distPath = 'resources/assets/dist/'; var vendorScripts = [ + 'lodash/dist/lodash.min.js', 'jquery/dist/jquery.min.js', 'bootstrap/dist/js/bootstrap.min.js', 'AdminLTE/dist/js/app.min.js', @@ -35,6 +36,7 @@ var vendorScripts = [ 'toastr/toastr.min.js', 'es6-promise/es6-promise.auto.min.js', 'sweetalert2/dist/sweetalert2.min.js', + 'jqPaginator/dist/jqPaginator.min.js', 'resources/assets/dist/scripts/general.js', ]; diff --git a/resources/assets/src/scripts/user.js b/resources/assets/src/scripts/user.js index 9ed9685e..545873d2 100644 --- a/resources/assets/src/scripts/user.js +++ b/resources/assets/src/scripts/user.js @@ -18,13 +18,13 @@ $('body').on('click', '#preview-switch', () => { TexturePreview.previewType == '3D' ? TexturePreview.show2dPreview() : TexturePreview.show3dPreview(); }); -var selected = []; +let skinSelected = false, capeSelected = false; $('body').on('click', '.item-body', function () { $('.item-selected').parent().removeClass('item-selected'); $(this).parent().addClass('item-selected'); - let tid = $(this).parent().attr('tid'); + const tid = $(this).parent().attr('tid'); $.ajax({ type: "POST", @@ -33,24 +33,95 @@ $('body').on('click', '.item-body', function () { success: (json) => { if (json.type == "cape") { MSP.changeCape('../textures/' + json.hash); - selected['cape'] = tid; + capeSelected = true; } else { MSP.changeSkin('../textures/' + json.hash); - selected['skin'] = tid; + skinSelected = true; } - selected.length = 0; - - ['skin', 'cape'].forEach((key) => { - if (selected[key] !== undefined) selected.length++; - - $('#textures-indicator').html(selected.length); - }); + if (skinSelected && capeSelected) + $('#textures-indicator').text(`${trans('general.skin')} & ${trans('general.cape')}`); + else if (skinSelected) + $('#textures-indicator').text(trans('general.skin')); + else if (capeSelected) + $('#textures-indicator').text(trans('general.cape')); }, error: showAjaxError }); }); +$('body').on('click', '.category-switch', () => { + const category = $('a[href="#skin-category"]').parent().hasClass('active') ? 'cape' : 'skin'; + const page = parseInt($('#closet-paginator').attr(`last-${category}-page`)); + const search = $('input[name=q]').val(); + reloadCloset(category, page, search); +}); + +function renderClosetItemComponent(item, rootPath) { + return ` +
+
+ +
+ +
`; +} + +function renderCloset(items, category) { + const rootPath = /(^https?.*)\/user\/closet/.exec(window.location.href)[1]; + const search = $('input[name=q]').val(); + let container = $(`#${category}-category`); + container.html(''); + if (items.length === 0) { + $('#closet-paginator').hide(); + if (search === '') { + container.html(`
+ ${trans('user.emptyClosetMsg', { url: rootPath + '/skinlib?filter=' + category })}
`); + } else { + container.html(`
${trans('general.noResult')}
`); + } + } else { + $('#closet-paginator').show(); + for (const item of items) { + container.append(renderClosetItemComponent(item, rootPath)); + } + } +} + +function reloadCloset(category, page, search) { + Promise.resolve($.ajax({ + type: 'GET', + url: /(^https?.*)\/user\/closet/.exec(window.location.href)[1] + '/user/closet-data', + dataType: 'json', + data: { + category: category, + page: page, + q: search + } + })).then(result => { + renderCloset(result.items, result.category); + let paginator = $('#closet-paginator'); + paginator.attr(`last-${result.category}-page`, page); + paginator.jqPaginator('option', { + currentPage: page, + totalPages: result.total_pages + }); + }).catch(error => showAjaxError); +} + function showPlayerTexturePreview(pid) { $.ajax({ type: "POST", @@ -179,6 +250,43 @@ $(document).ready(function() { confirmButtonText: trans('general.confirm'), cancelButtonText: trans('general.cancel') }); + + if (window.location.pathname.includes('/user/closet')) { + Promise.resolve($.ajax({ + type: 'GET', + url: /(^https?.*)\/user\/closet/.exec(window.location.href)[1] + '/user/closet-data', + dataType: 'json' + })).then(result => { + renderCloset(result.items, result.category); + $('#closet-paginator').jqPaginator({ + totalPages: result.total_pages, + visiblePages: 5, + currentPage: 1, + first: '
  • «
  • ', + prev: '
  • ', + next: '
  • ', + last: '
  • »
  • ', + page: '
  • {{page}}
  • ', + wrapper: '', + onPageChange: page => { + reloadCloset( + $('#skin-category').hasClass('active') ? 'skin' : 'cape', + page, + $('input[name=q]').val() + ); + } + }); + }).catch(error => showAjaxError); + + $('input[name=q]').on('input', _.debounce(() => { + const category = $('#skin-category').hasClass('active') ? 'skin' : 'cape'; + reloadCloset( + category, + 1, + $('input[name=q]').val() + ); + }, 350)); + } }); function setTexture() { diff --git a/resources/lang/en/locale.js b/resources/lang/en/locale.js index ae4d7f62..80fe4ac5 100644 --- a/resources/lang/en/locale.js +++ b/resources/lang/en/locale.js @@ -68,6 +68,11 @@ signInRemainingTime: 'Available after :time hours', // Closet + emptyClosetMsg: '

    Nothing in your closet...

    Why not explore the Skin Library for a while?

    ', + renameItem: 'Rename item', + removeItem: 'Remove from closet', + setAsAvatar: 'Set as avatar', + viewInSkinlib: 'View in skin library', switch2dPreview: 'Switch to 2D Preview', switch3dPreview: 'Switch to 3D Preview', removeFromClosetNotice: 'Sure to remove this texture from your closet?', @@ -153,10 +158,14 @@ extracting: 'Extracting update package..' }, general: { + skin: 'Skin', + cape: 'Cape', fatalError: 'Fatal Error (Please contact the author)', confirmLogout: 'Sure to log out?', confirm: 'OK', - cancel: 'Cancel' + cancel: 'Cancel', + more: 'More', + noResult: 'No result.' } }; })(window.jQuery); diff --git a/resources/lang/en/user.yml b/resources/lang/en/user.yml index a9b019df..761d28e6 100644 --- a/resources/lang/en/user.yml +++ b/resources/lang/en/user.yml @@ -28,13 +28,11 @@ score-intro: closet: upload: Upload Texture search: Search Texture + type-to-search: Type to search switch-category: Switch Category view: View in skin library more: More set-avatar: Set as avatar - empty-msg: | -

    Nothing in your closet...

    -

    Why not explore the Skin Library for a while?

    use-as: button: Apply... diff --git a/resources/lang/zh_CN/locale.js b/resources/lang/zh_CN/locale.js index d68cb06b..4a9fa546 100644 --- a/resources/lang/zh_CN/locale.js +++ b/resources/lang/zh_CN/locale.js @@ -68,6 +68,11 @@ signInRemainingTime: ':time 小时后可签到', // Closet + emptyClosetMsg: '

    衣柜里啥都没有哦~

    皮肤库看看吧~

    ', + renameItem: '重命名物品', + removeItem: '从衣柜中移除', + setAsAvatar: '设为头像', + viewInSkinlib: '在皮肤库中查看', switch2dPreview: '切换 2D 预览', switch3dPreview: '切换 3D 预览', removeFromClosetNotice: '确定要从衣柜中移除此材质吗?', @@ -153,10 +158,14 @@ extracting: '正在解压更新包' }, general: { + skin: '皮肤', + cape: '披风', fatalError: '严重错误(请联系作者)', confirmLogout: '确定要登出吗?', confirm: '确定', - cancel: '取消' + cancel: '取消', + more: '更多', + noResult: '无结果' }, vendor: { datatables: { diff --git a/resources/lang/zh_CN/user.yml b/resources/lang/zh_CN/user.yml index ad7b9861..19e8ffc7 100644 --- a/resources/lang/zh_CN/user.yml +++ b/resources/lang/zh_CN/user.yml @@ -35,13 +35,11 @@ score-intro: closet: upload: 上传材质 search: 搜索材质 + type-to-search: 输入即搜索 switch-category: 切换分类 view: 在皮肤库中查看 more: 更多 set-avatar: 设为头像 - empty-msg: | -

    衣柜里啥都没有哦~

    -

    皮肤库看看吧~

    use-as: button: 使用... diff --git a/resources/views/user/closet.tpl b/resources/views/user/closet.tpl index 219e1426..993fbaa6 100644 --- a/resources/views/user/closet.tpl +++ b/resources/views/user/closet.tpl @@ -26,51 +26,30 @@ - +
    diff --git a/resources/views/vendor/closet-items.tpl b/resources/views/vendor/closet-items.tpl deleted file mode 100644 index 6f0f4bf4..00000000 --- a/resources/views/vendor/closet-items.tpl +++ /dev/null @@ -1,30 +0,0 @@ -@forelse ($items as $item) -
    -
    - -
    - -
    -@empty -
    - @if($q) - {{ trans('skinlib.general.no-result') }} - @else - {!! trans('user.closet.empty-msg', ['url' => url('skinlib')]) !!} - @endif -
    - -@endforelse