From 0de96a6059785114e3d002d2d7e40297f5fdc763 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 9 Sep 2013 16:54:33 -0400 Subject: [PATCH] Adds support for dynamic composer messages. --- .../controllers/composer_controller.js | 72 ++++++++----------- .../composer_messages_controller.js | 31 ++++++++ .../templates/composer.js.handlebars | 18 +---- .../composer/education.js.handlebars | 2 + .../composer/similar_topics.js.handlebars | 8 +++ .../views/composer/composer_messages_view.js | 34 +++++++++ .../views/{ => composer}/composer_view.js | 18 ----- app/assets/javascripts/main_include.js | 1 + .../stylesheets/desktop/compose.css.scss | 2 +- .../stylesheets/mobile/compose.css.scss | 4 +- 10 files changed, 110 insertions(+), 80 deletions(-) create mode 100644 app/assets/javascripts/discourse/controllers/composer_messages_controller.js create mode 100644 app/assets/javascripts/discourse/templates/composer/education.js.handlebars create mode 100644 app/assets/javascripts/discourse/templates/composer/similar_topics.js.handlebars create mode 100644 app/assets/javascripts/discourse/views/composer/composer_messages_view.js rename app/assets/javascripts/discourse/views/{ => composer}/composer_view.js (96%) diff --git a/app/assets/javascripts/discourse/controllers/composer_controller.js b/app/assets/javascripts/discourse/controllers/composer_controller.js index 7b59ccc04d8..99805553faa 100644 --- a/app/assets/javascripts/discourse/controllers/composer_controller.js +++ b/app/assets/javascripts/discourse/controllers/composer_controller.js @@ -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"); diff --git a/app/assets/javascripts/discourse/controllers/composer_messages_controller.js b/app/assets/javascripts/discourse/controllers/composer_messages_controller.js new file mode 100644 index 00000000000..1f4b1bcf126 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/composer_messages_controller.js @@ -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); + } + +}); \ No newline at end of file diff --git a/app/assets/javascripts/discourse/templates/composer.js.handlebars b/app/assets/javascripts/discourse/templates/composer.js.handlebars index 3064aeebfd8..daed39384fd 100644 --- a/app/assets/javascripts/discourse/templates/composer.js.handlebars +++ b/app/assets/javascripts/discourse/templates/composer.js.handlebars @@ -2,23 +2,7 @@
-
- - - -
+ {{render composerMessages}}
diff --git a/app/assets/javascripts/discourse/templates/composer/education.js.handlebars b/app/assets/javascripts/discourse/templates/composer/education.js.handlebars new file mode 100644 index 00000000000..6b861e7f82a --- /dev/null +++ b/app/assets/javascripts/discourse/templates/composer/education.js.handlebars @@ -0,0 +1,2 @@ + +{{{body}}} \ No newline at end of file diff --git a/app/assets/javascripts/discourse/templates/composer/similar_topics.js.handlebars b/app/assets/javascripts/discourse/templates/composer/similar_topics.js.handlebars new file mode 100644 index 00000000000..71b761889e0 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/composer/similar_topics.js.handlebars @@ -0,0 +1,8 @@ + +

{{i18n composer.similar_topics}}

+ +
    + {{#each similarTopics}} +
  • {{{topicLink this}}} ({{{i18n topic.filters.n_posts count="posts_count"}}})
  • + {{/each}} +
diff --git a/app/assets/javascripts/discourse/views/composer/composer_messages_view.js b/app/assets/javascripts/discourse/views/composer/composer_messages_view.js new file mode 100644 index 00000000000..3056ce1e869 --- /dev/null +++ b/app/assets/javascripts/discourse/views/composer/composer_messages_view.js @@ -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'); + } + }), +}); + diff --git a/app/assets/javascripts/discourse/views/composer_view.js b/app/assets/javascripts/discourse/views/composer/composer_view.js similarity index 96% rename from app/assets/javascripts/discourse/views/composer_view.js rename to app/assets/javascripts/discourse/views/composer/composer_view.js index 41625419628..49bc80801e4 100644 --- a/app/assets/javascripts/discourse/views/composer_view.js +++ b/app/assets/javascripts/discourse/views/composer/composer_view.js @@ -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); }, diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index 0fb2fde9845..1ce1b7155f2 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -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 diff --git a/app/assets/stylesheets/desktop/compose.css.scss b/app/assets/stylesheets/desktop/compose.css.scss index 620a2abb792..cd4f8e001b6 100644 --- a/app/assets/stylesheets/desktop/compose.css.scss +++ b/app/assets/stylesheets/desktop/compose.css.scss @@ -51,7 +51,7 @@ } } -#similar-topics { +.similar-topics { background-color: #b5e8fd; border: 1px solid darken(#b5e8fd, 10%); diff --git a/app/assets/stylesheets/mobile/compose.css.scss b/app/assets/stylesheets/mobile/compose.css.scss index b996dde9a16..bf1c19abad5 100644 --- a/app/assets/stylesheets/mobile/compose.css.scss +++ b/app/assets/stylesheets/mobile/compose.css.scss @@ -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 {