diff --git a/app/assets/javascripts/discourse/controllers/composer_controller.js b/app/assets/javascripts/discourse/controllers/composer_controller.js index 4024be2970c..a88013d408e 100644 --- a/app/assets/javascripts/discourse/controllers/composer_controller.js +++ b/app/assets/javascripts/discourse/controllers/composer_controller.js @@ -242,7 +242,7 @@ Discourse.ComposerController = Discourse.Controller.extend({ composer = null; } - if (composer && !opts.tested && composer.get('wouldLoseChanges')) { + if (composer && !opts.tested && composer.get('replyDirty')) { if (composer.composeState === Discourse.Composer.DRAFT && composer.draftKey === opts.draftKey && composer.action === opts.action) { composer.set('composeState', Discourse.Composer.OPEN); promise.resolve(); @@ -300,7 +300,7 @@ Discourse.ComposerController = Discourse.Controller.extend({ var composerController = this; return Ember.Deferred.promise(function (promise) { - if (composerController.get('model.hasMetaData') || composerController.get('model.wouldLoseChanges')) { + if (composerController.get('model.hasMetaData') || composerController.get('model.replyDirty')) { bootbox.confirm(Em.String.i18n("post.abandon"), Em.String.i18n("no_value"), Em.String.i18n("yes_value"), function(result) { if (result) { composerController.destroyDraft(); @@ -326,7 +326,7 @@ Discourse.ComposerController = Discourse.Controller.extend({ }, shrink: function() { - if (this.get('model.wouldLoseChanges')) { + if (this.get('model.replyDirty')) { this.collapse(); } else { this.close(); diff --git a/app/assets/javascripts/discourse/controllers/quote_button_controller.js b/app/assets/javascripts/discourse/controllers/quote_button_controller.js index 13e27ba25b1..e7c67dfea40 100644 --- a/app/assets/javascripts/discourse/controllers/quote_button_controller.js +++ b/app/assets/javascripts/discourse/controllers/quote_button_controller.js @@ -113,7 +113,7 @@ Discourse.QuoteButtonController = Discourse.Controller.extend({ var buffer = this.get('buffer'); var quotedText = Discourse.BBCode.buildQuoteBBCode(post, buffer); - if (composerController.get('content.wouldLoseChanges')) { + if (composerController.get('content.replyDirty')) { composerController.appendText(quotedText); } else { composerController.open(composerOpts).then(function() { diff --git a/app/assets/javascripts/discourse/models/composer.js b/app/assets/javascripts/discourse/models/composer.js index e0cfe3467c8..099a24e0f19 100644 --- a/app/assets/javascripts/discourse/models/composer.js +++ b/app/assets/javascripts/discourse/models/composer.js @@ -21,13 +21,6 @@ var CLOSED = 'closed', Discourse.Composer = Discourse.Model.extend({ - init: function() { - this._super(); - var val = Discourse.KeyValueStore.get('composer.showPreview') || 'true'; - this.set('showPreview', val === 'true'); - this.set('archetypeId', Discourse.Site.instance().get('default_archetype')); - }, - archetypes: function() { return Discourse.Site.instance().get('archetypes'); }.property(), @@ -40,6 +33,8 @@ Discourse.Composer = Discourse.Model.extend({ viewOpen: Em.computed.equal('composeState', OPEN), viewDraft: Em.computed.equal('composeState', DRAFT), + notCreatingPrivateMessage: Em.computed.not('creatingPrivateMessage'), + archetype: function() { return this.get('archetypes').findProperty('id', this.get('archetypeId')); }.property('archetypeId'), @@ -48,42 +43,14 @@ Discourse.Composer = Discourse.Model.extend({ return this.set('metaData', Em.Object.create()); }.observes('archetype'), - editTitle: function() { - if (this.get('creatingTopic') || this.get('creatingPrivateMessage')) return true; - if (this.get('editingPost') && this.get('post.post_number') === 1) return true; - return false; - }.property('editingPost', 'creatingTopic', 'post.post_number'), - - canCategorize: function() { - return (this.get('editTitle') && !this.get('creatingPrivateMessage')); - }.property('editTitle', 'creatingPrivateMessage'), + editingFirstPost: Em.computed.and('editingPost', 'post.firstPost'), + canEditTitle: Em.computed.or('creatingTopic', 'creatingPrivateMessage', 'editingFirstPost'), + canCategorize: Em.computed.and('canEditTitle', 'notCreatingPrivateMessage'), showAdminOptions: function() { if (this.get('creatingTopic') && Discourse.User.current('staff')) return true; return false; - }.property('editTitle'), - - togglePreview: function() { - this.toggleProperty('showPreview'); - Discourse.KeyValueStore.set({ key: 'composer.showPreview', value: this.get('showPreview') }); - }, - - importQuote: function() { - // If there is no current post, use the post id from the stream - var postId = this.get('post.id') || this.get('topic.postStream.firstPostId'); - if (postId) { - this.set('loading', true); - var composer = this; - return Discourse.Post.load(postId).then(function(post) { - composer.appendText(Discourse.BBCode.buildQuoteBBCode(post, post.get('raw'))); - composer.set('loading', false); - }); - } - }, - - appendText: function(text) { - this.set('reply', (this.get('reply') || '') + text); - }, + }.property('canEditTitle'), // Determine the appropriate title for this action actionTitle: function() { @@ -144,7 +111,7 @@ Discourse.Composer = Discourse.Model.extend({ // - editing the 1st post // - creating a private message - if (this.get('editTitle') && !this.get('titleLengthValid')) return true; + if (this.get('canEditTitle') && !this.get('titleLengthValid')) return true; // Need at least one user when sending a private message if ( this.get('creatingPrivateMessage') && @@ -159,16 +126,17 @@ Discourse.Composer = Discourse.Model.extend({ if (this.get('canCategorize') && !Discourse.SiteSettings.allow_uncategorized_topics && !this.get('categoryName')) return true; return false; - }.property('loading', 'editTitle', 'titleLength', 'targetUsernames', 'replyLength', 'categoryName', 'missingReplyCharacters'), + }.property('loading', 'canEditTitle', 'titleLength', 'targetUsernames', 'replyLength', 'categoryName', 'missingReplyCharacters'), + /** + Is the title's length valid? + + @property titleLengthValid + **/ titleLengthValid: function() { - if (this.get('creatingPrivateMessage')) { - if (this.get('titleLength') < Discourse.SiteSettings.min_private_message_title_length) return false; - } else { - if (this.get('titleLength') < Discourse.SiteSettings.min_topic_title_length) return false; - } + if (this.get('titleLength') < this.get('minimumTitleLength')) return false; return (this.get('titleLength') <= Discourse.SiteSettings.max_topic_title_length); - }.property('creatingPrivateMessage', 'titleLength'), + }.property('minimumTitleLength', 'titleLength'), // The text for the save button saveText: function() { @@ -185,9 +153,139 @@ Discourse.Composer = Discourse.Model.extend({ return metaData ? Em.empty(Em.keys(this.get('metaData'))) : false; }.property('metaData'), - wouldLoseChanges: function() { + /** + Did the user make changes to the reply? + + @property replyDirty + **/ + replyDirty: function() { return this.get('reply') !== this.get('originalText'); - }.property('reply', 'save'), + }.property('reply', 'originalText'), + +/** + Number of missing characters in the title until valid. + + @property missingTitleCharacters + **/ + missingTitleCharacters: function() { + return this.get('minimumTitleLength') - this.get('titleLength'); + }.property('minimumTitleLength', 'titleLength'), + + /** + Minimum number of characters for a title to be valid. + + @property minimumTitleLength + **/ + minimumTitleLength: function() { + if (this.get('creatingPrivateMessage')) { + return Discourse.SiteSettings.min_private_message_title_length; + } else { + return Discourse.SiteSettings.min_topic_title_length; + } + }.property('creatingPrivateMessage'), + + /** + Number of missing characters in the reply until valid. + + @property missingReplyCharacters + **/ + missingReplyCharacters: function() { + return this.get('minimumPostLength') - this.get('replyLength'); + }.property('minimumPostLength', 'replyLength'), + + /** + Minimum number of characters for a post body to be valid. + + @property minimumPostLength + **/ + minimumPostLength: function() { + if( this.get('creatingPrivateMessage') ) { + return Discourse.SiteSettings.min_private_message_post_length; + } else { + return Discourse.SiteSettings.min_post_length; + } + }.property('creatingPrivateMessage'), + + /** + Computes the length of the title minus non-significant whitespaces + + @property titleLength + **/ + titleLength: function() { + var title = this.get('title') || ""; + return title.replace(/\s+/img, " ").trim().length; + }.property('title'), + + /** + Computes the length of the reply minus the quote(s) and non-significant whitespaces + + @property replyLength + **/ + replyLength: function() { + var reply = this.get('reply') || ""; + while (Discourse.BBCode.QUOTE_REGEXP.test(reply)) { reply = reply.replace(Discourse.BBCode.QUOTE_REGEXP, ""); } + return reply.replace(/\s+/img, " ").trim().length; + }.property('reply'), + + + updateDraftStatus: function() { + var $title = $('#reply-title'), + $reply = $('#wmd-input'); + + // 'title' is focused + if ($title.is(':focus')) { + var titleDiff = this.get('missingTitleCharacters'); + if (titleDiff > 0) { + this.flashDraftStatusForNewUser(); + return this.set('draftStatus', Em.String.i18n('composer.min_length.need_more_for_title', { n: titleDiff })); + } + // 'reply' is focused + } else if ($reply.is(':focus')) { + var replyDiff = this.get('missingReplyCharacters'); + if (replyDiff > 0) { + return this.set('draftStatus', Em.String.i18n('composer.min_length.need_more_for_reply', { n: replyDiff })); + } + } + + // hide the counters if the currently focused text field is OK + this.set('draftStatus', null); + + }.observes('missingTitleCharacters', 'missingReplyCharacters'), + + init: function() { + this._super(); + var val = Discourse.KeyValueStore.get('composer.showPreview') || 'true'; + this.set('showPreview', val === 'true'); + this.set('archetypeId', Discourse.Site.instance().get('default_archetype')); + }, + + /** + Append text to the current reply + + @method appendText + @param {String} text the text to append + **/ + appendText: function(text) { + this.set('reply', (this.get('reply') || '') + text); + }, + + togglePreview: function() { + this.toggleProperty('showPreview'); + Discourse.KeyValueStore.set({ key: 'composer.showPreview', value: this.get('showPreview') }); + }, + + importQuote: function() { + // If there is no current post, use the post id from the stream + var postId = this.get('post.id') || this.get('topic.postStream.firstPostId'); + if (postId) { + this.set('loading', true); + var composer = this; + return Discourse.Post.load(postId).then(function(post) { + composer.appendText(Discourse.BBCode.buildQuoteBBCode(post, post.get('raw'))); + composer.set('loading', false); + }); + } + }, /* Open a composer @@ -440,97 +538,7 @@ Discourse.Composer = Discourse.Model.extend({ $draftStatus.toggleClass('flash', true); setTimeout(function() { $draftStatus.removeClass('flash'); }, 250); } - }, - - updateDraftStatus: function() { - var $title = $('#reply-title'), - $reply = $('#wmd-input'); - - // 'title' is focused - if ($title.is(':focus')) { - var titleDiff = this.get('missingTitleCharacters'); - if (titleDiff > 0) { - this.flashDraftStatusForNewUser(); - return this.set('draftStatus', Em.String.i18n('composer.min_length.need_more_for_title', { n: titleDiff })); - } - // 'reply' is focused - } else if ($reply.is(':focus')) { - var replyDiff = this.get('missingReplyCharacters'); - if (replyDiff > 0) { - return this.set('draftStatus', Em.String.i18n('composer.min_length.need_more_for_reply', { n: replyDiff })); - } - } - - // hide the counters if the currently focused text field is OK - this.set('draftStatus', null); - - }.observes('missingTitleCharacters', 'missingReplyCharacters'), - - /** - Number of missing characters in the title until valid. - - @property missingTitleCharacters - **/ - missingTitleCharacters: function() { - return this.get('minimumTitleLength') - this.get('titleLength'); - }.property('minimumTitleLength', 'titleLength'), - - /** - Minimum number of characters for a title to be valid. - - @property minimumTitleLength - **/ - minimumTitleLength: function() { - if (this.get('creatingPrivateMessage')) { - return Discourse.SiteSettings.min_private_message_title_length; - } else { - return Discourse.SiteSettings.min_topic_title_length; - } - }.property('creatingPrivateMessage'), - - - /** - Number of missing characters in the reply until valid. - - @property missingReplyCharacters - **/ - missingReplyCharacters: function() { - return this.get('minimumPostLength') - this.get('replyLength'); - }.property('minimumPostLength', 'replyLength'), - - /** - Minimum number of characters for a post body to be valid. - - @property minimumPostLength - **/ - minimumPostLength: function() { - if( this.get('creatingPrivateMessage') ) { - return Discourse.SiteSettings.min_private_message_post_length; - } else { - return Discourse.SiteSettings.min_post_length; - } - }.property('creatingPrivateMessage'), - - /** - Computes the length of the title minus non-significant whitespaces - - @property titleLength - **/ - titleLength: function() { - var title = this.get('title') || ""; - return title.replace(/\s+/img, " ").trim().length; - }.property('title'), - - /** - Computes the length of the reply minus the quote(s) and non-significant whitespaces - - @property replyLength - **/ - replyLength: function() { - var reply = this.get('reply') || ""; - while (Discourse.BBCode.QUOTE_REGEXP.test(reply)) { reply = reply.replace(Discourse.BBCode.QUOTE_REGEXP, ""); } - return reply.replace(/\s+/img, " ").trim().length; - }.property('reply') + } }); diff --git a/app/assets/javascripts/discourse/models/post.js b/app/assets/javascripts/discourse/models/post.js index 757b23a2a04..d048f1eb431 100644 --- a/app/assets/javascripts/discourse/models/post.js +++ b/app/assets/javascripts/discourse/models/post.js @@ -9,8 +9,7 @@ Discourse.Post = Discourse.Model.extend({ shareUrl: function() { - if (this.get('postnumber') === 1) return this.get('topic.url'); - + if (this.get('firstPost')) return this.get('topic.url'); var user = Discourse.User.current(); return this.get('url') + (user ? '?u=' + user.get('username_lower') : ''); }.property('url'), @@ -38,9 +37,7 @@ Discourse.Post = Discourse.Model.extend({ return this.get('topic.details.created_by.id') === this.get('user_id'); }.property('topic.details.created_by.id', 'user_id'), - hasHistory: function() { - return this.get('version') > 1; - }.property('version'), + hasHistory: Em.computed.gt('version', 1), postElementId: function() { return "post_" + (this.get('post_number')); diff --git a/app/assets/javascripts/discourse/templates/composer.js.handlebars b/app/assets/javascripts/discourse/templates/composer.js.handlebars index ef1e16af882..75c842956c2 100644 --- a/app/assets/javascripts/discourse/templates/composer.js.handlebars +++ b/app/assets/javascripts/discourse/templates/composer.js.handlebars @@ -27,7 +27,7 @@