client/tag_input: When adding new tags, infer category via syntax "category:tag"
This commit is contained in:
parent
8e1e6af232
commit
82ca3fd54f
4 changed files with 62 additions and 12 deletions
|
@ -6,6 +6,7 @@ const uri = require('../util/uri.js');
|
|||
const misc = require('../util/misc.js');
|
||||
const settings = require('../models/settings.js');
|
||||
const Comment = require('../models/comment.js');
|
||||
const Tag = require('../models/tag.js');
|
||||
const Post = require('../models/post.js');
|
||||
const PostList = require('../models/post_list.js');
|
||||
const PostMainView = require('../views/post_main_view.js');
|
||||
|
@ -153,6 +154,25 @@ class PostMainController extends BasePostController {
|
|||
post.save()
|
||||
.then(() => {
|
||||
this._view.sidebarControl.showSuccess('Post saved.');
|
||||
// now save the new tags with categories
|
||||
let tagPromises = [];
|
||||
for (let newTag of e.detail.newTags) {
|
||||
// load the tag that was created during updating the post
|
||||
tagPromises.push(
|
||||
Tag.get(newTag.names[0]).then(tag => {
|
||||
tag.category = newTag.category;
|
||||
return tag.save();
|
||||
}
|
||||
).then(() => {
|
||||
e.detail.newTags.removeByName(newTag.names[0]);
|
||||
}, error => {
|
||||
this._view.sidebarControl.showError(error.message);
|
||||
})
|
||||
);
|
||||
}
|
||||
return Promise.all(tagPromises);
|
||||
})
|
||||
.then(() => {
|
||||
this._view.sidebarControl.enableForm();
|
||||
misc.disableExitConfirmation();
|
||||
}, error => {
|
||||
|
|
|
@ -338,6 +338,8 @@ class PostEditSidebarControl extends events.EventTarget {
|
|||
misc.splitByWhitespace(this._tagInputNode.value) :
|
||||
undefined,
|
||||
|
||||
newTags: this._tagControl.newTags,
|
||||
|
||||
relations: this._relationsInputNode ?
|
||||
misc.splitByWhitespace(this._relationsInputNode.value)
|
||||
.map(x => parseInt(x)) :
|
||||
|
|
|
@ -5,6 +5,7 @@ const tags = require('../tags.js');
|
|||
const misc = require('../util/misc.js');
|
||||
const uri = require('../util/uri.js');
|
||||
const Tag = require('../models/tag.js');
|
||||
const TagList = require('../models/tag_list.js');
|
||||
const settings = require('../models/settings.js');
|
||||
const events = require('../events.js');
|
||||
const views = require('../util/views.js');
|
||||
|
@ -84,6 +85,7 @@ class TagInputControl extends events.EventTarget {
|
|||
constructor(hostNode, tagList) {
|
||||
super();
|
||||
this.tags = tagList;
|
||||
this.newTags = new TagList();
|
||||
this._hostNode = hostNode;
|
||||
this._suggestions = new SuggestionList();
|
||||
this._tagToListItemNode = new Map();
|
||||
|
@ -139,27 +141,44 @@ class TagInputControl extends events.EventTarget {
|
|||
}
|
||||
|
||||
addTagByText(text, source) {
|
||||
// try to find category for new tags in the format "category:name"
|
||||
text = text.replace(/:\s+/, ':');
|
||||
for (let tagName of text.split(/\s+/).filter(word => word).reverse()) {
|
||||
let nameAndCat = tagName.split(':');
|
||||
if (nameAndCat.length > 1) {
|
||||
// "cat:my:tag" should parse to category "cat" and tag "my:tag"
|
||||
let categoryName = nameAndCat.shift();
|
||||
let joinedTagName = nameAndCat.join(':');
|
||||
this.addTagByCategoryAndName(categoryName, joinedTagName, source);
|
||||
} else {
|
||||
this.addTagByName(tagName, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addTagByName(name, source) {
|
||||
// use the default category
|
||||
return this.addTagByCategoryAndName(null, name, source);
|
||||
}
|
||||
|
||||
addTagByCategoryAndName(category, name, source) {
|
||||
category = category ? category.trim() : null;
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
// if tag with this name already exists, existing category will be used
|
||||
return Tag.get(name).then(tag => {
|
||||
return this.addTag(tag, source);
|
||||
}, () => {
|
||||
const tag = new Tag();
|
||||
tag.names = [name];
|
||||
tag.category = null;
|
||||
return this.addTag(tag, source);
|
||||
tag.category = category;
|
||||
return this.addTag(tag, source, true);
|
||||
});
|
||||
}
|
||||
|
||||
addTag(tag, source) {
|
||||
addTag(tag, source, isNew) {
|
||||
if (source != SOURCE_INIT && this.tags.isTaggedWith(tag.names[0])) {
|
||||
const listItemNode = this._getListItemNode(tag);
|
||||
if (source !== SOURCE_IMPLICATION) {
|
||||
|
@ -169,9 +188,14 @@ class TagInputControl extends events.EventTarget {
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.tags.addByName(tag.names[0], false).then(() => {
|
||||
return this.tags.addByTag(tag, false).then(() => {
|
||||
// new tags with categories will be saved separately after the post
|
||||
return isNew && tag.category
|
||||
? this.newTags.add(tag)
|
||||
: Promise.resolve();
|
||||
}).then( () => {
|
||||
const listItemNode = this._createListItemNode(tag);
|
||||
if (!tag.category) {
|
||||
if (isNew === true) {
|
||||
listItemNode.classList.add('new');
|
||||
}
|
||||
if (source === SOURCE_IMPLICATION) {
|
||||
|
@ -197,6 +221,7 @@ class TagInputControl extends events.EventTarget {
|
|||
if (!this.tags.isTaggedWith(tag.names[0])) {
|
||||
return;
|
||||
}
|
||||
this.newTags.removeByName(tag.names[0]);
|
||||
this.tags.removeByName(tag.names[0]);
|
||||
this._hideAutoComplete();
|
||||
|
||||
|
@ -230,7 +255,7 @@ class TagInputControl extends events.EventTarget {
|
|||
|
||||
_evtAddTagButtonClick(e) {
|
||||
e.preventDefault();
|
||||
this.addTagByName(this._tagInputNode.value, SOURCE_USER_INPUT);
|
||||
this.addTagByText(this._tagInputNode.value, SOURCE_USER_INPUT);
|
||||
this._tagInputNode.value = '';
|
||||
}
|
||||
|
||||
|
|
|
@ -35,17 +35,20 @@ class TagList extends AbstractList {
|
|||
}
|
||||
|
||||
addByName(tagName, addImplications) {
|
||||
if (this.isTaggedWith(tagName)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const tag = new Tag();
|
||||
tag.names = [tagName];
|
||||
return this.addByTag(tag, addImplications);
|
||||
}
|
||||
|
||||
addByTag(tag, addImplications) {
|
||||
if (this.isTaggedWith(tag.names[0])) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.add(tag);
|
||||
|
||||
if (addImplications !== false) {
|
||||
return Tag.get(tagName).then(actualTag => {
|
||||
return Tag.get(tag.names[0]).then(actualTag => {
|
||||
return Promise.all(
|
||||
actualTag.implications.map(
|
||||
relation => this.addByName(relation.names[0], true)));
|
||||
|
|
Reference in a new issue