mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-07 22:45:46 +01:00
feat: #7023
- add category selector to privileges and category create modals - allow category selector to work for multiple selectors on same page
This commit is contained in:
@@ -235,13 +235,14 @@ body {
|
|||||||
margin: 35px 5px 0 5px;
|
margin: 35px 5px 0 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[component="category-selector"] {
|
||||||
.category-dropdown-menu {
|
|
||||||
max-height: 600px;
|
|
||||||
overflow-y: auto;
|
|
||||||
.fa-stack {
|
.fa-stack {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
.category-dropdown-menu {
|
||||||
|
max-height: 600px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-reordering {
|
.table-reordering {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
define('admin/manage/categories', [
|
||||||
define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-serializeobject.min', 'translator', 'benchpress'], function (serialize, translator, Benchpress) {
|
'vendor/jquery/serializeObject/jquery.ba-serializeobject.min',
|
||||||
|
'translator',
|
||||||
|
'benchpress',
|
||||||
|
'categorySelector',
|
||||||
|
], function (serialize, translator, Benchpress, categorySelector) {
|
||||||
var Categories = {};
|
var Categories = {};
|
||||||
var newCategoryId = -1;
|
var newCategoryId = -1;
|
||||||
var sortables;
|
var sortables;
|
||||||
@@ -54,11 +58,16 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
|
|||||||
};
|
};
|
||||||
|
|
||||||
Categories.throwCreateModal = function () {
|
Categories.throwCreateModal = function () {
|
||||||
socket.emit('admin.categories.getNames', {}, function (err, categories) {
|
socket.emit('categories.getSelectCategories', {}, function (err, categories) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
categories.unshift({
|
||||||
|
cid: 0,
|
||||||
|
name: '[[admin/manage/categories:parent-category-none]]',
|
||||||
|
icon: 'fa-none',
|
||||||
|
});
|
||||||
Benchpress.parse('admin/partials/categories/create', {
|
Benchpress.parse('admin/partials/categories/create', {
|
||||||
categories: categories,
|
categories: categories,
|
||||||
}, function (html) {
|
}, function (html) {
|
||||||
@@ -74,11 +83,15 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var parentSelector = categorySelector.init(modal.find('#parentCidGroup [component="category-selector"]'));
|
||||||
|
var cloneFromSelector = categorySelector.init(modal.find('#cloneFromCidGroup [component="category-selector"]'));
|
||||||
function submit() {
|
function submit() {
|
||||||
var formData = modal.find('form').serializeObject();
|
var formData = modal.find('form').serializeObject();
|
||||||
formData.description = '';
|
formData.description = '';
|
||||||
formData.icon = 'fa-comments';
|
formData.icon = 'fa-comments';
|
||||||
formData.uid = app.user.uid;
|
formData.uid = app.user.uid;
|
||||||
|
formData.parentCid = parentSelector.getSelectedCid();
|
||||||
|
formData.cloneFromCid = cloneFromSelector.getSelectedCid();
|
||||||
|
|
||||||
Categories.create(formData);
|
Categories.create(formData);
|
||||||
modal.modal('hide');
|
modal.modal('hide');
|
||||||
@@ -87,11 +100,11 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
|
|||||||
|
|
||||||
$('#cloneChildren').on('change', function () {
|
$('#cloneChildren').on('change', function () {
|
||||||
var check = $(this);
|
var check = $(this);
|
||||||
var parentSelect = $('#parentCid');
|
var parentSelect = modal.find('#parentCidGroup [component="category-selector"] .dropdown-toggle');
|
||||||
|
|
||||||
if (check.prop('checked')) {
|
if (check.prop('checked')) {
|
||||||
parentSelect.attr('disabled', 'disabled');
|
parentSelect.attr('disabled', 'disabled');
|
||||||
parentSelect.val('');
|
parentSelector.selectCategory(0);
|
||||||
} else {
|
} else {
|
||||||
parentSelect.removeAttr('disabled');
|
parentSelect.removeAttr('disabled');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ define('admin/manage/privileges', [
|
|||||||
Privileges.init = function () {
|
Privileges.init = function () {
|
||||||
cid = ajaxify.data.cid || 0;
|
cid = ajaxify.data.cid || 0;
|
||||||
|
|
||||||
$('ul[for="category-selector"]').on('click', 'li', function () {
|
categorySelector.init($('[component="category-selector"]'), function (category) {
|
||||||
var val = this.getAttribute('data-cid');
|
var cid = parseInt(category.cid, 10);
|
||||||
ajaxify.go('admin/manage/privileges/' + (val === 'global' ? '' : val));
|
ajaxify.go('admin/manage/privileges/' + (cid || ''));
|
||||||
});
|
});
|
||||||
|
|
||||||
Privileges.setupPrivilegeTable();
|
Privileges.setupPrivilegeTable();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -179,7 +178,7 @@ define('admin/manage/privileges', [
|
|||||||
};
|
};
|
||||||
|
|
||||||
Privileges.copyPrivilegesFromCategory = function () {
|
Privileges.copyPrivilegesFromCategory = function () {
|
||||||
categorySelector.modal(function (fromCid) {
|
categorySelector.modal(ajaxify.data.categories.slice(1), function (fromCid) {
|
||||||
socket.emit('admin.categories.copyPrivilegesFrom', { toCid: cid, fromCid: fromCid }, function (err) {
|
socket.emit('admin.categories.copyPrivilegesFrom', { toCid: cid, fromCid: fromCid }, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
|
|||||||
@@ -2,32 +2,45 @@
|
|||||||
|
|
||||||
define('categorySelector', ['benchpress', 'translator', 'categorySearch'], function (Benchpress, translator, categorySearch) {
|
define('categorySelector', ['benchpress', 'translator', 'categorySearch'], function (Benchpress, translator, categorySearch) {
|
||||||
var categorySelector = {};
|
var categorySelector = {};
|
||||||
var selectedCategory;
|
|
||||||
var el;
|
categorySelector.init = function (el, callback) {
|
||||||
categorySelector.init = function (_el, callback) {
|
|
||||||
callback = callback || function () {};
|
callback = callback || function () {};
|
||||||
el = _el;
|
var selector = {
|
||||||
selectedCategory = null;
|
el: el,
|
||||||
|
selectedCategory: null,
|
||||||
|
};
|
||||||
|
|
||||||
el.on('click', '[data-cid]', function () {
|
el.on('click', '[data-cid]', function () {
|
||||||
var categoryEl = $(this);
|
var categoryEl = $(this);
|
||||||
categorySelector.selectCategory(categoryEl.attr('data-cid'));
|
if (categoryEl.hasClass('disabled')) {
|
||||||
callback(selectedCategory);
|
return false;
|
||||||
|
}
|
||||||
|
selector.selectCategory(categoryEl.attr('data-cid'));
|
||||||
|
callback(selector.selectedCategory);
|
||||||
});
|
});
|
||||||
|
|
||||||
categorySearch.init(el);
|
categorySearch.init(el);
|
||||||
};
|
|
||||||
|
|
||||||
categorySelector.getSelectedCategory = function () {
|
selector.selectCategory = function (cid) {
|
||||||
return selectedCategory;
|
var categoryEl = selector.el.find('[data-cid="' + cid + '"]');
|
||||||
};
|
selector.selectedCategory = {
|
||||||
|
cid: cid,
|
||||||
|
name: categoryEl.attr('data-name'),
|
||||||
|
};
|
||||||
|
|
||||||
categorySelector.selectCategory = function (cid) {
|
if (categoryEl.length) {
|
||||||
var categoryEl = el.find('[data-cid="' + cid + '"]');
|
selector.el.find('[component="category-selector-selected"]').html(categoryEl.find('[component="category-markup"]').html());
|
||||||
selectedCategory = {
|
} else {
|
||||||
cid: cid,
|
selector.el.find('[component="category-selector-selected"]').translateHtml('[[topic:thread_tools.select_category]]');
|
||||||
name: categoryEl.attr('data-name'),
|
}
|
||||||
};
|
};
|
||||||
el.find('[component="category-selector-selected"]').html(categoryEl.find('[component="category-markup"]').html());
|
selector.getSelectedCategory = function () {
|
||||||
|
return selector.selectedCategory;
|
||||||
|
};
|
||||||
|
selector.getSelectedCid = function () {
|
||||||
|
return selector.selectedCategory ? selector.selectedCategory.cid : 0;
|
||||||
|
};
|
||||||
|
return selector;
|
||||||
};
|
};
|
||||||
|
|
||||||
categorySelector.modal = function (categories, callback) {
|
categorySelector.modal = function (categories, callback) {
|
||||||
@@ -50,12 +63,11 @@ define('categorySelector', ['benchpress', 'translator', 'categorySearch'], funct
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
categorySelector.init(modal.find('[component="category-selector"]'));
|
var selector = categorySelector.init(modal.find('[component="category-selector"]'));
|
||||||
function submit(ev) {
|
function submit(ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
var selectedCategory = categorySelector.getSelectedCategory();
|
if (selector.selectedCategory) {
|
||||||
if (selectedCategory) {
|
callback(selector.selectedCategory.cid);
|
||||||
callback(selectedCategory.cid);
|
|
||||||
modal.modal('hide');
|
modal.modal('hide');
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ privilegesController.get = function (req, res, callback) {
|
|||||||
privileges.categories.list(cid, next);
|
privileges.categories.list(cid, next);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
allCategories: function (next) {
|
categories: function (next) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
categories.getAllCidsFromSet('categories:cid', next);
|
categories.getAllCidsFromSet('categories:cid', next);
|
||||||
@@ -36,7 +36,12 @@ privilegesController.get = function (req, res, callback) {
|
|||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
function (data) {
|
function (data) {
|
||||||
data.allCategories.forEach(function (category) {
|
data.categories.unshift({
|
||||||
|
cid: 0,
|
||||||
|
name: '[[admin/manage/privileges:global]]',
|
||||||
|
icon: 'fa-list',
|
||||||
|
});
|
||||||
|
data.categories.forEach(function (category) {
|
||||||
if (category) {
|
if (category) {
|
||||||
category.selected = category.cid === cid;
|
category.selected = category.cid === cid;
|
||||||
|
|
||||||
@@ -48,8 +53,8 @@ privilegesController.get = function (req, res, callback) {
|
|||||||
|
|
||||||
res.render('admin/manage/privileges', {
|
res.render('admin/manage/privileges', {
|
||||||
privileges: data.privileges,
|
privileges: data.privileges,
|
||||||
allCategories: data.allCategories,
|
categories: data.categories,
|
||||||
selected: data.selected ? data.selected.name : '[[admin/manage/privileges:global]]',
|
selectedCategory: data.selected,
|
||||||
cid: cid,
|
cid: cid,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ SocketCategories.get = function (socket, data, callback) {
|
|||||||
isAdmin: async.apply(user.isAdministrator, socket.uid),
|
isAdmin: async.apply(user.isAdministrator, socket.uid),
|
||||||
categories: function (next) {
|
categories: function (next) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
async.apply(categories.getAllCidsFromSet, 'categories:cid'),
|
async.apply(categories.getCidsByPrivilege, 'categories:cid', socket.uid, 'find'),
|
||||||
async.apply(categories.getCategoriesData),
|
async.apply(categories.getCategoriesData),
|
||||||
], next);
|
], next);
|
||||||
},
|
},
|
||||||
@@ -132,23 +132,16 @@ SocketCategories.getCategoriesByPrivilege = function (socket, privilege, callbac
|
|||||||
};
|
};
|
||||||
|
|
||||||
SocketCategories.getMoveCategories = function (socket, data, callback) {
|
SocketCategories.getMoveCategories = function (socket, data, callback) {
|
||||||
|
SocketCategories.getSelectCategories(socket, data, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
SocketCategories.getSelectCategories = function (socket, data, callback) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
isAdmin: async.apply(user.isAdministrator, socket.uid),
|
isAdmin: async.apply(user.isAdministrator, socket.uid),
|
||||||
categories: function (next) {
|
categories: function (next) {
|
||||||
async.waterfall([
|
categories.buildForSelect(socket.uid, 'find', next);
|
||||||
function (next) {
|
|
||||||
categories.getAllCidsFromSet('categories:cid', next);
|
|
||||||
},
|
|
||||||
function (cids, next) {
|
|
||||||
categories.getCategories(cids, socket.uid, next);
|
|
||||||
},
|
|
||||||
function (categoriesData, next) {
|
|
||||||
categoriesData = categories.getTree(categoriesData);
|
|
||||||
categories.buildForSelectCategories(categoriesData, next);
|
|
||||||
},
|
|
||||||
], next);
|
|
||||||
},
|
},
|
||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,19 +5,10 @@
|
|||||||
[[admin/manage/categories:privileges.description]]
|
[[admin/manage/categories:privileges.description]]
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="lead">
|
<div class="lead">
|
||||||
[[admin/manage/categories:privileges.category-selector]]
|
[[admin/manage/categories:privileges.category-selector]]
|
||||||
<button type="button" id="category-selector" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
|
<!-- IMPORT partials/category-selector.tpl -->
|
||||||
{selected} <i class="fa fa-angle-down"></i>
|
</div>
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul class="mdl-menu mdl-menu--bottom-left mdl-js-menu mdl-js-ripple-effect" for="category-selector">
|
|
||||||
<li class="mdl-menu__item mdl-menu__item--full-bleed-divider" data-cid="global">[[admin/manage/privileges:global]]</li>
|
|
||||||
<!-- BEGIN allCategories -->
|
|
||||||
<li class="mdl-menu__item" data-cid="{../value}">{../text}</li>
|
|
||||||
<!-- END -->
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
|||||||
@@ -3,24 +3,14 @@
|
|||||||
<label for="name">[[admin/manage/categories:name]]</label>
|
<label for="name">[[admin/manage/categories:name]]</label>
|
||||||
<input type="text" class="form-control" name="name" id="name" />
|
<input type="text" class="form-control" name="name" id="name" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group" id="parentCidGroup">
|
||||||
<label for="parentCid">[[admin/manage/categories:optional-parent-category]]</label>
|
<label for="parentCid">[[admin/manage/categories:optional-parent-category]]</label>
|
||||||
<select class="form-control" name="parentCid" id="parentCid">
|
<!-- IMPORT partials/category-selector.tpl -->
|
||||||
<option value=""></option>
|
|
||||||
<!-- BEGIN categories -->
|
|
||||||
<option value="{categories.cid}">{categories.name}</option>
|
|
||||||
<!-- END categories -->
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group" id="cloneFromCidGroup">
|
||||||
<label for="cloneFromCid">[[admin/manage/categories:optional-clone-settings]]</label>
|
<label for="cloneFromCid">[[admin/manage/categories:optional-clone-settings]]</label>
|
||||||
<select class="form-control" name="cloneFromCid" id="cloneFromCid">
|
<!-- IMPORT partials/category-selector.tpl -->
|
||||||
<option value=""></option>
|
|
||||||
<!-- BEGIN categories -->
|
|
||||||
<option value="{categories.cid}">{categories.name}</option>
|
|
||||||
<!-- END categories -->
|
|
||||||
</select>
|
|
||||||
<label>
|
<label>
|
||||||
<input id="cloneChildren" name="cloneChildren" type="checkbox">
|
<input id="cloneChildren" name="cloneChildren" type="checkbox">
|
||||||
<strong>[[admin/manage/categories:clone-children]]</strong>
|
<strong>[[admin/manage/categories:clone-children]]</strong>
|
||||||
|
|||||||
Reference in New Issue
Block a user