diff --git a/app/Http/Controllers/SkinlibController.php b/app/Http/Controllers/SkinlibController.php
index efa04cb1..776cf2b7 100644
--- a/app/Http/Controllers/SkinlibController.php
+++ b/app/Http/Controllers/SkinlibController.php
@@ -28,94 +28,91 @@ class SkinlibController extends Controller
$this->user = $users->get(session('uid'));
}
- public function index(Request $request)
+ public function index()
{
- $filter = $request->input('filter', 'skin');
- $sort = $request->input('sort', 'time');
- $uid = intval($request->input('uid', 0));
- $page = $request->input('page', 1);
- $page = $page <= 0 ? 1 : $page;
-
- $sort_by = ($sort == "time") ? "upload_at" : $sort;
-
- if ($filter == "skin") {
- $textures = Texture::where(function($query) {
- // Nested condition, DO NOT MODIFY
- $query->where('type', '=', 'steve')->orWhere('type', '=', 'alex');
- });
- } else {
- $textures = Texture::where('type', $filter);
- }
-
- if ($uid != 0) {
- $textures = $textures->where('uploader', $uid);
- }
-
- if (!is_null($this->user)) {
-
- // show private textures when show uploaded textures of current user
- if ($uid != $this->user->uid && !$this->user->isAdmin()) {
- $textures = $textures->where('public', 1)
- ->merge($textures->where('uploader', $this->user->uid));
- }
-
- } else {
- $textures = $textures->where('public', 1);
- }
-
- $total_pages = ceil($textures->count() / 20);
-
- $textures = $textures->orderBy($sort_by, 'desc')->skip(($page - 1) * 20)->take(20)->get();
-
- return view('skinlib.index')->with('user', $this->user)
- ->with('sort', $sort)
- ->with('filter', $filter)
- ->with('uploader', $uid)
- ->with('textures', $textures)
- ->with('page', $page)
- ->with('total_pages', $total_pages);
+ return view('skinlib.index', ['user' => $this->user]);
}
- public function search(Request $request)
+ /**
+ * Get skin library data filtered.
+ * Available Query String: filter, uploader, page, sort, keyword, items_per_page.
+ *
+ * @param Request $request [description]
+ * @return [type] [description]
+ */
+ public function getSkinlibFiltered(Request $request)
{
- $q = $request->input('q', '');
+
+ // Available filters: skin, steve, alex, cape
$filter = $request->input('filter', 'skin');
- $sort = $request->input('sort', 'time');
- $sort_by = ($sort == "time") ? "upload_at" : $sort;
+ // Filter result by uploader's uid
+ $uploader = intval($request->input('uploader', 0));
- if ($q == '') {
- return redirect('skinlib');
- }
+ // Available sorting methods: time, likes
+ $sort = $request->input('sort', 'time');
+ $sortBy = ($sort == "time") ? "upload_at" : $sort;
+
+ // Current page
+ $page = $request->input('page', 1);
+ $currentPage = ($page <= 0) ? 1 : $page;
+
+ // How many items to show in one page
+ $itemsPerPage = $request->input('items_per_page', 20);
+
+ // Keyword to search
+ $keyword = $request->input('keyword', '');
+
+ // Check if user logged in
+ $anonymous = is_null($this->user);
if ($filter == "skin") {
- $textures = Texture::like('name', $q)->where(function($query) use ($q) {
- $query->where('type', '=', 'steve')
- ->orWhere('type', '=', 'alex');
- })->orderBy($sort_by, 'desc')->get();
+ $query = Texture::where(function ($innerQuery) {
+ // Nested condition, DO NOT MODIFY
+ $innerQuery->where('type', '=', 'steve')->orWhere('type', '=', 'alex');
+ });
} else {
- $textures = Texture::like('name', $q)
- ->where('type', $filter)
- ->where('public', 1)
- ->orderBy($sort_by, 'desc')->get();
+ $query = Texture::where('type', $filter);
}
- if (!is_null($this->user)) {
- // show private textures when show uploaded textures of current user
- if (!$this->user->isAdmin()) {
- $textures = $textures->where('public', 1)
- ->merge($textures->where('uploader', $this->user->uid));
+ if ($keyword !== "") {
+ $query = $query->like('name', $keyword);
+ }
+
+ if ($uploader !== 0) {
+ $query = $query->where('uploader', $uploader);
+ }
+
+ if ($anonymous) {
+ // Show public textures only to anonymous visitors
+ $query = $query->where('public', 1);
+ } else {
+ // Show private textures when show uploaded textures of current user
+ if ($uploader != $this->user->uid && !$this->user->isAdmin()) {
+ $query = $query->where(function ($innerQuery) {
+ $innerQuery->where('public', '=', '1')->orWhere('uploader', '=', $this->user->uid);
+ });
}
- } else {
- $textures = $textures->where('public', 1);
}
- return view('skinlib.search')->with('user', $this->user)
- ->with('sort', $sort)
- ->with('filter', $filter)
- ->with('uploader', 0)
- ->with('q', $q)
- ->with('textures', $textures);
+ $totalPages = ceil($query->count() / 20);
+
+ $textures = $query->orderBy($sortBy, 'desc')
+ ->skip(($currentPage - 1) * $itemsPerPage)
+ ->take($itemsPerPage)
+ ->get();
+
+ if (! $anonymous) {
+ foreach ($textures as $item) {
+ $item->liked = $this->user->getCloset()->has($item->tid);
+ }
+ }
+
+ return response()->json([
+ 'items' => $textures,
+ 'anonymous' => $anonymous,
+ 'total_pages' => $totalPages
+ ]);
}
public function show($tid)
diff --git a/resources/assets/src/scripts/general.js b/resources/assets/src/scripts/general.js
index d30dc253..8cb2dce1 100644
--- a/resources/assets/src/scripts/general.js
+++ b/resources/assets/src/scripts/general.js
@@ -12,6 +12,17 @@ console.log(`\n %c Blessing Skin v${blessing.version} %c https://blessing.studio
$.locales = {};
$.currentLocale = {};
+$.defaultPaginatorConfig = {
+ visiblePages: 5,
+ currentPage: 1,
+ first: '
«',
+ prev: '‹',
+ next: '›',
+ last: '»',
+ page: '{{page}}',
+ wrapper: ''
+};
+
/**
* Check if given value is empty.
*
@@ -23,6 +34,8 @@ function isEmpty(obj) {
// null and undefined are "empty"
if (obj == null) return true;
+ if (typeof (obj) == 'number' || typeof (obj) == 'boolean') return false;
+
// Assume if it has a length property with a non-zero value
// that that property is correct.
if (obj.length > 0) return false;
@@ -145,13 +158,14 @@ function showAjaxError(json) {
* Get parameters in query string with key.
*
* @param {string} key
+ * @param {string} defaultValue
* @return {string}
*/
-function getQueryString(key) {
+function getQueryString(key, defaultValue) {
result = location.search.match(new RegExp('[\?\&]'+key+'=([^\&]+)','i'));
if (result == null || result.length < 1){
- return null;
+ return defaultValue;
} else {
return result[1];
}
diff --git a/resources/assets/src/scripts/skinlib.js b/resources/assets/src/scripts/skinlib.js
index d5d7b6c7..be00e657 100644
--- a/resources/assets/src/scripts/skinlib.js
+++ b/resources/assets/src/scripts/skinlib.js
@@ -1,38 +1,29 @@
/*
* @Author: printempw
* @Date: 2016-07-19 10:46:38
- * @Last Modified by: g-plane
- * @Last Modified time: 2017-04-25 21:56:19
+ * @Last Modified by: printempw
+ * @Last Modified time: 2017-06-30 10:25:12
*/
'use strict';
-$(document).ready(() => swal.setDefaults({
- confirmButtonText: trans('general.confirm'),
- cancelButtonText: trans('general.cancel')
-}));
+$(document).ready(() => {
+ swal.setDefaults({
+ confirmButtonText: trans('general.confirm'),
+ cancelButtonText: trans('general.cancel')
+ });
-$('#page-select').on('change', function () {
- let sort = getQueryString('sort'),
- page = getQueryString('page'),
- filter = getQueryString('filter');
+ if ($('#skinlib-container').length != 0) {
+ // Initially render skinlib
+ requestSkinlibData().then(result => {
+ renderSkinlib(result.items);
- let targetPage = $(this).val();
-
- // if has query strings
- if (filter || sort) {
-
- if (page == null) {
- // append "&page=" to current URL
- window.location = `${location.href}&page=${targetPage}`;
- } else {
- window.location = `?filter=${filter}&sort=${sort}&page=${targetPage}`;
- }
-
- } else {
- window.location = `?page=${targetPage}`;
+ updatePaginator(
+ $.skinlib.page,
+ result.total_pages || 1
+ );
+ });
}
-
});
$('#private').on('ifToggled', function () {
@@ -42,6 +33,223 @@ $('#type-skin').on('ifToggled', function () {
$(this).prop('checked') ? $('#skin-type').show() : $('#skin-type').hide();
});
+$.skinlib = {
+ page: getQueryString('page', 1),
+ filter: getQueryString('filter', 'skin'),
+ sort: getQueryString('sort', 'time'),
+ uploader: getQueryString('uploader', 0),
+ keyword: decodeURI(getQueryString('keyword', ''))
+};
+
+$(document).ready(() => {
+
+});
+
+function renderSkinlib(items) {
+ let container = $('#skinlib-container').html('');
+
+ if (items.length === 0) {
+ $('#skinlib-paginator').hide();
+
+ container.html(`
+ ${ trans('general.noResult') }
+
`);
+ } else {
+ $('#skinlib-paginator').show();
+
+ for (const item of items) {
+ container.append(renderSkinlibItemComponent(item));
+ }
+ }
+
+ $('.overlay').hide();
+}
+
+function reloadSkinlib() {
+ requestSkinlibData().then(result => {
+ $('.overlay').show();
+ renderSkinlib(result.items);
+
+ updatePaginator($.skinlib.page, result.total_pages || 1);
+ }).then(() => {
+ updateUrlQueryString();
+ updateBreadCrumb();
+ });
+}
+
+function requestSkinlibData() {
+ return Promise.resolve($.ajax({
+ type: 'GET',
+ url: url('skinlib/data'),
+ dataType: 'json',
+ data: $.skinlib,
+ error: showAjaxError
+ }));
+}
+
+function renderSkinlibItemComponent(item) {
+ let title = "";
+ let anonymous = "";
+ let liked = item.liked ? 'liked' : '';
+
+ if (item.liked === undefined) {
+ // If user haven't logged in
+ title = trans('skinlib.anonymous');
+ anonymous = 'anonymous';
+ } else {
+ title = item.liked ? trans('skinlib.removeFromCloset') : trans('skinlib.addToCloset');
+ }
+
+ return `
+
+
+
 })
+
+
+
+
+ `;
+}
+
+function updatePaginator(currentPage, totalPages) {
+ $.skinlib.page = currentPage;
+
+ $('p.pagination').text(trans('general.pagination', {
+ page: currentPage,
+ total: totalPages
+ }));
+
+ let paginator = $('#skinlib-paginator');
+
+ if (paginator.html().length == 0) {
+ // init paginator
+ $('#skinlib-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
+ currentPage: parseInt(currentPage),
+ totalPages: parseInt(totalPages),
+ onPageChange: onPageChange
+ }));
+ } else {
+ $('#skinlib-paginator').jqPaginator('option', {
+ currentPage: parseInt(currentPage),
+ totalPages: parseInt(totalPages)
+ });
+ }
+
+ let pageSelectElement = $('select.pagination').html('');
+
+ for (let i = 1; i <= totalPages; i++) {
+ pageSelectElement.append(`
+
+ `);
+ }
+}
+
+function onPageChange(page, type) {
+ $.skinlib.page = page;
+ updateBreadCrumb();
+
+ if (type == "init") {
+ console.log('Init paginator', page);
+ } else {
+ $('.overlay').show();
+ reloadSkinlib();
+
+ console.log('Rendering page', page);
+ }
+}
+
+$('select.pagination').on('change', function () {
+ onPageChange(parseInt($(this).val()));
+});
+
+$(document).on('click', '.more.like', function () {
+ let tid = $(this).attr('tid');
+
+ if ($(this).hasClass('anonymous'))
+ return;
+
+ if ($(this).hasClass('liked')) {
+ removeFromCloset(tid);
+ } else {
+ addToCloset(tid);
+ }
+});
+
+$('.filter').click(function (e) {
+ e.preventDefault();
+ let selectedFilter = $(this).data('filter');
+
+ if (selectedFilter == "uploader") {
+ $.skinlib.uploader = $(this).data('uid');
+ console.log('Show items uploaded by uid ' + $.skinlib.uploader);
+ } else {
+ $.skinlib.filter = selectedFilter;
+ console.log('Filter by ' + $.skinlib.filter);
+ }
+
+ reloadSkinlib();
+});
+
+$('.sort').click(function (e) {
+ e.preventDefault();
+ $.skinlib.sort = $(this).data('sort');
+
+ console.log('Sort by ' + $.skinlib.sort);
+ reloadSkinlib();
+});
+
+$('#search-form').submit(function (e) {
+ e.preventDefault();
+ $.skinlib.keyword = $('#navbar-search-input').val();
+
+ console.log('Search keyword: ' + $.skinlib.keyword);
+ reloadSkinlib();
+});
+
+function updateUrlQueryString() {
+ let query = $.param($.skinlib);
+
+ window.history.pushState(null, null, url(`skinlib?${query}`));
+}
+
+function updateBreadCrumb() {
+ if ($.skinlib.filter == "cape") {
+ $('#filter-indicator').html(trans('general.cape'));
+ } else {
+ $('#filter-indicator').html(trans('general.skin') + `
+ ${ 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').html(trans('general.searchResult', {
+ keyword: decodeURI($.skinlib.keyword)
+ }));
+
+ $('#navbar-search-input').val(decodeURI($.skinlib.keyword));
+ }
+}
+
function addToCloset(tid) {
$.getJSON(url(`skinlib/info/${tid}`), (json) => {
swal({
@@ -274,7 +482,7 @@ function changeTextureName(tid, oldName) {
});
}
-$('.private-label').click(function () {
+$(document).on('click', '.private-label', function () {
swal({
text: trans('skinlib.setPublicNotice'),
type: 'warning',
diff --git a/resources/assets/src/scripts/user.js b/resources/assets/src/scripts/user.js
index b0051226..88c017a8 100644
--- a/resources/assets/src/scripts/user.js
+++ b/resources/assets/src/scripts/user.js
@@ -261,20 +261,12 @@ $(document).ready(function() {
if (window.location.pathname.includes('/user/closet')) {
Promise.resolve($.ajax({
type: 'GET',
- url: /(^https?.*)\/user\/closet/.exec(window.location.href)[1] + '/user/closet-data',
+ url: url('/user/closet-data'),
dataType: 'json'
})).then(result => {
renderCloset(result.items, result.category);
- $('#closet-paginator').jqPaginator({
+ $('#closet-paginator').jqPaginator($.extend({}, $.defaultPaginatorConfig, {
totalPages: result.total_pages,
- visiblePages: 5,
- currentPage: 1,
- first: '«',
- prev: '‹',
- next: '›',
- last: '»',
- page: '{{page}}',
- wrapper: '',
onPageChange: page => {
reloadCloset(
$('#skin-category').hasClass('active') ? 'skin' : 'cape',
@@ -282,7 +274,7 @@ $(document).ready(function() {
$('input[name=q]').val()
);
}
- });
+ }));
}).catch(error => showAjaxError);
$('input[name=q]').on('input', debounce(() => {
diff --git a/resources/assets/src/styles/general.scss b/resources/assets/src/styles/general.scss
index 6547e05f..35ae4e34 100644
--- a/resources/assets/src/styles/general.scss
+++ b/resources/assets/src/styles/general.scss
@@ -40,13 +40,6 @@ input:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px #fff inset !important;
}
-#page-select {
- padding-left: 0;
- margin: 0 20px 0 0;
- border-radius: 4px;
- padding: 5.5px 14px;
-}
-
.item {
display: block;
background: #EFF1F0;
diff --git a/resources/assets/src/styles/skinlib.scss b/resources/assets/src/styles/skinlib.scss
index 5dc85161..174f6f4d 100644
--- a/resources/assets/src/styles/skinlib.scss
+++ b/resources/assets/src/styles/skinlib.scss
@@ -74,3 +74,32 @@ table {
.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/lang/en/general.yml b/resources/lang/en/general.yml
index d144fd74..7cf2252a 100644
--- a/resources/lang/en/general.yml
+++ b/resources/lang/en/general.yml
@@ -27,7 +27,7 @@ close: Close
skin: Skin
cape: Cape
-pagination: Page :page, total :total
+loading: Loading
texture-preview: Texture Preview
walk: Walk
diff --git a/resources/lang/en/locale.js b/resources/lang/en/locale.js
index 70f0533f..2c880e1d 100644
--- a/resources/lang/en/locale.js
+++ b/resources/lang/en/locale.js
@@ -47,6 +47,20 @@
setNewTextureName: 'Please enter the new texture name:',
emptyNewTextureName: 'Empty new texture name.',
+ // Skinlib
+ filter: {
+ skin: '(Any Model)',
+ steve: '(Steve)',
+ alex: '(Alex)',
+ cape: '(Cape)',
+ uploader: 'User (UID = :uid) Uploaded',
+ allUsers: 'All Users'
+ },
+ sort: {
+ time: 'Newestly Uploaded',
+ likes: 'Most Likes'
+ },
+
// Upload
emptyTextureName: 'Empty texture name.',
emptyTextureType: 'Please select a type for this texture.',
@@ -173,6 +187,8 @@
confirm: 'OK',
cancel: 'Cancel',
more: 'More',
+ pagination: 'Page :page, total :total',
+ searchResult: '(Search result of keyword ":keyword")',
noResult: 'No result.'
}
};
diff --git a/resources/lang/en/skinlib.yml b/resources/lang/en/skinlib.yml
index 23db7b47..cd907acb 100644
--- a/resources/lang/en/skinlib.yml
+++ b/resources/lang/en/skinlib.yml
@@ -29,10 +29,6 @@ item:
anonymous: Please login first
private: Private
-search:
- title: 'Search Result: :query'
- no-keywords: No keywords given
-
show:
title: Texture Details
anonymous: You must login to use closets
diff --git a/resources/lang/zh_CN/general.yml b/resources/lang/zh_CN/general.yml
index bcffc4f7..ef2c6f69 100644
--- a/resources/lang/zh_CN/general.yml
+++ b/resources/lang/zh_CN/general.yml
@@ -27,7 +27,7 @@ close: 关闭
skin: 皮肤
cape: 披风
-pagination: 第 :page 页,共 :total 页
+loading: 正在加载
texture-preview: 材质预览
walk: 行走
diff --git a/resources/lang/zh_CN/locale.js b/resources/lang/zh_CN/locale.js
index 49f718dd..24a4066b 100644
--- a/resources/lang/zh_CN/locale.js
+++ b/resources/lang/zh_CN/locale.js
@@ -42,6 +42,22 @@
removeFromCloset: '从衣柜中移除',
setItemName: '给你的皮肤起个名字吧~',
emptyItemName: '你还没有填写要收藏的材质名称啊',
+ anonymous: '请先登录',
+ private: '私密',
+
+ // Skinlib
+ filter: {
+ skin: '(任意模型)',
+ steve: '(Steve)',
+ alex: '(Alex)',
+ cape: '(披风)',
+ uploader: '用户(UID = :uid)上传',
+ allUsers: '所有用户'
+ },
+ sort: {
+ time: '最新上传',
+ likes: '最多收藏'
+ },
// Rename
setNewTextureName: '请输入新的材质名称:',
@@ -173,6 +189,8 @@
confirm: '确定',
cancel: '取消',
more: '更多',
+ pagination: '第 :page 页,共 :total 页',
+ searchResult: '(关键词 “:keyword” 的搜索结果)',
noResult: '无结果'
},
vendor: {
diff --git a/resources/lang/zh_CN/skinlib.yml b/resources/lang/zh_CN/skinlib.yml
index c4e3eab1..9d1ce783 100644
--- a/resources/lang/zh_CN/skinlib.yml
+++ b/resources/lang/zh_CN/skinlib.yml
@@ -29,10 +29,6 @@ item:
anonymous: 请先登录
private: 私密
-search:
- title: 搜索结果::query
- no-keywords: 未指定关键字
-
show:
title: 材质详情
anonymous: 登录后才能使用衣柜哦
diff --git a/resources/views/skinlib/index.tpl b/resources/views/skinlib/index.tpl
index 5350d796..63d29af1 100644
--- a/resources/views/skinlib/index.tpl
+++ b/resources/views/skinlib/index.tpl
@@ -8,27 +8,33 @@
diff --git a/resources/views/skinlib/item.tpl b/resources/views/skinlib/item.tpl
deleted file mode 100644
index 5d6259e4..00000000
--- a/resources/views/skinlib/item.tpl
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-

-
-
-
-
diff --git a/resources/views/skinlib/master.tpl b/resources/views/skinlib/master.tpl
index 93ef6d89..f6950c99 100644
--- a/resources/views/skinlib/master.tpl
+++ b/resources/views/skinlib/master.tpl
@@ -20,7 +20,9 @@