client/tags: add setting default tag category
This commit is contained in:
parent
77998f1660
commit
7aaa28f9de
5 changed files with 110 additions and 63 deletions
|
@ -29,5 +29,6 @@ $button-disabled-text-color = #666
|
|||
$button-disabled-background-color = #CCC
|
||||
$new-tag-background-color = #DFC
|
||||
$new-tag-text-color = black
|
||||
$default-tag-category-background-color = $active-tab-background-color
|
||||
$duplicate-tag-background-color = #FDC
|
||||
$duplicate-tag-text-color = black
|
||||
|
|
|
@ -57,23 +57,20 @@
|
|||
|
||||
.content-wrapper.tag-categories
|
||||
width: 100%
|
||||
max-width: 35em
|
||||
max-width: 40em
|
||||
table
|
||||
border-spacing: 0
|
||||
width: 100%
|
||||
tr.default td
|
||||
background: $default-tag-category-background-color
|
||||
td, th
|
||||
padding: .2em
|
||||
&:first-child
|
||||
padding-left: 0
|
||||
&:last-child
|
||||
padding-right: 0
|
||||
&.name
|
||||
width: 35%
|
||||
padding: .4em
|
||||
&.color
|
||||
text-align: center
|
||||
width: 35%
|
||||
&.usages
|
||||
text-align: center
|
||||
width: 10%
|
||||
&.remove, &.set-default
|
||||
white-space: pre
|
||||
tfoot
|
||||
display: none
|
||||
.messages, form
|
||||
|
|
|
@ -11,7 +11,11 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<% _.each(ctx.tagCategories, category => { %>
|
||||
<tr data-category='<%= category.name %>'>
|
||||
<% if (category.default) { %>
|
||||
<tr data-category='<%= category.name %>' class='default'>
|
||||
<% } else { %>
|
||||
<tr data-category='<%= category.name %>'>
|
||||
<% } %>
|
||||
<td class='name'>
|
||||
<% if (ctx.canEditName) { %>
|
||||
<%= ctx.makeTextInput({value: category.name, required: true}) %>
|
||||
|
@ -32,14 +36,19 @@
|
|||
</a>
|
||||
</td>
|
||||
<% if (ctx.canDelete) { %>
|
||||
<td>
|
||||
<td class='remove'>
|
||||
<% if (category.usages) { %>
|
||||
<a class='inactive remove' title="Can't delete category in use">Remove</a>
|
||||
<a class='inactive' title="Can't delete category in use">Remove</a>
|
||||
<% } else { %>
|
||||
<a href='#' class='remove'>Remove</a>
|
||||
<a href='#'>Remove</a>
|
||||
<% } %>
|
||||
</td>
|
||||
<% } %>
|
||||
<% if (ctx.canSetDefault) { %>
|
||||
<td class='set-default'>
|
||||
<a href='#'>Make default</a>
|
||||
</td>
|
||||
<% } %>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
|
@ -54,8 +63,11 @@
|
|||
<td class='usages'>
|
||||
0
|
||||
</td>
|
||||
<td>
|
||||
<a href='#' class='remove'>Remove</a>
|
||||
<td class='remove'>
|
||||
<a href='#'>Remove</a>
|
||||
</td>
|
||||
<td class='set-default'>
|
||||
<a href='#'>Make default</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
|
|
@ -42,7 +42,11 @@ class TagsController {
|
|||
(ctx, next) => { this._listTagsRoute(ctx, next); });
|
||||
}
|
||||
|
||||
_saveTagCategories(addedCategories, changedCategories, removedCategories) {
|
||||
_saveTagCategories(
|
||||
addedCategories,
|
||||
changedCategories,
|
||||
removedCategories,
|
||||
defaultCategory) {
|
||||
let promises = [];
|
||||
for (let category of addedCategories) {
|
||||
promises.push(api.post('/tag-categories/', category));
|
||||
|
@ -54,14 +58,25 @@ class TagsController {
|
|||
for (let name of removedCategories) {
|
||||
promises.push(api.delete('/tag-category/' + name));
|
||||
}
|
||||
Promise.all(promises).then(
|
||||
() => {
|
||||
events.notify(events.TagsChange);
|
||||
events.notify(events.Success, 'Changes saved.');
|
||||
},
|
||||
response => {
|
||||
events.notify(events.Error, response.description);
|
||||
});
|
||||
Promise.all(promises)
|
||||
.then(
|
||||
() => {
|
||||
if (!defaultCategory) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return api.put(
|
||||
'/tag-category/' + defaultCategory + '/default');
|
||||
}, response => {
|
||||
return Promise.reject(response);
|
||||
})
|
||||
.then(
|
||||
() => {
|
||||
events.notify(events.TagsChange);
|
||||
events.notify(events.Success, 'Changes saved.');
|
||||
},
|
||||
response => {
|
||||
events.notify(events.Error, response.description);
|
||||
});
|
||||
}
|
||||
|
||||
_loadTagRoute(ctx, next) {
|
||||
|
@ -165,6 +180,7 @@ class TagsController {
|
|||
canEditColor: api.hasPrivilege('tagCategories:edit:color'),
|
||||
canDelete: api.hasPrivilege('tagCategories:delete'),
|
||||
canCreate: api.hasPrivilege('tagCategories:create'),
|
||||
canSetDefault: api.hasPrivilege('tagCategories:setDefault'),
|
||||
saveChanges: (...args) => {
|
||||
return this._saveTagCategories(...args);
|
||||
},
|
||||
|
|
|
@ -8,7 +8,41 @@ class TagListHeaderView {
|
|||
this._template = views.getTemplate('tag-categories');
|
||||
}
|
||||
|
||||
_saveButtonClickHandler(e, ctx, target) {
|
||||
render(ctx) {
|
||||
const target = document.getElementById('content-holder');
|
||||
const source = this._template(ctx);
|
||||
|
||||
const form = source.querySelector('form');
|
||||
const newRowTemplate = source.querySelector('.add-template');
|
||||
const tableBody = source.querySelector('tbody');
|
||||
const addLink = source.querySelector('a.add');
|
||||
const saveButton = source.querySelector('button.save');
|
||||
|
||||
newRowTemplate.parentNode.removeChild(newRowTemplate);
|
||||
views.decorateValidator(form);
|
||||
|
||||
for (let row of tableBody.querySelectorAll('tr')) {
|
||||
this._addRowHandlers(row);
|
||||
}
|
||||
|
||||
if (addLink) {
|
||||
addLink.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
let newRow = newRowTemplate.cloneNode(true);
|
||||
tableBody.appendChild(newRow);
|
||||
this._addRowHandlers(row);
|
||||
});
|
||||
}
|
||||
|
||||
form.addEventListener('submit', e => {
|
||||
this._evtSaveButtonClick(e, ctx, target);
|
||||
});
|
||||
|
||||
views.listenToMessages(source);
|
||||
views.showView(target, source);
|
||||
}
|
||||
|
||||
_evtSaveButtonClick(e, ctx, target) {
|
||||
e.preventDefault();
|
||||
|
||||
views.clearMessages(target);
|
||||
|
@ -20,6 +54,7 @@ class TagListHeaderView {
|
|||
existingCategories[category.name] = category;
|
||||
}
|
||||
|
||||
let defaultCategory = null;
|
||||
let addedCategories = [];
|
||||
let removedCategories = [];
|
||||
let changedCategories = [];
|
||||
|
@ -31,6 +66,9 @@ class TagListHeaderView {
|
|||
name: row.querySelector('.name input').value,
|
||||
color: row.querySelector('.color input').value,
|
||||
};
|
||||
if (row.classList.contains('default')) {
|
||||
defaultCategory = category.name;
|
||||
}
|
||||
if (!name) {
|
||||
if (category.name) {
|
||||
addedCategories.push(category);
|
||||
|
@ -50,11 +88,14 @@ class TagListHeaderView {
|
|||
}
|
||||
}
|
||||
ctx.saveChanges(
|
||||
addedCategories, changedCategories, removedCategories);
|
||||
addedCategories,
|
||||
changedCategories,
|
||||
removedCategories,
|
||||
defaultCategory);
|
||||
});
|
||||
}
|
||||
|
||||
_removeButtonClickHandler(e, row, link) {
|
||||
_evtRemoveButtonClick(e, row, link) {
|
||||
e.preventDefault();
|
||||
if (link.classList.contains('inactive')) {
|
||||
return;
|
||||
|
@ -62,47 +103,27 @@ class TagListHeaderView {
|
|||
row.parentNode.removeChild(row);
|
||||
}
|
||||
|
||||
_addRemoveButtonClickHandler(row) {
|
||||
const link = row.querySelector('a.remove');
|
||||
if (!link) {
|
||||
return;
|
||||
_evtSetDefaultButtonClick(e, row) {
|
||||
e.preventDefault();
|
||||
const oldRowNode = row.parentNode.querySelector('tr.default');
|
||||
if (oldRowNode) {
|
||||
oldRowNode.classList.remove('default');
|
||||
}
|
||||
link.addEventListener(
|
||||
'click', e => this._removeButtonClickHandler(e, row, link));
|
||||
row.classList.add('default');
|
||||
}
|
||||
|
||||
render(ctx) {
|
||||
const target = document.getElementById('content-holder');
|
||||
const source = this._template(ctx);
|
||||
|
||||
const form = source.querySelector('form');
|
||||
const newRowTemplate = source.querySelector('.add-template');
|
||||
const tableBody = source.querySelector('tbody');
|
||||
const addLink = source.querySelector('a.add');
|
||||
const saveButton = source.querySelector('button.save');
|
||||
|
||||
newRowTemplate.parentNode.removeChild(newRowTemplate);
|
||||
views.decorateValidator(form);
|
||||
|
||||
for (let row of tableBody.querySelectorAll('tr')) {
|
||||
this._addRemoveButtonClickHandler(row);
|
||||
_addRowHandlers(row) {
|
||||
const removeLink = row.querySelector('.remove a');
|
||||
if (removeLink) {
|
||||
removeLink.addEventListener(
|
||||
'click', e => this._evtRemoveButtonClick(e, row, removeLink));
|
||||
}
|
||||
|
||||
if (addLink) {
|
||||
addLink.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
let newRow = newRowTemplate.cloneNode(true);
|
||||
tableBody.appendChild(newRow);
|
||||
this._addRemoveButtonClickHandler(newRow);
|
||||
});
|
||||
const defaultLink = row.querySelector('.set-default a');
|
||||
if (defaultLink) {
|
||||
defaultLink.addEventListener(
|
||||
'click', e => this._evtSetDefaultButtonClick(e, row));
|
||||
}
|
||||
|
||||
form.addEventListener('submit', e => {
|
||||
this._saveButtonClickHandler(e, ctx, target);
|
||||
});
|
||||
|
||||
views.listenToMessages(source);
|
||||
views.showView(target, source);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue