Extra tests for composer

This commit is contained in:
Robin Ward 2013-07-05 11:53:09 -04:00
parent 7335f5fb7f
commit 11bb9aafc7
11 changed files with 248 additions and 159 deletions

View File

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

View File

@ -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() {

View File

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

View File

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

View File

@ -27,7 +27,7 @@
<div class='control-row reply-area'>
<div class='reply-to'>{{{model.actionTitle}}}:</div>
{{#if model.editTitle}}
{{#if model.canEditTitle}}
<div class='form-element clearfix'>
{{#if model.creatingPrivateMessage}}
{{userSelector topicId=controller.controllers.topic.model.id

View File

@ -14,7 +14,7 @@ Discourse.ComposerView = Discourse.View.extend({
classNameBindings: ['model.creatingPrivateMessage:private-message',
'composeState',
'model.loading',
'model.editTitle',
'model.canEditTitle:edit-title',
'postMade',
'model.creatingTopic:topic',
'model.showPreview',

View File

@ -114,7 +114,6 @@ test("right clicks are tracked", function() {
Discourse.SiteSettings.track_external_right_clicks = true;
trackRightClick();
equal($('a').first().attr('href'), "/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42");
Discourse.SiteSettings.track_external_right_clicks = false;
});

View File

@ -1,2 +1,3 @@
/*jshint maxlen:10000000 */
Discourse.SiteSettings = {"title":"Discourse Meta","logo_url":"/assets/logo.png","logo_small_url":"/assets/logo-single.png","traditional_markdown_linebreaks":false,"top_menu":"latest|new|unread|read|favorited|categories","post_menu":"like|edit|flag|delete|share|bookmark|reply","share_links":"twitter|facebook|google+|email","track_external_right_clicks":false,"must_approve_users":false,"ga_tracking_code":"UA-33736483-2","ga_domain_name":"","enable_long_polling":true,"polling_interval":3000,"anon_polling_interval":30000,"min_post_length":20,"max_post_length":16000,"min_topic_title_length":15,"max_topic_title_length":255,"min_private_message_title_length":2,"allow_uncategorized_topics":true,"min_search_term_length":3,"flush_timings_secs":5,"suppress_reply_directly_below":true,"email_domains_blacklist":"mailinator.com","email_domains_whitelist":null,"version_checks":true,"min_title_similar_length":10,"min_body_similar_length":15,"category_colors":"BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890","max_upload_size_kb":1024,"category_featured_topics":6,"favicon_url":"/assets/favicon.ico","dynamic_favicon":false,"uncategorized_name":"uncategorized","uncategorized_color":"AB9364","uncategorized_text_color":"FFFFFF","invite_only":false,"login_required":false,"enable_local_logins":true,"enable_local_account_create":true,"enable_google_logins":true,"enable_yahoo_logins":true,"enable_twitter_logins":true,"enable_facebook_logins":true,"enable_cas_logins":false,"enable_github_logins":true,"enable_persona_logins":true,"educate_until_posts":2,"topic_views_heat_low":1000,"topic_views_heat_medium":2000,"topic_views_heat_high":5000,"min_private_message_post_length":5,"faq_url":"","tos_url":"","privacy_policy_url":"","authorized_extensions":".jpg|.jpeg|.png|.gif"};
Discourse.SiteSettingsOriginal = {"title":"Discourse Meta","logo_url":"/assets/logo.png","logo_small_url":"/assets/logo-single.png","traditional_markdown_linebreaks":false,"top_menu":"latest|new|unread|read|favorited|categories","post_menu":"like|edit|flag|delete|share|bookmark|reply","share_links":"twitter|facebook|google+|email","track_external_right_clicks":false,"must_approve_users":false,"ga_tracking_code":"UA-33736483-2","ga_domain_name":"","enable_long_polling":true,"polling_interval":3000,"anon_polling_interval":30000,"min_post_length":20,"max_post_length":16000,"min_topic_title_length":15,"max_topic_title_length":255,"min_private_message_title_length":2,"allow_uncategorized_topics":true,"min_search_term_length":3,"flush_timings_secs":5,"suppress_reply_directly_below":true,"email_domains_blacklist":"mailinator.com","email_domains_whitelist":null,"version_checks":true,"min_title_similar_length":10,"min_body_similar_length":15,"category_colors":"BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890","max_upload_size_kb":1024,"category_featured_topics":6,"favicon_url":"/assets/favicon.ico","dynamic_favicon":false,"uncategorized_name":"uncategorized","uncategorized_color":"AB9364","uncategorized_text_color":"FFFFFF","invite_only":false,"login_required":false,"enable_local_logins":true,"enable_local_account_create":true,"enable_google_logins":true,"enable_yahoo_logins":true,"enable_twitter_logins":true,"enable_facebook_logins":true,"enable_cas_logins":false,"enable_github_logins":true,"enable_persona_logins":true,"educate_until_posts":2,"topic_views_heat_low":1000,"topic_views_heat_medium":2000,"topic_views_heat_high":5000,"min_private_message_post_length":5,"faq_url":"","tos_url":"","privacy_policy_url":"","authorized_extensions":".jpg|.jpeg|.png|.gif"};
Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal);

View File

@ -33,22 +33,76 @@ test('missingTitleCharacters', function() {
missingTitleCharacters('z', true, Discourse.SiteSettings.min_private_message_title_length - 1, 'too short pm title');
});
test('wouldLoseChanges', function() {
test('replyDirty', function() {
var composer = Discourse.Composer.create();
ok(!composer.get('wouldLoseChanges'), "by default it's false");
ok(!composer.get('replyDirty'), "by default it's false");
composer.setProperties({
originalText: "hello",
reply: "hello"
});
ok(!composer.get('wouldLoseChanges'), "it's false when the originalText is the same as the reply");
ok(!composer.get('replyDirty'), "it's false when the originalText is the same as the reply");
composer.set('reply', 'hello world');
ok(composer.get('wouldLoseChanges'), "it's true when the reply changes");
ok(composer.get('replyDirty'), "it's true when the reply changes");
});
test("appendText", function() {
var composer = Discourse.Composer.create();
blank(composer.get('reply'), "the reply is blank by default");
composer.appendText("hello");
equal(composer.get('reply'), "hello", "it appends text to nothing");
composer.appendText(" world");
equal(composer.get('reply'), "hello world", "it appends text to existing text");
});
test("Title length for regular topics", function() {
Discourse.SiteSettings.min_topic_title_length = 5;
Discourse.SiteSettings.max_topic_title_length = 10;
var composer = Discourse.Composer.create();
composer.set('title', 'asdf');
ok(!composer.get('titleLengthValid'), "short titles are not valid");
composer.set('title', 'this is a long title');
ok(!composer.get('titleLengthValid'), "long titles are not valid");
composer.set('title', 'just right');
ok(composer.get('titleLengthValid'), "in the range is okay");
});
test("Title length for private messages", function() {
Discourse.SiteSettings.min_private_message_title_length = 5;
Discourse.SiteSettings.max_topic_title_length = 10;
var composer = Discourse.Composer.create({action: Discourse.Composer.PRIVATE_MESSAGE});
composer.set('title', 'asdf');
ok(!composer.get('titleLengthValid'), "short titles are not valid");
composer.set('title', 'this is a long title');
ok(!composer.get('titleLengthValid'), "long titles are not valid");
composer.set('title', 'just right');
ok(composer.get('titleLengthValid'), "in the range is okay");
});
test("Title length for private messages", function() {
Discourse.SiteSettings.min_private_message_title_length = 5;
Discourse.SiteSettings.max_topic_title_length = 10;
var composer = Discourse.Composer.create({action: Discourse.Composer.PRIVATE_MESSAGE});
composer.set('title', 'asdf');
ok(!composer.get('titleLengthValid'), "short titles are not valid");
composer.set('title', 'this is a long title');
ok(!composer.get('titleLengthValid'), "long titles are not valid");
composer.set('title', 'just right');
ok(composer.get('titleLengthValid'), "in the range is okay");
});
test('importQuote with no data', function() {
this.stub(Discourse.Post, 'load');
@ -63,6 +117,19 @@ test('importQuote with no data', function() {
ok(!Discourse.Post.load.calledOnce, "load is not called");
});
test('editingFirstPost', function() {
var composer = Discourse.Composer.create();
ok(!composer.get('editingFirstPost'), "it's false by default");
var post = Discourse.Post.create({id: 123, post_number: 2});
composer.setProperties({post: post, action: Discourse.Composer.EDIT });
ok(!composer.get('editingFirstPost'), "it's false when not editing the first post");
post.set('post_number', 1);
ok(composer.get('editingFirstPost'), "it's true when editing the first post");
});
asyncTest('importQuote with a post', function() {
expect(1);

View File

@ -30,3 +30,15 @@ test('updateFromPost', function() {
equal(post.get('raw'), "different raw", "raw field updated");
});
test('hasHistory', function() {
var post = Discourse.Post.create({id: 1});
ok(!post.get('hasHistory'), 'posts without versions have no history');
post.set('version', 1);
ok(!post.get('hasHistory'), 'posts with one version have no history');
post.set('version', 2);
ok(post.get('hasHistory'), 'posts with more than one version have a history');
});

View File

@ -72,8 +72,13 @@ Discourse.setupForTesting();
Discourse.injectTestHelpers();
Discourse.bindDOMEvents();
Discourse.Router.map(function() {
return Discourse.routeBuilder.call(this);
});
QUnit.testStart(function() {
// Allow our tests to change site settings and have them reset before the next test
Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal);
})