diff --git a/app/assets/javascripts/discourse/components/bbcode.js b/app/assets/javascripts/discourse/components/bbcode.js index fe5bae14a0a..91f3d326165 100644 --- a/app/assets/javascripts/discourse/components/bbcode.js +++ b/app/assets/javascripts/discourse/components/bbcode.js @@ -9,7 +9,7 @@ **/ Discourse.BBCode = { - QUOTE_REGEXP: /\[quote=([^\]]*)\]([\s\S]*?)\[\/quote\]/im, + QUOTE_REGEXP: /\[quote=([^\]]*)\]((?:[^](?!\[quote=[^\]]*\]))*?)\[\/quote\]/im, // Define our replacers replacers: { diff --git a/app/assets/javascripts/discourse/models/composer.js b/app/assets/javascripts/discourse/models/composer.js index 2132b161aef..a6a93083eb6 100644 --- a/app/assets/javascripts/discourse/models/composer.js +++ b/app/assets/javascripts/discourse/models/composer.js @@ -431,7 +431,7 @@ Discourse.Composer = Discourse.Model.extend({ _this = this; if (this.get('disableDrafts')) return; if (!this.get('reply')) return; - if (this.get('reply').length < Discourse.SiteSettings.min_post_length) return; + if (this.get('replyLength') < Discourse.SiteSettings.min_post_length) return; data = { reply: this.get('reply'), @@ -453,34 +453,42 @@ Discourse.Composer = Discourse.Model.extend({ }, resetDraftStatus: (function() { - var len, reply; - reply = this.get('reply'); - len = Discourse.SiteSettings.min_post_length; - if (!reply) { - return this.set('draftStatus', Em.String.i18n('composer.min_length.at_least', { - n: len - })); - } else if (reply.length < len) { - return this.set('draftStatus', Em.String.i18n('composer.min_length.more', { - n: len - reply.length - })); + var len = Discourse.SiteSettings.min_post_length, + replyLength = this.get('replyLength'); + + if (replyLength === 0) { + this.set('draftStatus', Em.String.i18n('composer.min_length.at_least', { n: len })); + } else if (replyLength < len) { + this.set('draftStatus', Em.String.i18n('composer.min_length.more', { n: len - replyLength })); } else { - return this.set('draftStatus', null); + this.set('draftStatus', null); } + }).observes('reply', 'title'), blank: function(prop) { - var p; - p = this.get(prop); + var p = this.get(prop); return !(p && p.length > 0); - } + }, + + /** + Computes the length of the reply minus the quote(s). + + @property replyLength + **/ + replyLength: function() { + var reply = this.get('reply'); + if(!reply) reply = ""; + while (Discourse.BBCode.QUOTE_REGEXP.test(reply)) { reply = reply.replace(Discourse.BBCode.QUOTE_REGEXP, ""); } + return reply.trim().length; + }.property('reply') + }); Discourse.Composer.reopenClass({ open: function(opts) { - var composer; - composer = Discourse.Composer.create(); + var composer = Discourse.Composer.create(); composer.open(opts); return composer; }, diff --git a/spec/javascripts/bbcode_spec.js b/spec/javascripts/components/bbcode_spec.js similarity index 100% rename from spec/javascripts/bbcode_spec.js rename to spec/javascripts/components/bbcode_spec.js diff --git a/spec/javascripts/key_value_store_spec.js b/spec/javascripts/components/key_value_store_spec.js similarity index 100% rename from spec/javascripts/key_value_store_spec.js rename to spec/javascripts/components/key_value_store_spec.js diff --git a/spec/javascripts/message_bus_spec.js b/spec/javascripts/components/message_bus_spec.js similarity index 100% rename from spec/javascripts/message_bus_spec.js rename to spec/javascripts/components/message_bus_spec.js diff --git a/spec/javascripts/onebox_spec.js b/spec/javascripts/components/onebox_spec.js similarity index 100% rename from spec/javascripts/onebox_spec.js rename to spec/javascripts/components/onebox_spec.js diff --git a/spec/javascripts/utilities_spec.js b/spec/javascripts/components/utilities_spec.js similarity index 100% rename from spec/javascripts/utilities_spec.js rename to spec/javascripts/components/utilities_spec.js diff --git a/spec/javascripts/models/composer_spec.js b/spec/javascripts/models/composer_spec.js new file mode 100644 index 00000000000..73224cb49e1 --- /dev/null +++ b/spec/javascripts/models/composer_spec.js @@ -0,0 +1,27 @@ +describe("Discourse.Composer", function() { + + describe("replyLength", function() { + + it("returns the length of a basic reply", function() { + var composer = Discourse.Composer.create({ reply: "basic reply" }); + expect(composer.get('replyLength')).toBe(11); + }); + + it("trims whitespaces", function() { + var composer = Discourse.Composer.create({ reply: "\nbasic reply\t" }); + expect(composer.get('replyLength')).toBe(11); + }); + + it("removes quotes", function() { + var composer = Discourse.Composer.create({ reply: "1[quote=]not counted[/quote]2[quote=]at all[/quote]3" }); + expect(composer.get('replyLength')).toBe(3); + }); + + it("handles nested quotes correctly", function() { + var composer = Discourse.Composer.create({ reply: "1[quote=]not[quote=]counted[/quote]yay[/quote]2" }); + expect(composer.get('replyLength')).toBe(2); + }); + + }); + +}); diff --git a/spec/javascripts/user_action_spec.js b/spec/javascripts/models/user_action_spec.js similarity index 100% rename from spec/javascripts/user_action_spec.js rename to spec/javascripts/models/user_action_spec.js