Initial commit as a clone of discourse-tagging

This commit is contained in:
Kane York
2015-06-25 09:25:15 -07:00
commit 174e6d6ecc
33 changed files with 856 additions and 0 deletions
@@ -0,0 +1,3 @@
{{#if canEditTags}}
{{tag-chooser tags=model.tags tabIndex="4"}}
{{/if}}
@@ -0,0 +1,3 @@
{{#if canEditTags}}
{{tag-chooser tags=buffered.tags}}
{{/if}}
@@ -0,0 +1,13 @@
{{#if tags_changes}}
<div class='row'>
{{i18n "tagging.changed"}}
{{#each t in previousTagChanges}}
{{discourse-tag tagId=t}}
{{/each}}
&rarr;
&nbsp;
{{#each t in currentTagChanges}}
{{discourse-tag tagId=t}}
{{/each}}
</div>
{{/if}}
@@ -0,0 +1,3 @@
<li>
{{#link-to 'tags'}}{{i18n "tagging.tags"}}{{/link-to}}
</li>
@@ -0,0 +1,3 @@
{{#each t in topic.tags}}
{{discourse-tag tagId=t}}
{{/each}}
@@ -0,0 +1,7 @@
import RESTAdapter from 'discourse/adapters/rest';
export default RESTAdapter.extend({
pathFor(type, id) {
return "/tags/" + id + "/notifications";
}
});
@@ -0,0 +1,33 @@
export default Ember.Component.extend({
tagName: 'a',
classNameBindings: [':discourse-tag'],
attributeBindings: ['href', 'style'],
href: function() {
return "/tags/" + this.get('tagId');
}.property('tagId'),
style: function() {
const count = parseFloat(this.get('count')),
minCount = parseFloat(this.get('minCount')),
maxCount = parseFloat(this.get('maxCount'));
if (count && maxCount && minCount) {
let ratio = (count - minCount) / maxCount;
if (ratio) {
ratio = ratio + 1.0;
return "font-size: " + ratio + "em";
}
}
}.property('count', 'scaleTo'),
render(buffer) {
buffer.push(Handlebars.Utils.escapeExpression(this.get('tagId')));
},
click(e) {
e.preventDefault();
Discourse.URL.routeTo(this.get('href'));
return true;
}
});
@@ -0,0 +1,88 @@
function formatTag(t) {
const ret = "<a href class='discourse-tag'>" + Handlebars.Utils.escapeExpression(t.id) + "</a>";
return (t.count) ? ret + " <span class='discourse-tag-count'>x" + t.count + "</span>" : ret;
}
export default Ember.TextField.extend({
classNameBindings: [':tag-chooser'],
attributeBindings: ['tabIndex'],
_setupTags: function() {
const tags = this.get('tags') || [];
this.set('value', tags.join(", "));
}.on('init'),
_valueChanged: function() {
const tags = this.get('value').split(',').map(v => v.trim()).reject(v => v.length === 0).uniq();
this.set('tags', tags);
}.observes('value'),
_initializeTags: function() {
const site = this.site,
filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
this.$().select2({
tags: true,
placeholder: I18n.t('tagging.choose_for_topic'),
maximumInputLength: this.siteSettings.max_tag_length,
maximumSelectionSize: this.siteSettings.max_tags_per_topic,
initSelection(element, callback) {
const data = [];
function splitVal(string, separator) {
var val, i, l;
if (string === null || string.length < 1) return [];
val = string.split(separator);
for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
return val;
}
$(splitVal(element.val(), ",")).each(function () {
data.push({
id: this,
text: this
});
});
callback(data);
},
createSearchChoice: function(term, data) {
term = term.replace(filterRegexp, '').trim();
// No empty terms, make sure the user has permission to create the tag
if (!term.length || !site.get('can_create_tag')) { return; }
if ($(data).filter(function() {
return this.text.localeCompare(term) === 0;
}).length === 0) {
return { id: term, text: term };
}
},
createSearchChoicePosition: function(list, item) {
// Search term goes on the bottom
list.push(item);
},
formatSelectionCssClass: function () { return "discourse-tag"; },
formatResult: formatTag,
// formatSelection: formatTag,
multiple: true,
ajax: {
quietMillis: 200,
cache: true,
url: "/tags/filter/search",
dataType: 'json',
data: function (term) {
return { q: term };
},
results: function (data) {
return data;
}
},
});
}.on('didInsertElement'),
_destroyTags: function() {
this.$().select2('destroy');
}.on('willDestroyElement')
});
@@ -0,0 +1,11 @@
import NotificationsButton from 'discourse/components/notifications-button';
export default NotificationsButton.extend({
classNames: ['notification-options', 'tag-notification-menu'],
buttonIncludesText: false,
i18nPrefix: 'tagging.notifications',
clicked(id) {
this.sendAction('action', id);
}
});
@@ -0,0 +1,15 @@
export default Ember.Controller.extend({
tag: null,
list: null,
loadMoreTopics() {
return this.get('list').loadMore();
},
actions: {
changeTagNotification(id) {
const tagNotification = this.get('tagNotification');
tagNotification.update({ notification_level: id });
}
}
});
@@ -0,0 +1,44 @@
import ComposerController from 'discourse/controllers/composer';
import HistoryController from 'discourse/controllers/history';
import TopicController from 'discourse/controllers/topic';
import { needsSecondRowIf } from 'discourse/components/header-extra-info';
// Work around a quirk of custom fields -- an array of one element
// is returned as just that element. We should fix this properly
// in custom fields and remove this.
function customTagArray(fieldName) {
return function() {
var val = this.get(fieldName);
if (!val) { return val; }
if (!Array.isArray(val)) { val = [val]; }
return val;
}.property(fieldName);
}
export default {
name: 'extend-for-tagging',
initialize() {
Discourse.Composer.serializeOnCreate('tags');
Discourse.Composer.serializeToTopic('tags', 'topic.tags');
TopicController.reopen({
canEditTags: Ember.computed.not('isPrivateMessage')
});
HistoryController.reopen({
previousTagChanges: customTagArray('tags_changes.previous'),
currentTagChanges: customTagArray('tags_changes.current')
});
ComposerController.reopen({
canEditTags: function() {
return !this.site.mobileView &&
this.get('model.canEditTitle') &&
!this.get('model.creatingPrivateMessage');
}.property('model.canEditTitle', 'model.creatingPrivateMessage')
});
// Show a second row in the header if there are any tags on the topic
needsSecondRowIf('topic.tags.length', tagsLength => parseInt(tagsLength) > 0);
}
};
@@ -0,0 +1,5 @@
export default Discourse.Route.extend({
model() {
return Discourse.ajax("/tags/filter/cloud.json");
}
});
@@ -0,0 +1,32 @@
export default Discourse.Route.extend({
model(tag) {
tag.tag_id = Handlebars.Utils.escapeExpression(tag.tag_id);
if (this.get('currentUser')) {
// If logged in, we should get the tag's user settings
const self = this;
return this.store.find('tagNotification', tag.tag_id).then(function(tn) {
self.set('tagNotification', tn);
return tag;
});
}
return tag;
},
afterModel(tag) {
const self = this;
return Discourse.TopicList.list('tags/' + tag.tag_id).then(function(list) {
self.set('list', list);
});
},
setupController(controller, model) {
controller.setProperties({
tag: model,
list: this.get('list'),
tagNotification: this.get('tagNotification')
});
}
});
@@ -0,0 +1,5 @@
export default function() {
this.resource('tags', function() {
this.route('show', {path: ':tag_id'});
});
}
@@ -0,0 +1,9 @@
<div class="container list-container">
<div class="row">
<div class="full-width">
<div id='list-area'>
{{outlet}}
</div>
</div>
</div>
</div>
@@ -0,0 +1,10 @@
<h2>{{i18n "tagging.all_tags"}}</h2>
<div class='tag-cloud'>
{{#each tag in cloud}}
{{discourse-tag tagId=tag.id
count=tag.count
maxCount=model.max_count
minCount=model.min_count}}
{{/each}}
</div>
@@ -0,0 +1,9 @@
{{#if tagNotification}}
{{tag-notifications-button tag=tag.tag_id
action="changeTagNotification"
notificationLevel=tagNotification.notification_level}}
{{/if}}
<h2>{{{i18n "tagging.topics_tagged" tag=tag.tag_id}}}</h2>
{{topic-list topics=list.topics}}
@@ -0,0 +1,3 @@
import DiscoveryTopicsView from "discourse/views/discovery-topics";
export default DiscoveryTopicsView;