mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 19:46:01 +01:00
closes #4795
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/*global define, socket, app, utils, bootbox*/
|
/*global define, socket, app, utils, bootbox, ajaxify*/
|
||||||
|
|
||||||
define('admin/manage/tags', [
|
define('admin/manage/tags', [
|
||||||
'forum/infinitescroll',
|
'forum/infinitescroll',
|
||||||
@@ -12,11 +12,47 @@ define('admin/manage/tags', [
|
|||||||
Tags.init = function() {
|
Tags.init = function() {
|
||||||
selectable.enable('.tag-management', '.tag-row');
|
selectable.enable('.tag-management', '.tag-row');
|
||||||
|
|
||||||
|
handleCreate();
|
||||||
handleSearch();
|
handleSearch();
|
||||||
handleModify();
|
handleModify();
|
||||||
handleDeleteSelected();
|
handleDeleteSelected();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function handleCreate() {
|
||||||
|
var createModal = $('#create-modal');
|
||||||
|
var createTagName = $('#create-tag-name');
|
||||||
|
var createModalGo = $('#create-modal-go');
|
||||||
|
|
||||||
|
createModal.on('keypress', function(e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
createModalGo.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#create').on('click', function() {
|
||||||
|
createModal.modal('show');
|
||||||
|
setTimeout(function() {
|
||||||
|
createTagName.focus();
|
||||||
|
}, 250);
|
||||||
|
});
|
||||||
|
|
||||||
|
createModalGo.on('click', function() {
|
||||||
|
socket.emit('admin.tags.create', {
|
||||||
|
tag: createTagName.val()
|
||||||
|
}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
createTagName.val('');
|
||||||
|
createModal.on('hidden.bs.modal', function() {
|
||||||
|
ajaxify.refresh();
|
||||||
|
});
|
||||||
|
createModal.modal('hide');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function handleSearch() {
|
function handleSearch() {
|
||||||
$('#tag-search').on('input propertychange', function() {
|
$('#tag-search').on('input propertychange', function() {
|
||||||
if (timeoutId) {
|
if (timeoutId) {
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ tagsController.getTag = function(req, res, next) {
|
|||||||
},
|
},
|
||||||
function (results, next) {
|
function (results, next) {
|
||||||
if (Array.isArray(results.tids) && !results.tids.length) {
|
if (Array.isArray(results.tids) && !results.tids.length) {
|
||||||
topics.deleteTag(req.params.tag);
|
|
||||||
return res.render('tag', templateData);
|
return res.render('tag', templateData);
|
||||||
}
|
}
|
||||||
topicCount = results.topicCount;
|
topicCount = results.topicCount;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
var utils = require('../../../public/src/utils');
|
||||||
|
|
||||||
module.exports = function(db, module) {
|
module.exports = function(db, module) {
|
||||||
var helpers = module.helpers.mongo;
|
var helpers = module.helpers.mongo;
|
||||||
@@ -381,12 +382,12 @@ module.exports = function(db, module) {
|
|||||||
map[item.value] = item.score;
|
map[item.value] = item.score;
|
||||||
});
|
});
|
||||||
|
|
||||||
var returnData = new Array(values.length),
|
var returnData = new Array(values.length);
|
||||||
score;
|
var score;
|
||||||
|
|
||||||
for(var i=0; i<values.length; ++i) {
|
for(var i=0; i<values.length; ++i) {
|
||||||
score = map[values[i]];
|
score = map[values[i]];
|
||||||
returnData[i] = score ? score : null;
|
returnData[i] = utils.isNumber(score) ? score : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, returnData);
|
callback(null, returnData);
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var topics = require('../../topics'),
|
var topics = require('../../topics');
|
||||||
Tags = {};
|
var Tags = {};
|
||||||
|
|
||||||
|
Tags.create = function(socket, data, callback) {
|
||||||
|
if (!data) {
|
||||||
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
topics.createEmptyTag(data.tag, callback);
|
||||||
|
};
|
||||||
|
|
||||||
Tags.update = function(socket, data, callback) {
|
Tags.update = function(socket, data, callback) {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|||||||
@@ -48,6 +48,29 @@ module.exports = function(Topics) {
|
|||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Topics.createEmptyTag = function(tag, callback) {
|
||||||
|
if (!tag) {
|
||||||
|
return callback(new Error('[[error:invalid-tag]]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = utils.cleanUpTag(tag, meta.config.maximumTagLength);
|
||||||
|
if (tag.length < (meta.config.minimumTagLength || 3)) {
|
||||||
|
return callback(new Error('[[error:tag-too-short]]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function(next) {
|
||||||
|
db.isSortedSetMember('tags:topic:count', tag, next);
|
||||||
|
},
|
||||||
|
function(isMember, next) {
|
||||||
|
if (isMember) {
|
||||||
|
return callback(new Error('[[error:tag-exists]]'));
|
||||||
|
}
|
||||||
|
db.sortedSetAdd('tags:topic:count', 0, tag, next);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
};
|
||||||
|
|
||||||
Topics.updateTag = function(tag, data, callback) {
|
Topics.updateTag = function(tag, data, callback) {
|
||||||
db.setObject('tag:' + tag, data, callback);
|
db.setObject('tag:' + tag, data, callback);
|
||||||
};
|
};
|
||||||
@@ -233,7 +256,7 @@ module.exports = function(Topics) {
|
|||||||
updateTagCount(tag, next);
|
updateTagCount(tag, next);
|
||||||
}, next);
|
}, next);
|
||||||
}
|
}
|
||||||
], function(err, results) {
|
], function(err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -317,7 +340,7 @@ module.exports = function(Topics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var maximumTopics = parseInt(meta.config.maximumRelatedTopics, 10) || 0;
|
var maximumTopics = parseInt(meta.config.maximumRelatedTopics, 10) || 0;
|
||||||
if (maximumTopics === 0 || !topicData.tags.length) {
|
if (maximumTopics === 0 || !topicData.tags || !topicData.tags.length) {
|
||||||
return callback(null, []);
|
return callback(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<!-- IF !tags.length -->
|
<!-- IF !tags.length -->
|
||||||
Your forum does not have any topics with tags yet.
|
Your forum does not have any topics with tags yet.
|
||||||
<!-- ENDIF !tags.length -->
|
<!-- ENDIF !tags.length -->
|
||||||
|
|
||||||
<div class="tag-list">
|
<div class="tag-list">
|
||||||
<!-- BEGIN tags -->
|
<!-- BEGIN tags -->
|
||||||
<div class="tag-row" data-tag="{tags.value}">
|
<div class="tag-row" data-tag="{tags.value}">
|
||||||
@@ -32,9 +32,10 @@
|
|||||||
|
|
||||||
<div class="col-lg-3 acp-sidebar">
|
<div class="col-lg-3 acp-sidebar">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Modify Tag</div>
|
<div class="panel-heading">Create & Modify Tags</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>Select tags via clicking and/or dragging, use shift to select multiple.</p>
|
<p>Select tags via clicking and/or dragging, use shift to select multiple.</p>
|
||||||
|
<button class="btn btn-primary btn-block" id="create">Create Tag</button>
|
||||||
<button class="btn btn-primary btn-block" id="modify">Modify Tags</button>
|
<button class="btn btn-primary btn-block" id="modify">Modify Tags</button>
|
||||||
<button class="btn btn-warning btn-block" id="deleteSelected">Delete Tags</button>
|
<button class="btn btn-warning btn-block" id="deleteSelected">Delete Tags</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,4 +49,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="create-modal">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title">Create Tag</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="create-tag-name">Tag Name</label>
|
||||||
|
<input type="text" class="form-control" id="create-tag-name" placeholder="Tag Name" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" id="create-modal-go">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -336,6 +336,18 @@ describe('Sorted Set methods', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('sortedSetScores()', function() {
|
describe('sortedSetScores()', function() {
|
||||||
|
before(function(done) {
|
||||||
|
db.sortedSetAdd('zeroScore', 0, 'value1', done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return 0 if score is 0', function(done) {
|
||||||
|
db.sortedSetScores('zeroScore', ['value1'], function(err, scores) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.equal(0, scores[0]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should return the scores of value in sorted sets', function(done) {
|
it('should return the scores of value in sorted sets', function(done) {
|
||||||
db.sortedSetScores('sortedSetTest1', ['value2', 'value1', 'doesnotexist'], function(err, scores) {
|
db.sortedSetScores('sortedSetTest1', ['value2', 'value1', 'doesnotexist'], function(err, scores) {
|
||||||
assert.equal(err, null);
|
assert.equal(err, null);
|
||||||
|
|||||||
Reference in New Issue
Block a user