Adds support for dynamic composer messages.
This commit is contained in:
parent
9c6c0f2a3d
commit
0de96a6059
|
@ -7,10 +7,16 @@
|
||||||
@module Discourse
|
@module Discourse
|
||||||
**/
|
**/
|
||||||
Discourse.ComposerController = Discourse.Controller.extend({
|
Discourse.ComposerController = Discourse.Controller.extend({
|
||||||
needs: ['modal', 'topic'],
|
needs: ['modal', 'topic', 'composerMessages'],
|
||||||
|
|
||||||
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY),
|
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Discourse.Composer.REPLY_AS_NEW_TOPIC_KEY),
|
||||||
|
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this._super();
|
||||||
|
this.set('similarTopics', Em.A());
|
||||||
|
},
|
||||||
|
|
||||||
togglePreview: function() {
|
togglePreview: function() {
|
||||||
this.get('model').togglePreview();
|
this.get('model').togglePreview();
|
||||||
},
|
},
|
||||||
|
@ -94,7 +100,6 @@ Discourse.ComposerController = Discourse.Controller.extend({
|
||||||
composerController.destroyDraft();
|
composerController.destroyDraft();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
composerController.close();
|
composerController.close();
|
||||||
|
|
||||||
|
@ -112,51 +117,27 @@ Discourse.ComposerController = Discourse.Controller.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
closeEducation: function() {
|
_considerNewUserEducation: function() {
|
||||||
this.set('educationClosed', true);
|
|
||||||
},
|
|
||||||
|
|
||||||
closeSimilar: function() {
|
|
||||||
this.set('similarClosed', true);
|
|
||||||
},
|
|
||||||
|
|
||||||
similarVisible: function() {
|
|
||||||
if (this.get('similarClosed')) return false;
|
|
||||||
if (this.get('model.composeState') !== Discourse.Composer.OPEN) return false;
|
|
||||||
return (this.get('similarTopics.length') || 0) > 0;
|
|
||||||
}.property('similarTopics.length', 'similarClosed', 'model.composeState'),
|
|
||||||
|
|
||||||
newUserEducationVisible: function() {
|
|
||||||
if (!this.get('educationContents')) return false;
|
|
||||||
if (this.get('model.composeState') !== Discourse.Composer.OPEN) return false;
|
|
||||||
if (!this.present('model.reply')) return false;
|
|
||||||
if (this.get('educationClosed')) return false;
|
|
||||||
return true;
|
|
||||||
}.property('model.composeState', 'model.reply', 'educationClosed', 'educationContents'),
|
|
||||||
|
|
||||||
fetchNewUserEducation: function() {
|
|
||||||
|
|
||||||
// We don't show education when editing a post.
|
// We don't show education when editing a post.
|
||||||
if (this.get('model.editingPost')) return;
|
if (this.get('model.editingPost')) return;
|
||||||
|
|
||||||
// If creating a topic, use topic_count, otherwise post_count
|
// If creating a topic, use topic_count, otherwise post_count
|
||||||
var count = this.get('model.creatingTopic') ? Discourse.User.currentProp('topic_count') : Discourse.User.currentProp('reply_count');
|
var count = this.get('model.creatingTopic') ? Discourse.User.currentProp('topic_count') : Discourse.User.currentProp('reply_count');
|
||||||
if (count >= Discourse.SiteSettings.educate_until_posts) {
|
if (count >= Discourse.SiteSettings.educate_until_posts) { return; }
|
||||||
this.set('educationClosed', true);
|
|
||||||
this.set('educationContents', '');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The user must have typed a reply
|
// The user must have typed a reply
|
||||||
if (!this.get('typedReply')) return;
|
if (!this.get('typedReply')) return;
|
||||||
|
|
||||||
this.set('educationClosed', false);
|
|
||||||
|
|
||||||
// If visible update the text
|
// If visible update the text
|
||||||
var educationKey = this.get('model.creatingTopic') ? 'new-topic' : 'new-reply';
|
var educationKey = this.get('model.creatingTopic') ? 'new-topic' : 'new-reply',
|
||||||
var composerController = this;
|
messageController = this.get('controllers.composerMessages');
|
||||||
|
|
||||||
Discourse.ajax("/education/" + educationKey, {dataType: 'html'}).then(function(result) {
|
Discourse.ajax("/education/" + educationKey, {dataType: 'html'}).then(function(result) {
|
||||||
composerController.set('educationContents', result);
|
messageController.popup({
|
||||||
|
templateName: 'composer/education',
|
||||||
|
body: result
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}.observes('typedReply', 'model.creatingTopic', 'currentUser.reply_count'),
|
}.observes('typedReply', 'model.creatingTopic', 'currentUser.reply_count'),
|
||||||
|
@ -176,16 +157,25 @@ Discourse.ComposerController = Discourse.Controller.extend({
|
||||||
// We don't care about similar topics unless creating a topic
|
// We don't care about similar topics unless creating a topic
|
||||||
if (!this.get('model.creatingTopic')) return;
|
if (!this.get('model.creatingTopic')) return;
|
||||||
|
|
||||||
var body = this.get('model.reply');
|
var body = this.get('model.reply'),
|
||||||
var title = this.get('model.title');
|
title = this.get('model.title');
|
||||||
|
|
||||||
// Ensure the fields are of the minimum length
|
// Ensure the fields are of the minimum length
|
||||||
if (body.length < Discourse.SiteSettings.min_body_similar_length) return;
|
if (body.length < Discourse.SiteSettings.min_body_similar_length) return;
|
||||||
if (title.length < Discourse.SiteSettings.min_title_similar_length) return;
|
if (title.length < Discourse.SiteSettings.min_title_similar_length) return;
|
||||||
|
|
||||||
var composerController = this;
|
var messageController = this.get('controllers.composerMessages'),
|
||||||
Discourse.Topic.findSimilarTo(title, body).then(function (topics) {
|
similarTopics = this.get('similarTopics');
|
||||||
composerController.set('similarTopics', topics);
|
|
||||||
|
Discourse.Topic.findSimilarTo(title, body).then(function (newTopics) {
|
||||||
|
similarTopics.clear();
|
||||||
|
similarTopics.pushObjects(newTopics);
|
||||||
|
|
||||||
|
messageController.popup({
|
||||||
|
templateName: 'composer/similar_topics',
|
||||||
|
similarTopics: similarTopics,
|
||||||
|
extraClass: 'similar-topics'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -211,8 +201,6 @@ Discourse.ComposerController = Discourse.Controller.extend({
|
||||||
var promise = opts.promise || Ember.Deferred.create();
|
var promise = opts.promise || Ember.Deferred.create();
|
||||||
opts.promise = promise;
|
opts.promise = promise;
|
||||||
this.set('typedReply', false);
|
this.set('typedReply', false);
|
||||||
this.set('similarTopics', null);
|
|
||||||
this.set('similarClosed', false);
|
|
||||||
|
|
||||||
if (!opts.draftKey) {
|
if (!opts.draftKey) {
|
||||||
alert("composer was opened without a draft key");
|
alert("composer was opened without a draft key");
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
A controller for displaying messages as the user composes a message.
|
||||||
|
|
||||||
|
@class ComposerMessagesController
|
||||||
|
@extends Ember.ArrayController
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ComposerMessagesController = Ember.ArrayController.extend({
|
||||||
|
needs: ['composer'],
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this._super();
|
||||||
|
this.set('messagesByTemplate', {});
|
||||||
|
},
|
||||||
|
|
||||||
|
popup: function(msg) {
|
||||||
|
var messagesByTemplate = this.get('messagesByTemplate'),
|
||||||
|
existing = messagesByTemplate[msg.templateName];
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
this.pushObject(msg);
|
||||||
|
messagesByTemplate[msg.templateName] = msg;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
closeMessage: function(message) {
|
||||||
|
this.removeObject(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
|
@ -2,23 +2,7 @@
|
||||||
|
|
||||||
<div class='contents'>
|
<div class='contents'>
|
||||||
|
|
||||||
<div class='composer-popup-container'>
|
{{render composerMessages}}
|
||||||
<div id='new-user-education' class='composer-popup' style='display: none'>
|
|
||||||
<a href='#' {{action closeEducation}} class='close'><i class='icon icon-remove-sign'></i></a>
|
|
||||||
{{{educationContents}}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id='similar-topics' class='composer-popup' style='display: none'>
|
|
||||||
<a href='#' {{action closeSimilar}} class='close'><i class='icon icon-remove-sign'></i></a>
|
|
||||||
<h3>{{i18n composer.similar_topics}}<h3>
|
|
||||||
|
|
||||||
<ul class='topics'>
|
|
||||||
{{#each similarTopics}}
|
|
||||||
<li>{{{topicLink this}}} <span class='posts-count'>({{{i18n topic.filters.n_posts count="posts_count"}}})</span></li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='control'>
|
<div class='control'>
|
||||||
<a href='#' class='toggler' {{action toggle bubbles=false}} title='{{i18n composer.toggler}}'></a>
|
<a href='#' class='toggler' {{action toggle bubbles=false}} title='{{i18n composer.toggler}}'></a>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<a href='#' {{action closeMessage this}} class='close'><i class='icon icon-remove-sign'></i></a>
|
||||||
|
{{{body}}}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<a href='#' {{action closeMessage this}} class='close'><i class='icon icon-remove-sign'></i></a>
|
||||||
|
<h3>{{i18n composer.similar_topics}}<h3>
|
||||||
|
|
||||||
|
<ul class='topics'>
|
||||||
|
{{#each similarTopics}}
|
||||||
|
<li>{{{topicLink this}}} <span class='posts-count'>({{{i18n topic.filters.n_posts count="posts_count"}}})</span></li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
Renders a popup messages on the composer
|
||||||
|
|
||||||
|
@class ComposerMessagesView
|
||||||
|
@extends Discourse.View
|
||||||
|
@namespace Discourse
|
||||||
|
@module Discourse
|
||||||
|
**/
|
||||||
|
Discourse.ComposerMessagesView = Ember.CollectionView.extend({
|
||||||
|
classNameBindings: [':composer-popup-container', 'hidden'],
|
||||||
|
content: Em.computed.alias('controller.content'),
|
||||||
|
|
||||||
|
hidden: Em.computed.not('controller.controllers.composer.model.viewOpen'),
|
||||||
|
|
||||||
|
itemViewClass: Discourse.View.extend({
|
||||||
|
classNames: ['composer-popup', 'hidden'],
|
||||||
|
templateName: Em.computed.alias('content.templateName'),
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this._super();
|
||||||
|
this.set('context', this.get('content'));
|
||||||
|
|
||||||
|
if (this.get('content.extraClass')) {
|
||||||
|
this.get('classNames').pushObject(this.get('content.extraClass'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
didInsertElement: function() {
|
||||||
|
var replyControl = $('#reply-control');
|
||||||
|
this.$().css('bottom', (replyControl.height() || 0) + "px").slideDown('fast');
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
|
@ -67,24 +67,6 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
});
|
});
|
||||||
}.observes('model.reply', 'model.hidePreview'),
|
}.observes('model.reply', 'model.hidePreview'),
|
||||||
|
|
||||||
newUserEducationVisibilityChanged: function() {
|
|
||||||
var $panel = $('#new-user-education');
|
|
||||||
if (this.get('controller.newUserEducationVisible')) {
|
|
||||||
$panel.slideDown('fast');
|
|
||||||
} else {
|
|
||||||
$panel.slideUp('fast');
|
|
||||||
}
|
|
||||||
}.observes('controller.newUserEducationVisible'),
|
|
||||||
|
|
||||||
similarVisibilityChanged: function() {
|
|
||||||
var $panel = $('#similar-topics');
|
|
||||||
if (this.get('controller.similarVisible')) {
|
|
||||||
$panel.slideDown('fast');
|
|
||||||
} else {
|
|
||||||
$panel.slideUp('fast');
|
|
||||||
}
|
|
||||||
}.observes('controller.similarVisible'),
|
|
||||||
|
|
||||||
movePanels: function(sizePx) {
|
movePanels: function(sizePx) {
|
||||||
$('.composer-popup').css('bottom', sizePx);
|
$('.composer-popup').css('bottom', sizePx);
|
||||||
},
|
},
|
|
@ -15,6 +15,7 @@
|
||||||
//= require_tree ./discourse/mixins
|
//= require_tree ./discourse/mixins
|
||||||
//= require ./discourse/components/computed
|
//= require ./discourse/components/computed
|
||||||
//= require ./discourse/views/view
|
//= require ./discourse/views/view
|
||||||
|
//= require ./discourse/views/container_view
|
||||||
//= require ./discourse/components/debounce
|
//= require ./discourse/components/debounce
|
||||||
//= require ./discourse/models/model
|
//= require ./discourse/models/model
|
||||||
//= require ./discourse/models/user_action
|
//= require ./discourse/models/user_action
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#similar-topics {
|
.similar-topics {
|
||||||
background-color: #b5e8fd;
|
background-color: #b5e8fd;
|
||||||
border: 1px solid darken(#b5e8fd, 10%);
|
border: 1px solid darken(#b5e8fd, 10%);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.composer-popup, #similar-topics {
|
.composer-popup {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ display: none;
|
||||||
a.cancel {
|
a.cancel {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
padding-left: 7px;
|
padding-left: 7px;
|
||||||
float: left;
|
float: left;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
.control-row {
|
.control-row {
|
||||||
|
|
Loading…
Reference in New Issue