mirror of
https://github.com/codeninjasllc/discourse.git
synced 2025-04-29 23:43:55 -04:00
UX: Move likes into drop down instead of its own status line
This commit is contained in:
parent
5cb8f3bce5
commit
db75774440
20 changed files with 306 additions and 238 deletions
app/assets
config/locales
test/javascripts
|
@ -0,0 +1,63 @@
|
||||||
|
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||||
|
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||||
|
|
||||||
|
export default Ember.Component.extend(StringBuffer, {
|
||||||
|
tagName: 'section',
|
||||||
|
classNameBindings: [':post-actions', 'hidden'],
|
||||||
|
actionsSummary: Em.computed.alias('post.actionsWithoutLikes'),
|
||||||
|
emptySummary: Em.computed.empty('actionsSummary'),
|
||||||
|
hidden: Em.computed.and('emptySummary', 'post.notDeleted'),
|
||||||
|
rerenderTriggers: ['actionsSummary.@each', 'post.deleted'],
|
||||||
|
|
||||||
|
// This was creating way too many bound ifs and subviews in the handlebars version.
|
||||||
|
renderString(buffer) {
|
||||||
|
if (!this.get('emptySummary')) {
|
||||||
|
this.get('actionsSummary').forEach(function(c) {
|
||||||
|
buffer.push("<div class='post-action'>");
|
||||||
|
|
||||||
|
const renderActionIf = function(property, dataAttribute, text) {
|
||||||
|
if (!c.get(property)) { return; }
|
||||||
|
buffer.push(" <span class='action-link " + dataAttribute +"-action'><a href='#' data-" + dataAttribute + "='" + c.get('id') + "'>" + text + "</a>.</span>");
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO multi line expansion for flags
|
||||||
|
buffer.push(c.get('description') + '.');
|
||||||
|
renderActionIf('can_undo', 'undo', I18n.t("post.actions.undo." + c.get('actionType.name_key')));
|
||||||
|
renderActionIf('can_defer_flags', 'defer-flags', I18n.t("post.actions.defer_flags", { count: c.count }));
|
||||||
|
buffer.push("</div>");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const post = this.get('post');
|
||||||
|
if (!post.get('deleted')) {
|
||||||
|
buffer.push("<div class='post-action'>" +
|
||||||
|
iconHTML('fa-trash-o') + ' ' +
|
||||||
|
Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) +
|
||||||
|
Discourse.Formatter.autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
|
||||||
|
"</div>");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
actionTypeById(actionTypeId) {
|
||||||
|
return this.get('actionsSummary').findProperty('id', actionTypeId);
|
||||||
|
},
|
||||||
|
|
||||||
|
click(e) {
|
||||||
|
const $target = $(e.target);
|
||||||
|
let actionTypeId;
|
||||||
|
|
||||||
|
const post = this.get('post');
|
||||||
|
|
||||||
|
if (actionTypeId = $target.data('defer-flags')) {
|
||||||
|
this.actionTypeById(actionTypeId).deferFlags(post);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionTypeId = $target.data('undo')) {
|
||||||
|
this.get('actionsSummary').findProperty('id', actionTypeId).undo(post);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,98 +0,0 @@
|
||||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
|
||||||
|
|
||||||
export default Em.Component.extend(StringBuffer, {
|
|
||||||
tagName: 'section',
|
|
||||||
classNameBindings: [':post-actions', 'hidden'],
|
|
||||||
actionsHistory: Em.computed.alias('post.actionsHistory'),
|
|
||||||
emptyHistory: Em.computed.empty('actionsHistory'),
|
|
||||||
hidden: Em.computed.and('emptyHistory', 'post.notDeleted'),
|
|
||||||
|
|
||||||
rerenderTriggers: ['actionsHistory.@each', 'actionsHistory.users.length', 'post.deleted'],
|
|
||||||
|
|
||||||
// This was creating way too many bound ifs and subviews in the handlebars version.
|
|
||||||
renderString(buffer) {
|
|
||||||
if (!this.get('emptyHistory')) {
|
|
||||||
this.get('actionsHistory').forEach(function(c) {
|
|
||||||
buffer.push("<div class='post-action'>");
|
|
||||||
|
|
||||||
const renderActionIf = function(property, dataAttribute, text) {
|
|
||||||
if (!c.get(property)) { return; }
|
|
||||||
buffer.push(" <span class='action-link " + dataAttribute +"-action'><a href='#' data-" + dataAttribute + "='" + c.get('id') + "'>" + text + "</a>.</span>");
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO multi line expansion for flags
|
|
||||||
let iconsHtml = "";
|
|
||||||
if (c.get('usersExpanded')) {
|
|
||||||
let postUrl;
|
|
||||||
c.get('users').forEach(function(u) {
|
|
||||||
iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + u.get('username_lower') + "\" data-user-card=\"" + u.get('username_lower') + "\">";
|
|
||||||
if (u.post_url) {
|
|
||||||
postUrl = postUrl || u.post_url;
|
|
||||||
}
|
|
||||||
iconsHtml += Discourse.Utilities.avatarImg({
|
|
||||||
size: 'small',
|
|
||||||
avatarTemplate: u.get('avatarTemplate'),
|
|
||||||
title: u.get('username')
|
|
||||||
});
|
|
||||||
iconsHtml += "</a>";
|
|
||||||
});
|
|
||||||
|
|
||||||
let key = 'post.actions.people.' + c.get('actionType.name_key');
|
|
||||||
if (postUrl) { key = key + "_with_url"; }
|
|
||||||
|
|
||||||
// TODO postUrl might be uninitialized? pick a good default
|
|
||||||
buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
|
|
||||||
}
|
|
||||||
renderActionIf('usersCollapsed', 'who-acted', c.get('description'));
|
|
||||||
renderActionIf('canAlsoAction', 'act', I18n.t("post.actions.it_too." + c.get('actionType.name_key')));
|
|
||||||
renderActionIf('can_undo', 'undo', I18n.t("post.actions.undo." + c.get('actionType.name_key')));
|
|
||||||
renderActionIf('can_defer_flags', 'defer-flags', I18n.t("post.actions.defer_flags", { count: c.count }));
|
|
||||||
|
|
||||||
buffer.push("</div>");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const post = this.get('post');
|
|
||||||
if (post.get('deleted')) {
|
|
||||||
buffer.push("<div class='post-action'>" +
|
|
||||||
"<i class='fa fa-trash-o'></i> " +
|
|
||||||
Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) +
|
|
||||||
Discourse.Formatter.autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) +
|
|
||||||
"</div>");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
actionTypeById(actionTypeId) {
|
|
||||||
return this.get('actionsHistory').findProperty('id', actionTypeId);
|
|
||||||
},
|
|
||||||
|
|
||||||
click(e) {
|
|
||||||
const $target = $(e.target);
|
|
||||||
let actionTypeId;
|
|
||||||
|
|
||||||
const post = this.get('post');
|
|
||||||
|
|
||||||
if (actionTypeId = $target.data('defer-flags')) {
|
|
||||||
this.actionTypeById(actionTypeId).deferFlags(post);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// User wants to know who actioned it
|
|
||||||
if (actionTypeId = $target.data('who-acted')) {
|
|
||||||
this.actionTypeById(actionTypeId).loadUsers(post);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionTypeId = $target.data('act')) {
|
|
||||||
this.get('actionsHistory').findProperty('id', actionTypeId).act(post);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionTypeId = $target.data('undo')) {
|
|
||||||
this.get('actionsHistory').findProperty('id', actionTypeId).undo(post);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,7 +1,8 @@
|
||||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||||
|
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||||
|
|
||||||
// Helper class for rendering a button
|
// Helper class for rendering a button
|
||||||
export var Button = function(action, label, icon, opts) {
|
export const Button = function(action, label, icon, opts) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ function animateHeart($elem, start, end, complete) {
|
||||||
.css('textIndent', start)
|
.css('textIndent', start)
|
||||||
.animate({ textIndent: end }, {
|
.animate({ textIndent: end }, {
|
||||||
complete: complete,
|
complete: complete,
|
||||||
step: function(now) {
|
step(now) {
|
||||||
$(this).css('transform','scale('+now+')');
|
$(this).css('transform','scale('+now+')');
|
||||||
},
|
},
|
||||||
duration: 150
|
duration: 150
|
||||||
|
@ -26,9 +27,9 @@ function animateHeart($elem, start, end, complete) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button.prototype.render = function(buffer) {
|
Button.prototype.render = function(buffer) {
|
||||||
var opts = this.opts;
|
const opts = this.opts;
|
||||||
|
|
||||||
var label = I18n.t(this.label);
|
const label = I18n.t(this.label);
|
||||||
|
|
||||||
buffer.push("<button aria-label=\"" + label +"\" " + "title=\"" + label + "\"");
|
buffer.push("<button aria-label=\"" + label +"\" " + "title=\"" + label + "\"");
|
||||||
if (opts.disabled) { buffer.push(" disabled"); }
|
if (opts.disabled) { buffer.push(" disabled"); }
|
||||||
|
@ -36,21 +37,22 @@ Button.prototype.render = function(buffer) {
|
||||||
if (opts.shareUrl) { buffer.push(" data-share-url=\"" + opts.shareUrl + "\""); }
|
if (opts.shareUrl) { buffer.push(" data-share-url=\"" + opts.shareUrl + "\""); }
|
||||||
if (opts.postNumber) { buffer.push(" data-post-number=\"" + opts.postNumber + "\""); }
|
if (opts.postNumber) { buffer.push(" data-post-number=\"" + opts.postNumber + "\""); }
|
||||||
buffer.push(" data-action=\"" + this.action + "\">");
|
buffer.push(" data-action=\"" + this.action + "\">");
|
||||||
if (this.icon) { buffer.push("<i class=\"fa fa-" + this.icon + "\"></i>"); }
|
if (this.icon) { buffer.push(iconHTML(this.icon)); }
|
||||||
if (opts.textLabel) { buffer.push(I18n.t(opts.textLabel)); }
|
if (opts.textLabel) { buffer.push(I18n.t(opts.textLabel)); }
|
||||||
if (opts.innerHTML) { buffer.push(opts.innerHTML); }
|
if (opts.innerHTML) { buffer.push(opts.innerHTML); }
|
||||||
buffer.push("</button>");
|
buffer.push("</button>");
|
||||||
};
|
};
|
||||||
|
|
||||||
var hiddenButtons;
|
let hiddenButtons;
|
||||||
|
|
||||||
var PostMenuView = Discourse.View.extend(StringBuffer, {
|
const PostMenuView = Ember.Component.extend(StringBuffer, {
|
||||||
tagName: 'section',
|
tagName: 'section',
|
||||||
classNames: ['post-menu-area', 'clearfix'],
|
classNames: ['post-menu-area', 'clearfix'],
|
||||||
|
|
||||||
rerenderTriggers: [
|
rerenderTriggers: [
|
||||||
'post.deleted_at',
|
'post.deleted_at',
|
||||||
'post.like_count',
|
'likeAction.count',
|
||||||
|
'likeAction.users.length',
|
||||||
'post.reply_count',
|
'post.reply_count',
|
||||||
'post.showRepliesBelow',
|
'post.showRepliesBelow',
|
||||||
'post.can_delete',
|
'post.can_delete',
|
||||||
|
@ -62,53 +64,71 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
'post.post_type',
|
'post.post_type',
|
||||||
'collapsed'],
|
'collapsed'],
|
||||||
|
|
||||||
|
likeAction: function() {
|
||||||
|
return this.get('post.actionByName.like');
|
||||||
|
}.property('post.actionByName.like'),
|
||||||
|
|
||||||
_collapsedByDefault: function() {
|
_collapsedByDefault: function() {
|
||||||
this.set('collapsed', true);
|
this.set('collapsed', true);
|
||||||
}.on('init'),
|
}.on('init'),
|
||||||
|
|
||||||
renderString: function(buffer) {
|
renderString(buffer) {
|
||||||
var post = this.get('post');
|
const post = this.get('post');
|
||||||
|
|
||||||
buffer.push("<nav class='post-controls'>");
|
buffer.push("<nav class='post-controls'>");
|
||||||
this.renderReplies(post, buffer);
|
this.renderReplies(post, buffer);
|
||||||
|
this.renderLikes(post, buffer);
|
||||||
this.renderButtons(post, buffer);
|
this.renderButtons(post, buffer);
|
||||||
this.renderAdminPopup(post, buffer);
|
this.renderAdminPopup(post, buffer);
|
||||||
buffer.push("</nav>");
|
buffer.push("</nav>");
|
||||||
},
|
},
|
||||||
|
|
||||||
// Delegate click actions
|
// Delegate click actions
|
||||||
click: function(e) {
|
click(e) {
|
||||||
var $target = $(e.target),
|
const $target = $(e.target),
|
||||||
action = $target.data('action') || $target.parent().data('action');
|
action = $target.data('action') || $target.parent().data('action');
|
||||||
|
|
||||||
if (!action) return;
|
if (!action) return;
|
||||||
var handler = this["click" + action.capitalize()];
|
const handler = this["click" + action.capitalize()];
|
||||||
if (!handler) return;
|
if (!handler) return;
|
||||||
|
|
||||||
handler.call(this, this.get('post'));
|
handler.call(this, this.get('post'));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Replies Button
|
// Replies Button
|
||||||
renderReplies: function(post, buffer) {
|
renderReplies(post, buffer) {
|
||||||
if (!post.get('showRepliesBelow')) return;
|
if (!post.get('showRepliesBelow')) return;
|
||||||
|
|
||||||
var reply_count = post.get('reply_count');
|
const replyCount = post.get('reply_count');
|
||||||
buffer.push("<button class='show-replies' data-action='replies'>");
|
buffer.push("<button class='show-replies' data-action='replies'>");
|
||||||
buffer.push("<span class='badge-posts'>" + reply_count + "</span>");
|
buffer.push("<span class='badge-posts'>" + replyCount + "</span>");
|
||||||
buffer.push(I18n.t("post.has_replies", { count: reply_count }));
|
buffer.push(I18n.t("post.has_replies", { count: replyCount }));
|
||||||
|
|
||||||
var icon = (this.get('post.replies.length') > 0) ? 'fa-chevron-up' : 'fa-chevron-down';
|
const icon = (this.get('post.replies.length') > 0) ? 'chevron-up' : 'chevron-down';
|
||||||
return buffer.push("<i class='fa " + icon + "'></i></button>");
|
return buffer.push(iconHTML(icon) + "</button>");
|
||||||
},
|
},
|
||||||
|
|
||||||
renderButtons: function(post, buffer) {
|
renderLikes(post, buffer) {
|
||||||
var self = this,
|
const likeCount = this.get('likeAction.count') || 0;
|
||||||
allButtons = [],
|
if (likeCount === 0) { return; }
|
||||||
visibleButtons = [];
|
|
||||||
|
buffer.push("<button class='show-likes' data-action='likes'>");
|
||||||
|
buffer.push("<span class='badge-posts'>" + likeCount + "</span>");
|
||||||
|
buffer.push(I18n.t("post.has_likes", { count: likeCount }));
|
||||||
|
|
||||||
|
const icon = (this.get('likeAction.users.length') > 0) ? 'chevron-up' : 'chevron-down';
|
||||||
|
return buffer.push(iconHTML(icon) + "</button>");
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
renderButtons(post, buffer) {
|
||||||
|
const self = this;
|
||||||
|
const allButtons = [];
|
||||||
|
let visibleButtons = [];
|
||||||
|
|
||||||
if (typeof hiddenButtons === "undefined") {
|
if (typeof hiddenButtons === "undefined") {
|
||||||
if (!Em.isEmpty(Discourse.SiteSettings.post_menu_hidden_items)) {
|
if (!Em.isEmpty(this.siteSettings.post_menu_hidden_items)) {
|
||||||
hiddenButtons = Discourse.SiteSettings.post_menu_hidden_items.split('|');
|
hiddenButtons = this.siteSettings.post_menu_hidden_items.split('|');
|
||||||
} else {
|
} else {
|
||||||
hiddenButtons = [];
|
hiddenButtons = [];
|
||||||
}
|
}
|
||||||
|
@ -118,11 +138,11 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
hiddenButtons.removeObject("bookmark");
|
hiddenButtons.removeObject("bookmark");
|
||||||
}
|
}
|
||||||
|
|
||||||
var yours = post.get('yours');
|
const yours = post.get('yours');
|
||||||
Discourse.SiteSettings.post_menu.split("|").forEach(function(i) {
|
this.siteSettings.post_menu.split("|").forEach(function(i) {
|
||||||
var creator = self["buttonFor" + i.replace(/\+/, '').capitalize()];
|
const creator = self["buttonFor" + i.replace(/\+/, '').capitalize()];
|
||||||
if (creator) {
|
if (creator) {
|
||||||
var button = creator.call(self, post);
|
const button = creator.call(self, post);
|
||||||
if (button) {
|
if (button) {
|
||||||
allButtons.push(button);
|
allButtons.push(button);
|
||||||
if ((yours && button.opts.alwaysShowYours) ||
|
if ((yours && button.opts.alwaysShowYours) ||
|
||||||
|
@ -136,7 +156,7 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
|
|
||||||
// Only show ellipsis if there is more than one button hidden
|
// Only show ellipsis if there is more than one button hidden
|
||||||
// if there are no more buttons, we are not collapsed
|
// if there are no more buttons, we are not collapsed
|
||||||
var collapsed = this.get('collapsed');
|
const collapsed = this.get('collapsed');
|
||||||
if (!collapsed || (allButtons.length <= visibleButtons.length + 1)) {
|
if (!collapsed || (allButtons.length <= visibleButtons.length + 1)) {
|
||||||
visibleButtons = allButtons;
|
visibleButtons = allButtons;
|
||||||
if (collapsed) { this.set('collapsed', false); }
|
if (collapsed) { this.set('collapsed', false); }
|
||||||
|
@ -144,7 +164,7 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
visibleButtons.splice(visibleButtons.length - 1, 0, this.buttonForShowMoreActions(post));
|
visibleButtons.splice(visibleButtons.length - 1, 0, this.buttonForShowMoreActions(post));
|
||||||
}
|
}
|
||||||
|
|
||||||
var callbacks = PostMenuView._registerButtonCallbacks;
|
const callbacks = PostMenuView._registerButtonCallbacks;
|
||||||
if (callbacks) {
|
if (callbacks) {
|
||||||
_.each(callbacks, function(callback) {
|
_.each(callbacks, function(callback) {
|
||||||
callback.apply(self, [visibleButtons]);
|
callback.apply(self, [visibleButtons]);
|
||||||
|
@ -152,13 +172,23 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.push('<div class="actions">');
|
buffer.push('<div class="actions">');
|
||||||
visibleButtons.forEach(function (b) {
|
visibleButtons.forEach((b) => b.render(buffer));
|
||||||
b.render(buffer);
|
|
||||||
});
|
|
||||||
buffer.push("</div>");
|
buffer.push("</div>");
|
||||||
},
|
},
|
||||||
|
|
||||||
clickReplies: function() {
|
clickLikes() {
|
||||||
|
const likeAction = this.get('post.actionByName.like');
|
||||||
|
if (likeAction) {
|
||||||
|
const users = likeAction.get('users');
|
||||||
|
if (users && users.length) {
|
||||||
|
users.clear();
|
||||||
|
} else {
|
||||||
|
likeAction.loadUsers(this.get('post'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clickReplies() {
|
||||||
if (this.get('post.replies.length') > 0) {
|
if (this.get('post.replies.length') > 0) {
|
||||||
this.set('post.replies', []);
|
this.set('post.replies', []);
|
||||||
} else {
|
} else {
|
||||||
|
@ -167,12 +197,12 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Delete button
|
// Delete button
|
||||||
buttonForDelete: function(post) {
|
buttonForDelete(post) {
|
||||||
var label, icon;
|
let label, icon;
|
||||||
|
|
||||||
if (post.get('post_number') === 1) {
|
if (post.get('post_number') === 1) {
|
||||||
// If it's the first post, the delete/undo actions are related to the topic
|
// If it's the first post, the delete/undo actions are related to the topic
|
||||||
var topic = post.get('topic');
|
const topic = post.get('topic');
|
||||||
if (topic.get('deleted_at')) {
|
if (topic.get('deleted_at')) {
|
||||||
if (!topic.get('details.can_recover')) { return; }
|
if (!topic.get('details.can_recover')) { return; }
|
||||||
label = "topic.actions.recover";
|
label = "topic.actions.recover";
|
||||||
|
@ -195,50 +225,50 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
icon = "trash-o";
|
icon = "trash-o";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var action = (icon === 'trash-o') ? 'delete' : 'recover';
|
const action = (icon === 'trash-o') ? 'delete' : 'recover';
|
||||||
var opts;
|
let opts;
|
||||||
if (icon === "trash-o"){
|
if (icon === "trash-o"){
|
||||||
opts = {className: 'delete'};
|
opts = {className: 'delete'};
|
||||||
}
|
}
|
||||||
return new Button(action, label, icon, opts);
|
return new Button(action, label, icon, opts);
|
||||||
},
|
},
|
||||||
|
|
||||||
clickRecover: function(post) {
|
clickRecover(post) {
|
||||||
this.get('controller').send('recoverPost', post);
|
this.sendAction('recoverPost', post);
|
||||||
},
|
},
|
||||||
|
|
||||||
clickDelete: function(post) {
|
clickDelete(post) {
|
||||||
this.get('controller').send('deletePost', post);
|
this.sendAction('deletePost', post);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Like button
|
// Like button
|
||||||
buttonForLike: function(post) {
|
buttonForLike(post) {
|
||||||
var likeAction = post.get('actionByName.like');
|
const likeAction = this.get('likeAction');
|
||||||
if (!likeAction) { return; }
|
if (!likeAction) { return; }
|
||||||
|
|
||||||
var className = likeAction.get('acted') ? 'has-like' : 'like';
|
const className = likeAction.get('acted') ? 'has-like' : 'like';
|
||||||
if (likeAction.get('canToggle')) {
|
if (likeAction.get('canToggle')) {
|
||||||
var descKey = likeAction.get('acted') ? 'post.controls.undo_like' : 'post.controls.like';
|
const descKey = likeAction.get('acted') ? 'post.controls.undo_like' : 'post.controls.like';
|
||||||
return new Button('like', descKey, 'heart', {className: className});
|
return new Button('like', descKey, 'heart', {className: className});
|
||||||
} else if (likeAction.get('acted')) {
|
} else if (likeAction.get('acted')) {
|
||||||
return new Button('like', 'post.controls.has_liked', 'heart', {className: className, disabled: true});
|
return new Button('like', 'post.controls.has_liked', 'heart', {className: className, disabled: true});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
clickLike: function(post) {
|
clickLike(post) {
|
||||||
var $heart = this.$('.fa-heart'),
|
const $heart = this.$('.fa-heart'),
|
||||||
controller = this.get('controller'),
|
$likeButton = this.$('button[data-action=like]'),
|
||||||
$likeButton = this.$('button[data-action=like]');
|
acted = post.get('actionByName.like.acted'),
|
||||||
|
self = this;
|
||||||
|
|
||||||
var acted = post.get('actionByName.like.acted');
|
|
||||||
if (acted) {
|
if (acted) {
|
||||||
controller.send('toggleLike', post);
|
this.sendAction('toggleLike', post);
|
||||||
$likeButton.removeClass('has-like').addClass('like');
|
$likeButton.removeClass('has-like').addClass('like');
|
||||||
} else {
|
} else {
|
||||||
var scale = [1.0, 1.5];
|
const scale = [1.0, 1.5];
|
||||||
animateHeart($heart, scale[0], scale[1], function() {
|
animateHeart($heart, scale[0], scale[1], function() {
|
||||||
animateHeart($heart, scale[1], scale[0], function() {
|
animateHeart($heart, scale[1], scale[0], function() {
|
||||||
controller.send('toggleLike', post);
|
self.sendAction('toggleLike', post);
|
||||||
$likeButton.removeClass('like').addClass('has-like');
|
$likeButton.removeClass('like').addClass('has-like');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -246,17 +276,17 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Flag button
|
// Flag button
|
||||||
buttonForFlag: function(post) {
|
buttonForFlag(post) {
|
||||||
if (Em.isEmpty(post.get('flagsAvailable'))) return;
|
if (Em.isEmpty(post.get('flagsAvailable'))) return;
|
||||||
return new Button('flag', 'post.controls.flag', 'flag');
|
return new Button('flag', 'post.controls.flag', 'flag');
|
||||||
},
|
},
|
||||||
|
|
||||||
clickFlag: function(post) {
|
clickFlag(post) {
|
||||||
this.get('controller').send('showFlags', post);
|
this.sendAction('showFlags', post);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Edit button
|
// Edit button
|
||||||
buttonForEdit: function(post) {
|
buttonForEdit(post) {
|
||||||
if (!post.get('can_edit')) return;
|
if (!post.get('can_edit')) return;
|
||||||
return new Button('edit', 'post.controls.edit', 'pencil', {
|
return new Button('edit', 'post.controls.edit', 'pencil', {
|
||||||
alwaysShowYours: true,
|
alwaysShowYours: true,
|
||||||
|
@ -264,14 +294,14 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
clickEdit: function(post) {
|
clickEdit(post) {
|
||||||
this.get('controller').send('editPost', post);
|
this.sendAction('editPost', post);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Share button
|
// Share button
|
||||||
buttonForShare: function(post) {
|
buttonForShare(post) {
|
||||||
if (!Discourse.User.current()) return;
|
if (!Discourse.User.current()) return;
|
||||||
var options = {
|
const options = {
|
||||||
shareUrl: post.get('shareUrl'),
|
shareUrl: post.get('shareUrl'),
|
||||||
postNumber: post.get('post_number')
|
postNumber: post.get('post_number')
|
||||||
};
|
};
|
||||||
|
@ -279,9 +309,9 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Reply button
|
// Reply button
|
||||||
buttonForReply: function() {
|
buttonForReply() {
|
||||||
if (!this.get('controller.model.details.can_create_post')) return;
|
if (!this.get('canCreatePost')) return;
|
||||||
var options = {className: 'create'};
|
const options = {className: 'create'};
|
||||||
|
|
||||||
if(!Discourse.Mobile.mobileView) {
|
if(!Discourse.Mobile.mobileView) {
|
||||||
options.textLabel = 'topic.reply.title';
|
options.textLabel = 'topic.reply.title';
|
||||||
|
@ -290,15 +320,15 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
return new Button('reply', 'post.controls.reply', 'reply', options);
|
return new Button('reply', 'post.controls.reply', 'reply', options);
|
||||||
},
|
},
|
||||||
|
|
||||||
clickReply: function(post) {
|
clickReply(post) {
|
||||||
this.get('controller').send('replyToPost', post);
|
this.sendAction('replyToPost', post);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Bookmark button
|
// Bookmark button
|
||||||
buttonForBookmark: function(post) {
|
buttonForBookmark(post) {
|
||||||
if (!Discourse.User.current()) return;
|
if (!Discourse.User.current()) return;
|
||||||
|
|
||||||
var iconClass = 'read-icon',
|
let iconClass = 'read-icon',
|
||||||
buttonClass = 'bookmark',
|
buttonClass = 'bookmark',
|
||||||
tooltip = 'bookmarks.not_bookmarked';
|
tooltip = 'bookmarks.not_bookmarked';
|
||||||
|
|
||||||
|
@ -311,33 +341,30 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
return new Button('bookmark', tooltip, {className: buttonClass, innerHTML: "<div class='" + iconClass + "'>"});
|
return new Button('bookmark', tooltip, {className: buttonClass, innerHTML: "<div class='" + iconClass + "'>"});
|
||||||
},
|
},
|
||||||
|
|
||||||
clickBookmark: function(post) {
|
clickBookmark(post) {
|
||||||
this.get('controller').send('toggleBookmark', post);
|
this.sendAction('toggleBookmark', post);
|
||||||
},
|
},
|
||||||
|
|
||||||
buttonForAdmin: function() {
|
buttonForAdmin() {
|
||||||
if (!Discourse.User.currentProp('canManageTopic')) { return; }
|
if (!Discourse.User.currentProp('canManageTopic')) { return; }
|
||||||
return new Button('admin', 'post.controls.admin', 'wrench');
|
return new Button('admin', 'post.controls.admin', 'wrench');
|
||||||
},
|
},
|
||||||
|
|
||||||
renderAdminPopup: function(post, buffer) {
|
renderAdminPopup(post, buffer) {
|
||||||
if (!Discourse.User.currentProp('canManageTopic')) { return; }
|
if (!Discourse.User.currentProp('canManageTopic')) { return; }
|
||||||
|
|
||||||
var isWiki = post.get('wiki'),
|
const isWiki = post.get('wiki'),
|
||||||
wikiIcon = '<i class="fa fa-pencil-square-o"></i>',
|
wikiIcon = iconHTML('pencil-square-o'),
|
||||||
wikiText = isWiki ? I18n.t('post.controls.unwiki') : I18n.t('post.controls.wiki');
|
wikiText = isWiki ? I18n.t('post.controls.unwiki') : I18n.t('post.controls.wiki'),
|
||||||
|
isModerator = post.get('post_type') === this.site.get('post_types.moderator_action'),
|
||||||
|
postTypeIcon = iconHTML('shield'),
|
||||||
|
postTypeText = isModerator ? I18n.t('post.controls.revert_to_regular') : I18n.t('post.controls.convert_to_moderator'),
|
||||||
|
rebakePostIcon = iconHTML('cog'),
|
||||||
|
rebakePostText = I18n.t('post.controls.rebake'),
|
||||||
|
unhidePostIcon = iconHTML('eye'),
|
||||||
|
unhidePostText = I18n.t('post.controls.unhide');
|
||||||
|
|
||||||
var isModerator = post.get('post_type') === Discourse.Site.currentProp('post_types.moderator_action'),
|
const html = '<div class="post-admin-menu">' +
|
||||||
postTypeIcon = '<i class="fa fa-shield"></i>',
|
|
||||||
postTypeText = isModerator ? I18n.t('post.controls.revert_to_regular') : I18n.t('post.controls.convert_to_moderator');
|
|
||||||
|
|
||||||
var rebakePostIcon = '<i class="fa fa-cog"></i>',
|
|
||||||
rebakePostText = I18n.t('post.controls.rebake');
|
|
||||||
|
|
||||||
var unhidePostIcon = '<i class="fa fa-eye"></i>',
|
|
||||||
unhidePostText = I18n.t('post.controls.unhide');
|
|
||||||
|
|
||||||
var html = '<div class="post-admin-menu">' +
|
|
||||||
'<h3>' + I18n.t('admin_title') + '</h3>' +
|
'<h3>' + I18n.t('admin_title') + '</h3>' +
|
||||||
'<ul>' +
|
'<ul>' +
|
||||||
'<li class="btn btn-admin" data-action="toggleWiki">' + wikiIcon + wikiText + '</li>' +
|
'<li class="btn btn-admin" data-action="toggleWiki">' + wikiIcon + wikiText + '</li>' +
|
||||||
|
@ -350,8 +377,8 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
buffer.push(html);
|
buffer.push(html);
|
||||||
},
|
},
|
||||||
|
|
||||||
clickAdmin: function() {
|
clickAdmin() {
|
||||||
var $postAdminMenu = this.$(".post-admin-menu");
|
const $postAdminMenu = this.$(".post-admin-menu");
|
||||||
$postAdminMenu.show();
|
$postAdminMenu.show();
|
||||||
$("html").on("mouseup.post-admin-menu", function() {
|
$("html").on("mouseup.post-admin-menu", function() {
|
||||||
$postAdminMenu.hide();
|
$postAdminMenu.hide();
|
||||||
|
@ -359,34 +386,34 @@ var PostMenuView = Discourse.View.extend(StringBuffer, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
clickToggleWiki: function() {
|
clickToggleWiki() {
|
||||||
this.get('controller').send('toggleWiki', this.get('post'));
|
this.sendAction('toggleWiki', this.get('post'));
|
||||||
},
|
},
|
||||||
|
|
||||||
clickTogglePostType: function () {
|
clickTogglePostType() {
|
||||||
this.get("controller").send("togglePostType", this.get("post"));
|
this.sendAction("togglePostType", this.get("post"));
|
||||||
},
|
},
|
||||||
|
|
||||||
clickRebakePost: function () {
|
clickRebakePost() {
|
||||||
this.get("controller").send("rebakePost", this.get("post"));
|
this.sendAction("rebakePost", this.get("post"));
|
||||||
},
|
},
|
||||||
|
|
||||||
clickUnhidePost: function () {
|
clickUnhidePost() {
|
||||||
this.get("controller").send("unhidePost", this.get("post"));
|
this.sendAction("unhidePost", this.get("post"));
|
||||||
},
|
},
|
||||||
|
|
||||||
buttonForShowMoreActions: function() {
|
buttonForShowMoreActions() {
|
||||||
return new Button('showMoreActions', 'show_more', 'ellipsis-h');
|
return new Button('showMoreActions', 'show_more', 'ellipsis-h');
|
||||||
},
|
},
|
||||||
|
|
||||||
clickShowMoreActions: function() {
|
clickShowMoreActions() {
|
||||||
this.set('collapsed', false);
|
this.set('collapsed', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
PostMenuView.reopenClass({
|
PostMenuView.reopenClass({
|
||||||
registerButton: function(callback){
|
registerButton(callback){
|
||||||
this._registerButtonCallbacks = this._registerButtonCallbacks || [];
|
this._registerButtonCallbacks = this._registerButtonCallbacks || [];
|
||||||
this._registerButtonCallbacks.push(callback);
|
this._registerButtonCallbacks.push(callback);
|
||||||
}
|
}
|
24
app/assets/javascripts/discourse/components/who-liked.js.es6
Normal file
24
app/assets/javascripts/discourse/components/who-liked.js.es6
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||||
|
|
||||||
|
export default Ember.Component.extend(StringBuffer, {
|
||||||
|
classNames: ['who-liked'],
|
||||||
|
likedUsers: Ember.computed.alias('post.actionByName.like.users'),
|
||||||
|
rerenderTriggers: ['likedUsers.length'],
|
||||||
|
|
||||||
|
renderString(buffer) {
|
||||||
|
const likedUsers = this.get('likedUsers');
|
||||||
|
if (likedUsers) {
|
||||||
|
let iconsHtml = "";
|
||||||
|
likedUsers.forEach(function(u) {
|
||||||
|
iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + u.get('username_lower') + "\" data-user-card=\"" + u.get('username_lower') + "\">";
|
||||||
|
iconsHtml += Discourse.Utilities.avatarImg({
|
||||||
|
size: 'small',
|
||||||
|
avatarTemplate: u.get('avatarTemplate'),
|
||||||
|
title: u.get('username')
|
||||||
|
});
|
||||||
|
iconsHtml += "</a>";
|
||||||
|
});
|
||||||
|
buffer.push(iconsHtml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,4 +1,5 @@
|
||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
|
import { MAX_MESSAGE_LENGTH } from 'discourse/models/post-action-type';
|
||||||
|
|
||||||
// Supports logic for flags in the modal
|
// Supports logic for flags in the modal
|
||||||
export default ObjectController.extend({
|
export default ObjectController.extend({
|
||||||
|
@ -38,7 +39,7 @@ export default ObjectController.extend({
|
||||||
return I18n.t("flagging.custom_message.more", { n: minLen - len });
|
return I18n.t("flagging.custom_message.more", { n: minLen - len });
|
||||||
} else {
|
} else {
|
||||||
return I18n.t("flagging.custom_message.left", {
|
return I18n.t("flagging.custom_message.left", {
|
||||||
n: Discourse.PostActionType.MAX_MESSAGE_LENGTH - len
|
n: MAX_MESSAGE_LENGTH - len
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}.property('message.length')
|
}.property('message.length')
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
|
import { MAX_MESSAGE_LENGTH } from 'discourse/models/post-action-type';
|
||||||
|
|
||||||
export default ObjectController.extend(ModalFunctionality, {
|
export default ObjectController.extend(ModalFunctionality, {
|
||||||
userDetails: null,
|
userDetails: null,
|
||||||
|
@ -42,7 +43,7 @@ export default ObjectController.extend(ModalFunctionality, {
|
||||||
if (selected.get('is_custom_flag')) {
|
if (selected.get('is_custom_flag')) {
|
||||||
const len = this.get('message.length') || 0;
|
const len = this.get('message.length') || 0;
|
||||||
return len >= Discourse.SiteSettings.min_private_message_post_length &&
|
return len >= Discourse.SiteSettings.min_private_message_post_length &&
|
||||||
len <= Discourse.PostActionType.MAX_MESSAGE_LENGTH;
|
len <= MAX_MESSAGE_LENGTH;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}.property('selected.is_custom_flag', 'message.length'),
|
}.property('selected.is_custom_flag', 'message.length'),
|
||||||
|
|
|
@ -24,6 +24,9 @@ export default {
|
||||||
injectAll(app, 'appEvents');
|
injectAll(app, 'appEvents');
|
||||||
Discourse.URL.appEvents = appEvents;
|
Discourse.URL.appEvents = appEvents;
|
||||||
|
|
||||||
|
app.register('store:main', Store);
|
||||||
|
inject(app, 'store', 'route', 'controller');
|
||||||
|
|
||||||
// Inject Discourse.Site to avoid using Discourse.Site.current()
|
// Inject Discourse.Site to avoid using Discourse.Site.current()
|
||||||
const site = Discourse.Site.current();
|
const site = Discourse.Site.current();
|
||||||
app.register('site:main', site, { instantiate: false });
|
app.register('site:main', site, { instantiate: false });
|
||||||
|
@ -37,9 +40,6 @@ export default {
|
||||||
app.register('session:main', Session.current(), { instantiate: false });
|
app.register('session:main', Session.current(), { instantiate: false });
|
||||||
injectAll(app, 'session');
|
injectAll(app, 'session');
|
||||||
|
|
||||||
app.register('store:main', Store);
|
|
||||||
inject(app, 'store', 'route', 'controller');
|
|
||||||
|
|
||||||
app.register('current-user:main', Discourse.User.current(), { instantiate: false });
|
app.register('current-user:main', Discourse.User.current(), { instantiate: false });
|
||||||
inject(app, 'currentUser', 'component', 'route', 'controller');
|
inject(app, 'currentUser', 'component', 'route', 'controller');
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ export default RestModel.extend({
|
||||||
|
|
||||||
// Description for the action
|
// Description for the action
|
||||||
description: function() {
|
description: function() {
|
||||||
var action = this.get('actionType.name_key');
|
const action = this.get('actionType.name_key');
|
||||||
if (this.get('acted')) {
|
if (this.get('acted')) {
|
||||||
if (this.get('count') <= 1) {
|
if (this.get('count') <= 1) {
|
||||||
return I18n.t('post.actions.by_you.' + action);
|
return I18n.t('post.actions.by_you.' + action);
|
||||||
|
@ -17,7 +17,6 @@ export default RestModel.extend({
|
||||||
}
|
}
|
||||||
}.property('count', 'acted', 'actionType'),
|
}.property('count', 'acted', 'actionType'),
|
||||||
|
|
||||||
canAlsoAction: Em.computed.and('can_act', 'actionType.notCustomFlag'),
|
|
||||||
usersCollapsed: Em.computed.not('usersExpanded'),
|
usersCollapsed: Em.computed.not('usersExpanded'),
|
||||||
usersExpanded: Em.computed.gt('users.length', 0),
|
usersExpanded: Em.computed.gt('users.length', 0),
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ export default RestModel.extend({
|
||||||
act: function(post, opts) {
|
act: function(post, opts) {
|
||||||
if (!opts) opts = {};
|
if (!opts) opts = {};
|
||||||
|
|
||||||
var action = this.get('actionType.name_key');
|
const action = this.get('actionType.name_key');
|
||||||
|
|
||||||
// Mark it as acted
|
// Mark it as acted
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
|
@ -72,7 +71,7 @@ export default RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create our post action
|
// Create our post action
|
||||||
var self = this;
|
const self = this;
|
||||||
|
|
||||||
return Discourse.ajax("/post_actions", {
|
return Discourse.ajax("/post_actions", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
|
@ -109,7 +108,7 @@ export default RestModel.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
deferFlags: function(post) {
|
deferFlags: function(post) {
|
||||||
var self = this;
|
const self = this;
|
||||||
return Discourse.ajax("/post_actions/defer_flags", {
|
return Discourse.ajax("/post_actions/defer_flags", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: {
|
data: {
|
||||||
|
@ -122,16 +121,16 @@ export default RestModel.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
loadUsers: function(post) {
|
loadUsers: function(post) {
|
||||||
var self = this;
|
const self = this;
|
||||||
Discourse.ajax("/post_actions/users", {
|
Discourse.ajax("/post_actions/users", {
|
||||||
data: {
|
data: {
|
||||||
id: post.get('id'),
|
id: post.get('id'),
|
||||||
post_action_type_id: this.get('id')
|
post_action_type_id: this.get('id')
|
||||||
}
|
}
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
var users = Em.A();
|
const users = [];
|
||||||
self.set('users', users);
|
self.set('users', users);
|
||||||
_.each(result,function(user) {
|
result.forEach(function(user) {
|
||||||
if (user.id === Discourse.User.currentProp('id')) {
|
if (user.id === Discourse.User.currentProp('id')) {
|
||||||
users.pushObject(Discourse.User.current());
|
users.pushObject(Discourse.User.current());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import RestModel from 'discourse/models/rest';
|
||||||
|
|
||||||
|
const PostActionType = RestModel.extend({
|
||||||
|
notCustomFlag: Em.computed.not('is_custom_flag')
|
||||||
|
});
|
||||||
|
|
||||||
|
export const MAX_MESSAGE_LENGTH = 500;
|
||||||
|
|
||||||
|
export default PostActionType;
|
|
@ -108,11 +108,12 @@ const Post = RestModel.extend({
|
||||||
});
|
});
|
||||||
}.property('actions_summary.@each.can_act'),
|
}.property('actions_summary.@each.can_act'),
|
||||||
|
|
||||||
actionsHistory: function() {
|
actionsWithoutLikes: function() {
|
||||||
if (!this.present('actions_summary')) return null;
|
if (!this.present('actions_summary')) return null;
|
||||||
|
|
||||||
return this.get('actions_summary').filter(function(i) {
|
return this.get('actions_summary').filter(function(i) {
|
||||||
if (i.get('count') === 0) return false;
|
if (i.get('count') === 0) return false;
|
||||||
|
if (i.get('actionType.name_key') === 'like') { return false; }
|
||||||
if (i.get('users') && i.get('users').length > 0) return true;
|
if (i.get('users') && i.get('users').length > 0) return true;
|
||||||
return !i.get('hidden');
|
return !i.get('hidden');
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
/**
|
|
||||||
A data model representing action types (flags, likes) against a Post
|
|
||||||
|
|
||||||
@class PostActionType
|
|
||||||
@extends Discourse.Model
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.PostActionType = Discourse.Model.extend({
|
|
||||||
notCustomFlag: Em.computed.not('is_custom_flag')
|
|
||||||
});
|
|
||||||
|
|
||||||
Discourse.PostActionType.reopenClass({
|
|
||||||
MAX_MESSAGE_LENGTH: 500
|
|
||||||
});
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import PostActionType from 'discourse/models/post-action-type';
|
||||||
|
|
||||||
const Site = Discourse.Model.extend({
|
const Site = Discourse.Model.extend({
|
||||||
|
|
||||||
isReadOnly: Em.computed.alias('is_readonly'),
|
isReadOnly: Em.computed.alias('is_readonly'),
|
||||||
|
@ -102,7 +104,7 @@ Site.reopenClass(Discourse.Singleton, {
|
||||||
if (result.post_action_types) {
|
if (result.post_action_types) {
|
||||||
result.postActionByIdLookup = Em.Object.create();
|
result.postActionByIdLookup = Em.Object.create();
|
||||||
result.post_action_types = _.map(result.post_action_types,function(p) {
|
result.post_action_types = _.map(result.post_action_types,function(p) {
|
||||||
const actionType = Discourse.PostActionType.create(p);
|
const actionType = PostActionType.create(p);
|
||||||
result.postActionByIdLookup.set("action" + p.id, actionType);
|
result.postActionByIdLookup.set("action" + p.id, actionType);
|
||||||
return actionType;
|
return actionType;
|
||||||
});
|
});
|
||||||
|
@ -111,7 +113,7 @@ Site.reopenClass(Discourse.Singleton, {
|
||||||
if (result.topic_flag_types) {
|
if (result.topic_flag_types) {
|
||||||
result.topicFlagByIdLookup = Em.Object.create();
|
result.topicFlagByIdLookup = Em.Object.create();
|
||||||
result.topic_flag_types = _.map(result.topic_flag_types,function(p) {
|
result.topic_flag_types = _.map(result.topic_flag_types,function(p) {
|
||||||
const actionType = Discourse.PostActionType.create(p);
|
const actionType = PostActionType.create(p);
|
||||||
result.topicFlagByIdLookup.set("action" + p.id, actionType);
|
result.topicFlagByIdLookup.set("action" + p.id, actionType);
|
||||||
return actionType;
|
return actionType;
|
||||||
});
|
});
|
||||||
|
|
|
@ -90,7 +90,20 @@
|
||||||
<button {{action "expandFirstPost" this}} class='btn expand-post'>{{i18n 'post.show_full'}}…</button>
|
<button {{action "expandFirstPost" this}} class='btn expand-post'>{{i18n 'post.show_full'}}…</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{view 'post-menu' post=this adminMenu=view.adminMenu}}
|
|
||||||
|
{{post-menu post=this
|
||||||
|
canCreatePost=controller.model.details.can_create_post
|
||||||
|
replyToPost="replyToPost"
|
||||||
|
recoverPost="recoverPost"
|
||||||
|
deletePost="deletePost"
|
||||||
|
toggleLike="toggleLike"
|
||||||
|
showFlags="showFlags"
|
||||||
|
editPost="editPost"
|
||||||
|
toggleBookmark="toggleBookmark"
|
||||||
|
toggleWiki="toggleWiki"
|
||||||
|
togglePostType="togglePostType"
|
||||||
|
rebakePost="rebakePost"
|
||||||
|
unhidePost="unhidePost"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if replies}}
|
{{#if replies}}
|
||||||
|
@ -101,7 +114,8 @@
|
||||||
</section>
|
</section>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{discourse-action-history post=this}}
|
{{actions-summary post=this}}
|
||||||
|
{{who-liked post=this}}
|
||||||
{{view 'topic-map-container' post=this topic=controller.model}}
|
{{view 'topic-map-container' post=this topic=controller.model}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
//= require_tree ./discourse/adapters
|
//= require_tree ./discourse/adapters
|
||||||
//= require ./discourse/models/rest
|
//= require ./discourse/models/rest
|
||||||
//= require ./discourse/models/model
|
//= require ./discourse/models/model
|
||||||
|
//= require ./discourse/models/post-action-type
|
||||||
//= require ./discourse/models/post
|
//= require ./discourse/models/post
|
||||||
//= require ./discourse/models/post-stream
|
//= require ./discourse/models/post-stream
|
||||||
//= require ./discourse/models/topic-details
|
//= require ./discourse/models/topic-details
|
||||||
|
|
|
@ -233,3 +233,11 @@ blockquote > *:last-child {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.who-liked {
|
||||||
|
a {
|
||||||
|
margin: 0 0.25em 0.5em 0;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ nav.post-controls {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.show-replies {
|
.show-replies, .show-likes {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
span.badge-posts {color: scale-color($primary, $lightness: 60%);}
|
span.badge-posts {color: scale-color($primary, $lightness: 60%);}
|
||||||
|
|
|
@ -27,6 +27,21 @@ span.badge-posts {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-likes {
|
||||||
|
margin-left: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
font-size: inherit;
|
||||||
|
span.badge-posts {color: scale-color($primary, $lightness: 60%);}
|
||||||
|
&:hover {
|
||||||
|
background: dark-light-diff($primary, $secondary, 90%, -65%);
|
||||||
|
span.badge-posts {color: $primary;}
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nav.post-controls {
|
nav.post-controls {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1233,6 +1233,9 @@ en:
|
||||||
has_replies:
|
has_replies:
|
||||||
one: "Reply"
|
one: "Reply"
|
||||||
other: "Replies"
|
other: "Replies"
|
||||||
|
has_likes:
|
||||||
|
one: "Like"
|
||||||
|
other: "Likes"
|
||||||
|
|
||||||
errors:
|
errors:
|
||||||
create: "Sorry, there was an error creating your post. Please try again."
|
create: "Sorry, there was an error creating your post. Please try again."
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import createStore from 'helpers/create-store';
|
||||||
|
|
||||||
var buildPost = function(args) {
|
var buildPost = function(args) {
|
||||||
return Discourse.Post.create(_.merge({
|
return Discourse.Post.create(_.merge({
|
||||||
id: 1,
|
id: 1,
|
||||||
|
@ -18,14 +20,21 @@ moduleFor("controller:flag", "controller:flag", {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("canDeleteSpammer not staff", function(){
|
test("canDeleteSpammer not staff", function(){
|
||||||
|
const store = createStore();
|
||||||
|
|
||||||
var flagController = this.subject({ model: buildPost() });
|
var flagController = this.subject({ model: buildPost() });
|
||||||
sandbox.stub(Discourse.User, 'currentProp').withArgs('staff').returns(false);
|
sandbox.stub(Discourse.User, 'currentProp').withArgs('staff').returns(false);
|
||||||
flagController.set('selected', Discourse.PostActionType.create({name_key: 'spam'}));
|
|
||||||
|
const spamFlag = store.createRecord('post-action-type', {name_key: 'spam'});
|
||||||
|
flagController.set('selected', spamFlag);
|
||||||
equal(flagController.get('canDeleteSpammer'), false, 'false if current user is not staff');
|
equal(flagController.get('canDeleteSpammer'), false, 'false if current user is not staff');
|
||||||
});
|
});
|
||||||
|
|
||||||
var canDeleteSpammer = function(flagController, postActionType, expected, testName) {
|
var canDeleteSpammer = function(flagController, postActionType, expected, testName) {
|
||||||
flagController.set('selected', Discourse.PostActionType.create({name_key: postActionType}));
|
const store = createStore();
|
||||||
|
const flag = store.createRecord('post-action-type', {name_key: postActionType});
|
||||||
|
flagController.set('selected', flag);
|
||||||
|
|
||||||
equal(flagController.get('canDeleteSpammer'), expected, testName);
|
equal(flagController.get('canDeleteSpammer'), expected, testName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -81,15 +81,19 @@ var origDebounce = Ember.run.debounce,
|
||||||
flushMap = require('discourse/models/store', null, null, false).flushMap,
|
flushMap = require('discourse/models/store', null, null, false).flushMap,
|
||||||
server;
|
server;
|
||||||
|
|
||||||
|
function dup(obj) {
|
||||||
|
return jQuery.extend(true, {}, obj);
|
||||||
|
}
|
||||||
|
|
||||||
QUnit.testStart(function(ctx) {
|
QUnit.testStart(function(ctx) {
|
||||||
server = createPretendServer();
|
server = createPretendServer();
|
||||||
|
|
||||||
// Allow our tests to change site settings and have them reset before the next test
|
// Allow our tests to change site settings and have them reset before the next test
|
||||||
Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal);
|
Discourse.SiteSettings = dup(Discourse.SiteSettingsOriginal);
|
||||||
Discourse.BaseUri = "/";
|
Discourse.BaseUri = "/";
|
||||||
Discourse.BaseUrl = "localhost";
|
Discourse.BaseUrl = "localhost";
|
||||||
Discourse.User.resetCurrent();
|
Discourse.User.resetCurrent();
|
||||||
Discourse.Site.resetCurrent(Discourse.Site.create(fixtures['site.json'].site));
|
Discourse.Site.resetCurrent(Discourse.Site.create(dup(fixtures['site.json'].site)));
|
||||||
|
|
||||||
Discourse.URL.redirectedTo = null;
|
Discourse.URL.redirectedTo = null;
|
||||||
Discourse.URL.redirectTo = function(url) {
|
Discourse.URL.redirectTo = function(url) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue