New Feature: Staff can choose to "Take Action" when flagging to immediately reach hiding
thresholds.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
Supports logic for flags in the modal
|
||||
|
||||
@class FlagActionTypeController
|
||||
@extends Discourse.ObjectController
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.FlagActionTypeController = Discourse.ObjectController.extend({
|
||||
needs: ['flag'],
|
||||
|
||||
message: Em.computed.alias('controllers.flag.message'),
|
||||
|
||||
customPlaceholder: function(){
|
||||
return Em.String.i18n("flagging.custom_placeholder_" + this.get('name_key'));
|
||||
}.property('name_key'),
|
||||
|
||||
formattedName: function(){
|
||||
return this.get('name').replace("{{username}}", this.get('controllers.flag.username'));
|
||||
}.property('name'),
|
||||
|
||||
selected: function() {
|
||||
return this.get('model') === this.get('controllers.flag.selected');
|
||||
}.property('controllers.flag.selected'),
|
||||
|
||||
showMessageInput: Em.computed.and('is_custom_flag', 'selected'),
|
||||
showDescription: Em.computed.not('showMessageInput'),
|
||||
|
||||
customMessageLengthClasses: function() {
|
||||
return (this.get('message.length') < Discourse.PostActionType.MIN_MESSAGE_LENGTH) ? "too-short" : "ok"
|
||||
}.property('message.length'),
|
||||
|
||||
customMessageLength: function() {
|
||||
var len = this.get('message.length') || 0;
|
||||
var minLen = Discourse.PostActionType.MIN_MESSAGE_LENGTH;
|
||||
if (len === 0) {
|
||||
return Em.String.i18n("flagging.custom_message.at_least", { n: minLen });
|
||||
} else if (len < minLen) {
|
||||
return Em.String.i18n("flagging.custom_message.more", { n: minLen - len });
|
||||
} else {
|
||||
return Em.String.i18n("flagging.custom_message.left", {
|
||||
n: Discourse.PostActionType.MAX_MESSAGE_LENGTH - len
|
||||
});
|
||||
}
|
||||
}.property('message.length')
|
||||
|
||||
});
|
||||
|
||||
@@ -9,70 +9,58 @@
|
||||
**/
|
||||
Discourse.FlagController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
// trick to bind user / post to flag
|
||||
boundFlags: function() {
|
||||
var _this = this;
|
||||
var original = this.get('flagsAvailable');
|
||||
if(original){
|
||||
return $.map(original, function(v){
|
||||
var b = Discourse.BoundPostActionType.create(v);
|
||||
b.set('post', _this.get('model'));
|
||||
return b;
|
||||
});
|
||||
}
|
||||
}.property('flagsAvailable.@each'),
|
||||
|
||||
changePostActionType: function(action) {
|
||||
if (this.get('postActionTypeId') === action.id) return false;
|
||||
|
||||
this.get('boundFlags').setEach('selected', false);
|
||||
action.set('selected', true);
|
||||
|
||||
this.set('postActionTypeId', action.id);
|
||||
this.set('isCustomFlag', action.is_custom_flag);
|
||||
this.set('selected', action);
|
||||
return false;
|
||||
},
|
||||
|
||||
showSubmit: function() {
|
||||
if (this.get('postActionTypeId')) {
|
||||
if (this.get('isCustomFlag')) {
|
||||
var m = this.get('selected.message');
|
||||
return m && m.length >= 10 && m.length <= 500;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
submitEnabled: function() {
|
||||
var selected = this.get('selected');
|
||||
if (!selected) return false;
|
||||
|
||||
if (selected.get('is_custom_flag')) {
|
||||
var len = this.get('message.length') || 0;
|
||||
return len >= Discourse.PostActionType.MIN_MESSAGE_LENGTH &&
|
||||
len <= Discourse.PostActionType.MAX_MESSAGE_LENGTH;
|
||||
}
|
||||
return false;
|
||||
}.property('isCustomFlag', 'selected.customMessageLength', 'postActionTypeId'),
|
||||
return true;
|
||||
}.property('selected.is_custom_flag', 'message.length'),
|
||||
|
||||
submitDisabled: Em.computed.not('submitEnabled'),
|
||||
|
||||
// Staff accounts can "take action"
|
||||
canTakeAction: function() {
|
||||
// We can only take actions on non-custom flags
|
||||
if (this.get('selected.is_custom_flag')) return false;
|
||||
return Discourse.User.current('staff');
|
||||
}.property('selected.is_custom_flag'),
|
||||
|
||||
submitText: function(){
|
||||
var action = this.get('selected');
|
||||
if (this.get('selected.is_custom_flag')) {
|
||||
return Em.String.i18n("flagging.notify_action");
|
||||
} else {
|
||||
return Em.String.i18n("flagging.action");
|
||||
}
|
||||
}.property('selected'),
|
||||
}.property('selected.is_custom_flag'),
|
||||
|
||||
createFlag: function() {
|
||||
var _this = this;
|
||||
takeAction: function() {
|
||||
this.createFlag({takeAction: true})
|
||||
this.set('hidden', true);
|
||||
},
|
||||
|
||||
var action = this.get('selected');
|
||||
var postAction = this.get('actionByName.' + (action.get('name_key')));
|
||||
createFlag: function(opts) {
|
||||
var flagController = this;
|
||||
var postAction = this.get('actionByName.' + this.get('selected.name_key'));
|
||||
var params = this.get('selected.is_custom_flag') ? {message: this.get('message')} : {}
|
||||
|
||||
var actionType = Discourse.Site.instance().postActionTypeById(this.get('postActionTypeId'));
|
||||
if (postAction) {
|
||||
postAction.act({
|
||||
message: action.get('message')
|
||||
}).then(function() {
|
||||
return $('#discourse-modal').modal('hide');
|
||||
}, function(errors) {
|
||||
return _this.displayErrors(errors);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
if (opts) params = $.extend(params, opts);
|
||||
|
||||
postAction.act(params).then(function() {
|
||||
flagController.closeModal();
|
||||
}, function(errors) {
|
||||
flagController.displayErrors(errors);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
**/
|
||||
Discourse.ModalController = Discourse.Controller.extend({
|
||||
|
||||
/**
|
||||
Close the modal.
|
||||
|
||||
@method closeModal
|
||||
**/
|
||||
closeModal: function() {
|
||||
// Currently uses jQuery to hide it.
|
||||
$('#discourse-modal').modal('hide');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,16 @@ Discourse.ModalFunctionality = Em.Mixin.create({
|
||||
message: message,
|
||||
messageClass: messageClass
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
Close the modal.
|
||||
|
||||
@method closeModal
|
||||
**/
|
||||
closeModal: function() {
|
||||
// Currently uses jQuery to hide it.
|
||||
this.get('controllers.modal').closeModal();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -37,6 +37,8 @@ Discourse.ActionSummary = Discourse.Model.extend({
|
||||
|
||||
// Perform this action
|
||||
act: function(opts) {
|
||||
if (!opts) opts = {};
|
||||
|
||||
var action = this.get('actionType.name_key');
|
||||
|
||||
// Mark it as acted
|
||||
@@ -63,7 +65,8 @@ Discourse.ActionSummary = Discourse.Model.extend({
|
||||
data: {
|
||||
id: this.get('post.id'),
|
||||
post_action_type_id: this.get('id'),
|
||||
message: (opts ? opts.message : void 0) || ""
|
||||
message: opts.message,
|
||||
take_action: opts.takeAction
|
||||
}
|
||||
}).then(null, function (error) {
|
||||
actionSummary.removeAction();
|
||||
|
||||
@@ -6,31 +6,9 @@
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.PostActionType = Discourse.Model.extend({
|
||||
});
|
||||
Discourse.PostActionType = Discourse.Model.extend({});
|
||||
|
||||
Discourse.BoundPostActionType = Discourse.PostActionType.extend({
|
||||
customPlaceholder: function(){
|
||||
return Em.String.i18n("flagging.custom_placeholder_" + this.get('name_key'));
|
||||
}.property('name_key'),
|
||||
|
||||
formattedName: function(){
|
||||
return this.get('name').replace("{{username}}", this.get('post.username'));
|
||||
}.property('name'),
|
||||
|
||||
messageChanged: function() {
|
||||
var len, message, minLen, _ref;
|
||||
minLen = 10;
|
||||
len = ((_ref = this.get('message')) ? _ref.length : void 0) || 0;
|
||||
this.set("customMessageLengthClasses", "too-short custom-message-length");
|
||||
if (len === 0) {
|
||||
message = Em.String.i18n("flagging.custom_message.at_least", { n: minLen });
|
||||
} else if (len < minLen) {
|
||||
message = Em.String.i18n("flagging.custom_message.more", { n: minLen - len });
|
||||
} else {
|
||||
message = Em.String.i18n("flagging.custom_message.left", { n: 500 - len });
|
||||
this.set("customMessageLengthClasses", "ok custom-message-length");
|
||||
}
|
||||
this.set("customMessageLength", message);
|
||||
}.observes("message")
|
||||
});
|
||||
Discourse.PostActionType.reopenClass({
|
||||
MIN_MESSAGE_LENGTH: 10,
|
||||
MAX_MESSAGE_LENGTH: 500
|
||||
})
|
||||
|
||||
@@ -13,9 +13,7 @@ Discourse.TopicRoute = Discourse.Route.extend({
|
||||
|
||||
showFlags: function(post) {
|
||||
Discourse.Route.showModal(this, 'flag', post);
|
||||
this.controllerFor('flag').setProperties({
|
||||
postActionTypeId: null
|
||||
});
|
||||
this.controllerFor('flag').setProperties({ selected: null });
|
||||
},
|
||||
|
||||
showAutoClose: function() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="modal-body">
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
{{view Discourse.ArchetypeOptionsView archetypeBinding="view.archetype"}}
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' data-dismiss="modal">{{i18n post.archetypes.save}}</button>
|
||||
</div>
|
||||
<button class='btn btn-primary' {{action closeModal}}>{{i18n post.archetypes.save}}</button>
|
||||
</div>
|
||||
@@ -1,36 +1,30 @@
|
||||
<div class="modal-body flag-modal">
|
||||
{{#if flagsAvailable}}
|
||||
<form>
|
||||
{{#each boundFlags}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound name_key}}" {{action changePostActionType this}} name='post_action_type_index'> <strong>{{formattedName}}</strong>
|
||||
{{#if is_custom_flag}}
|
||||
{{#unless selected}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
{{#if description}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</label>
|
||||
{{#if is_custom_flag}}
|
||||
{{#if selected}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div {{bindAttr class="customMessageLengthClasses"}}>{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
|
||||
<form>
|
||||
{{#each flagsAvailable itemController="flagActionType"}}
|
||||
<div class='controls'>
|
||||
<label class='radio'>
|
||||
<input type='radio' id="radio_{{unbound name_key}}" {{action changePostActionType this}} name='post_action_type_index'> <strong>{{formattedName}}</strong>
|
||||
{{#if showDescription}}
|
||||
<div class='description'>{{{description}}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</form>
|
||||
{{else}}
|
||||
{{i18n flagging.cant}}
|
||||
</label>
|
||||
{{#if showMessageInput}}
|
||||
{{textarea name="message" class="flag-message" placeholder=customPlaceholder value=message}}
|
||||
<div {{bindAttr class=":custom-message-length customMessageLengthClasses"}}>{{customMessageLength}}</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
{{i18n flagging.cant}}
|
||||
{{/each}}
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action createFlag}} {{bindAttr disabled="submitDisabled"}}>{{submitText}}</button>
|
||||
|
||||
{{#if canTakeAction}}
|
||||
<button class='btn btn-danger' {{action takeAction}} {{bindAttr disabled="submitDisabled"}}>{{i18n flagging.take_action}}</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if showSubmit}}
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' {{action createFlag}}>{{submitText}}</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{{#if finished}}
|
||||
<button class='btn btn-primary' data-dismiss="modal">{{i18n close}}</button>
|
||||
<button class='btn btn-primary' {{action closeModal}}>{{i18n close}}</button>
|
||||
{{else}}
|
||||
<button class='btn btn-primary' {{bindAttr disabled="disabled"}} {{action createInvite}}>{{buttonTitle}}</button>
|
||||
{{/if}}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{{#if finished}}
|
||||
<button class='btn btn-primary' data-dismiss="modal">{{i18n close}}</button>
|
||||
<button class='btn btn-primary' {{action closeModal}}>{{i18n close}}</button>
|
||||
{{else}}
|
||||
<button class='btn btn-primary' {{bindAttr disabled="disabled"}} {{action invite}}>{{buttonTitle}}</button>
|
||||
{{/if}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal"><i class='icon-remove icon'></i></a>
|
||||
<a class="close" {{action closeModal}}><i class='icon-remove icon'></i></a>
|
||||
<h3>{{title}}</h3>
|
||||
</div>
|
||||
<div id='modal-alert'></div>
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class='btn btn-primary' data-dismiss="modal">{{i18n close}}</button>
|
||||
<button class='btn btn-primary' {{action closeModal}}>{{i18n close}}</button>
|
||||
</div>
|
||||
Reference in New Issue
Block a user