Adds support for dynamic composer messages.

This commit is contained in:
Robin Ward 2013-09-09 16:54:33 -04:00
parent 9c6c0f2a3d
commit 0de96a6059
10 changed files with 110 additions and 80 deletions

View file

@ -7,10 +7,16 @@
@module Discourse
**/
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),
init: function() {
this._super();
this.set('similarTopics', Em.A());
},
togglePreview: function() {
this.get('model').togglePreview();
},
@ -94,7 +100,6 @@ Discourse.ComposerController = Discourse.Controller.extend({
composerController.destroyDraft();
}
opts = opts || {};
composerController.close();
@ -112,51 +117,27 @@ Discourse.ComposerController = Discourse.Controller.extend({
});
},
closeEducation: 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() {
_considerNewUserEducation: function() {
// We don't show education when editing a post.
if (this.get('model.editingPost')) return;
// 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');
if (count >= Discourse.SiteSettings.educate_until_posts) {
this.set('educationClosed', true);
this.set('educationContents', '');
return;
}
if (count >= Discourse.SiteSettings.educate_until_posts) { return; }
// The user must have typed a reply
if (!this.get('typedReply')) return;
this.set('educationClosed', false);
// If visible update the text
var educationKey = this.get('model.creatingTopic') ? 'new-topic' : 'new-reply';
var composerController = this;
var educationKey = this.get('model.creatingTopic') ? 'new-topic' : 'new-reply',
messageController = this.get('controllers.composerMessages');
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'),
@ -176,16 +157,25 @@ Discourse.ComposerController = Discourse.Controller.extend({
// We don't care about similar topics unless creating a topic
if (!this.get('model.creatingTopic')) return;
var body = this.get('model.reply');
var title = this.get('model.title');
var body = this.get('model.reply'),
title = this.get('model.title');
// Ensure the fields are of the minimum length
if (body.length < Discourse.SiteSettings.min_body_similar_length) return;
if (title.length < Discourse.SiteSettings.min_title_similar_length) return;
var composerController = this;
Discourse.Topic.findSimilarTo(title, body).then(function (topics) {
composerController.set('similarTopics', topics);
var messageController = this.get('controllers.composerMessages'),
similarTopics = this.get('similarTopics');
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();
opts.promise = promise;
this.set('typedReply', false);
this.set('similarTopics', null);
this.set('similarClosed', false);
if (!opts.draftKey) {
alert("composer was opened without a draft key");

View file

@ -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);
}
});

View file

@ -2,23 +2,7 @@
<div class='contents'>
<div class='composer-popup-container'>
<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>
{{render composerMessages}}
<div class='control'>
<a href='#' class='toggler' {{action toggle bubbles=false}} title='{{i18n composer.toggler}}'></a>

View file

@ -0,0 +1,2 @@
<a href='#' {{action closeMessage this}} class='close'><i class='icon icon-remove-sign'></i></a>
{{{body}}}

View file

@ -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>

View file

@ -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');
}
}),
});

View file

@ -67,24 +67,6 @@ Discourse.ComposerView = Discourse.View.extend({
});
}.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) {
$('.composer-popup').css('bottom', sizePx);
},

View file

@ -15,6 +15,7 @@
//= require_tree ./discourse/mixins
//= require ./discourse/components/computed
//= require ./discourse/views/view
//= require ./discourse/views/container_view
//= require ./discourse/components/debounce
//= require ./discourse/models/model
//= require ./discourse/models/user_action

View file

@ -51,7 +51,7 @@
}
}
#similar-topics {
.similar-topics {
background-color: #b5e8fd;
border: 1px solid darken(#b5e8fd, 10%);

View file

@ -12,7 +12,7 @@
display: none;
}
.composer-popup, #similar-topics {
.composer-popup {
display: none;
}
@ -99,7 +99,7 @@ display: none;
a.cancel {
text-decoration: underline;
padding-left: 7px;
float: left;
float: left;
margin-top: 6px;
}
.control-row {