2013-02-22 15:41:12 -05:00
/ * *
A data model for representing the composer ' s current state
@ class Composer
@ extends Discourse . Model
@ namespace Discourse
@ module Discourse
* * /
var CLOSED , CREATE _TOPIC , DRAFT , EDIT , OPEN , PRIVATE _MESSAGE , REPLY , REPLY _AS _NEW _TOPIC _KEY , SAVING ;
CLOSED = 'closed' ;
SAVING = 'saving' ;
OPEN = 'open' ;
DRAFT = 'draft' ;
// The actions the composer can take
CREATE _TOPIC = 'createTopic' ;
PRIVATE _MESSAGE = 'privateMessage' ;
REPLY = 'reply' ;
EDIT = 'edit' ;
REPLY _AS _NEW _TOPIC _KEY = "reply_as_new_topic" ;
Discourse . Composer = Discourse . Model . extend ( {
init : function ( ) {
this . _super ( ) ;
2013-03-13 18:37:45 -04:00
var val = Discourse . KeyValueStore . get ( 'composer.showPreview' ) || 'true' ;
2013-02-22 15:41:12 -05:00
this . set ( 'showPreview' , val === 'true' ) ;
2013-05-24 11:22:17 -04:00
this . set ( 'archetypeId' , Discourse . Site . instance ( ) . get ( 'default_archetype' ) ) ;
2013-02-22 15:41:12 -05:00
} ,
2013-05-24 11:22:17 -04:00
archetypes : function ( ) {
return Discourse . Site . instance ( ) . get ( 'archetypes' ) ;
} . property ( ) ,
2013-04-07 14:56:58 +02:00
creatingTopic : function ( ) {
2013-02-22 15:41:12 -05:00
return this . get ( 'action' ) === CREATE _TOPIC ;
2013-04-07 14:56:58 +02:00
} . property ( 'action' ) ,
2013-02-22 15:41:12 -05:00
2013-04-07 14:56:58 +02:00
creatingPrivateMessage : function ( ) {
2013-02-22 15:41:12 -05:00
return this . get ( 'action' ) === PRIVATE _MESSAGE ;
2013-04-07 14:56:58 +02:00
} . property ( 'action' ) ,
2013-02-22 15:41:12 -05:00
2013-04-07 14:56:58 +02:00
editingPost : function ( ) {
2013-02-22 15:41:12 -05:00
return this . get ( 'action' ) === EDIT ;
2013-04-07 14:56:58 +02:00
} . property ( 'action' ) ,
2013-02-22 15:41:12 -05:00
2013-04-07 14:56:58 +02:00
replyingToTopic : function ( ) {
2013-03-11 20:56:45 -07:00
return this . get ( 'action' ) === REPLY ;
2013-04-07 14:56:58 +02:00
} . property ( 'action' ) ,
2013-03-11 20:56:45 -07:00
2013-04-07 14:56:58 +02:00
viewOpen : function ( ) {
2013-02-22 15:41:12 -05:00
return this . get ( 'composeState' ) === OPEN ;
2013-04-07 14:56:58 +02:00
} . property ( 'composeState' ) ,
2013-02-22 15:41:12 -05:00
2013-04-07 14:56:58 +02:00
archetype : function ( ) {
2013-02-22 15:41:12 -05:00
return this . get ( 'archetypes' ) . findProperty ( 'id' , this . get ( 'archetypeId' ) ) ;
2013-04-07 14:56:58 +02:00
} . property ( 'archetypeId' ) ,
2013-02-22 15:41:12 -05:00
2013-04-07 14:56:58 +02:00
archetypeChanged : function ( ) {
2013-02-22 15:41:12 -05:00
return this . set ( 'metaData' , Em . Object . create ( ) ) ;
2013-04-07 14:56:58 +02:00
} . observes ( 'archetype' ) ,
2013-02-22 15:41:12 -05:00
2013-04-07 14:56:58 +02:00
editTitle : function ( ) {
2013-02-22 15:41:12 -05:00
if ( this . get ( 'creatingTopic' ) || this . get ( 'creatingPrivateMessage' ) ) return true ;
if ( this . get ( 'editingPost' ) && this . get ( 'post.post_number' ) === 1 ) return true ;
return false ;
2013-04-07 14:56:58 +02:00
} . property ( 'editingPost' , 'creatingTopic' , 'post.post_number' ) ,
2013-02-22 15:41:12 -05:00
2013-05-07 14:25:41 -04:00
showAdminOptions : function ( ) {
if ( this . get ( 'creatingTopic' ) && Discourse . get ( 'currentUser.staff' ) ) return true ;
return false ;
} . property ( 'editTitle' ) ,
2013-02-22 15:41:12 -05:00
togglePreview : function ( ) {
this . toggleProperty ( 'showPreview' ) ;
2013-05-07 12:34:47 +02:00
Discourse . KeyValueStore . set ( { key : 'composer.showPreview' , value : this . get ( 'showPreview' ) } ) ;
2013-02-22 15:41:12 -05:00
} ,
// Import a quote from the post
importQuote : function ( ) {
2013-03-13 18:37:45 -04:00
var post = this . get ( 'post' ) ;
// If we don't have a post, check the topic for the first one
2013-02-22 15:41:12 -05:00
if ( ! post ) {
2013-03-13 18:37:45 -04:00
var posts = this . get ( 'topic.posts' ) ;
2013-02-22 15:41:12 -05:00
if ( posts && posts . length > 0 ) {
post = posts [ 0 ] ;
}
}
2013-03-13 18:37:45 -04:00
2013-02-22 15:41:12 -05:00
if ( post ) {
this . set ( 'loading' , true ) ;
2013-03-13 18:37:45 -04:00
var composer = this ;
2013-03-14 14:45:29 -04:00
Discourse . Post . load ( post . get ( 'id' ) ) . then ( function ( result ) {
2013-03-13 18:37:45 -04:00
composer . appendText ( Discourse . BBCode . buildQuoteBBCode ( post , result . get ( 'raw' ) ) ) ;
2013-03-14 14:45:29 -04:00
composer . set ( 'loading' , false ) ;
2013-02-22 15:41:12 -05:00
} ) ;
}
} ,
appendText : function ( text ) {
2013-03-13 18:37:45 -04:00
this . set ( 'reply' , ( this . get ( 'reply' ) || '' ) + text ) ;
2013-02-22 15:41:12 -05:00
} ,
// Determine the appropriate title for this action
2013-04-07 14:56:58 +02:00
actionTitle : function ( ) {
2013-03-12 13:34:27 -04:00
var topic = this . get ( 'topic' ) ;
2013-03-12 14:54:05 -04:00
var postLink , topicLink ;
2013-02-22 15:41:12 -05:00
if ( topic ) {
2013-03-12 13:34:27 -04:00
var postNumber = this . get ( 'post.post_number' ) ;
2013-03-12 14:41:27 +01:00
postLink = "<a href='" + ( topic . get ( 'url' ) ) + "/" + postNumber + "'>" +
2013-03-12 13:34:27 -04:00
Em . String . i18n ( "post.post_number" , { number : postNumber } ) + "</a>" ;
2013-03-12 14:42:52 -04:00
topicLink = "<a href='" + ( topic . get ( 'url' ) ) + "'> " + ( Handlebars . Utils . escapeExpression ( topic . get ( 'title' ) ) ) + "</a>" ;
2013-02-22 15:41:12 -05:00
}
2013-03-12 13:34:27 -04:00
2013-03-13 12:00:38 -04:00
var postDescription ,
post = this . get ( 'post' ) ;
if ( post ) {
postDescription = Em . String . i18n ( 'post.' + this . get ( 'action' ) , {
link : postLink ,
replyAvatar : Discourse . Utilities . tinyAvatar ( post . get ( 'username' ) ) ,
username : this . get ( 'post.username' )
2013-03-12 13:34:27 -04:00
} ) ;
2013-03-13 12:00:38 -04:00
var replyUsername = post . get ( 'reply_to_user.username' ) ;
if ( replyUsername && this . get ( 'action' ) === EDIT ) {
postDescription += " " + Em . String . i18n ( "post.in_reply_to" ) + " " +
Discourse . Utilities . tinyAvatar ( replyUsername ) + " " + replyUsername ;
}
2013-03-12 13:34:27 -04:00
}
2013-02-22 15:41:12 -05:00
switch ( this . get ( 'action' ) ) {
2013-04-07 14:56:58 +02:00
case PRIVATE _MESSAGE : return Em . String . i18n ( 'topic.private_message' ) ;
case CREATE _TOPIC : return Em . String . i18n ( 'topic.create_long' ) ;
2013-02-22 15:41:12 -05:00
case REPLY :
2013-03-12 13:34:27 -04:00
case EDIT :
2013-03-13 12:00:38 -04:00
if ( postDescription ) return postDescription ;
if ( topic ) return Em . String . i18n ( 'post.reply_topic' , { link : topicLink } ) ;
2013-02-22 15:41:12 -05:00
}
2013-03-12 13:34:27 -04:00
2013-04-07 14:56:58 +02:00
} . property ( 'action' , 'post' , 'topic' , 'topic.title' ) ,
2013-02-22 15:41:12 -05:00
2013-04-07 14:56:58 +02:00
toggleText : function ( ) {
2013-03-15 12:56:14 +01:00
return this . get ( 'showPreview' ) ? Em . String . i18n ( 'composer.hide_preview' ) : Em . String . i18n ( 'composer.show_preview' ) ;
2013-04-07 14:56:58 +02:00
} . property ( 'showPreview' ) ,
2013-02-20 13:15:50 -05:00
2013-04-07 14:56:58 +02:00
hidePreview : function ( ) {
2013-02-22 15:41:12 -05:00
return ! this . get ( 'showPreview' ) ;
2013-04-07 14:56:58 +02:00
} . property ( 'showPreview' ) ,
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
// Whether to disable the post button
2013-04-07 14:56:58 +02:00
cantSubmitPost : function ( ) {
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
// Can't submit while loading
if ( this . get ( 'loading' ) ) return true ;
2013-02-20 13:15:50 -05:00
2013-03-19 01:24:10 +01:00
// Title is required when:
// - creating a new topic
// - editing the 1st post
// - creating a private message
if ( this . get ( 'editTitle' ) && this . get ( 'titleLength' ) < Discourse . SiteSettings . min _topic _title _length ) return true ;
// Need at least one user when sending a private message
if ( this . get ( 'creatingPrivateMessage' ) && ( this . get ( 'targetUsernames' ) . trim ( ) + ',' ) . indexOf ( ',' ) === 0 ) return true ;
2013-02-20 13:15:50 -05:00
2013-03-19 01:24:10 +01:00
// reply is always required
2013-03-15 12:56:14 +01:00
if ( this . get ( 'replyLength' ) < Discourse . SiteSettings . min _post _length ) return true ;
2013-05-24 16:49:08 -04:00
if ( ! Discourse . SiteSettings . allow _uncategorized _topics && ! this . get ( 'categoryName' ) ) return true ;
2013-02-22 15:41:12 -05:00
return false ;
2013-05-24 16:49:08 -04:00
} . property ( 'loading' , 'editTitle' , 'titleLength' , 'targetUsernames' , 'replyLength' , 'categoryName' ) ,
2013-02-22 15:41:12 -05:00
// The text for the save button
2013-04-07 14:56:58 +02:00
saveText : function ( ) {
2013-02-22 15:41:12 -05:00
switch ( this . get ( 'action' ) ) {
2013-04-07 14:56:58 +02:00
case EDIT : return Em . String . i18n ( 'composer.save_edit' ) ;
case REPLY : return Em . String . i18n ( 'composer.reply' ) ;
case CREATE _TOPIC : return Em . String . i18n ( 'composer.create_topic' ) ;
case PRIVATE _MESSAGE : return Em . String . i18n ( 'composer.create_pm' ) ;
2013-02-22 15:41:12 -05:00
}
2013-04-07 14:56:58 +02:00
} . property ( 'action' ) ,
2013-02-20 13:15:50 -05:00
2013-04-07 14:56:58 +02:00
hasMetaData : function ( ) {
2013-03-19 01:24:10 +01:00
var metaData = this . get ( 'metaData' ) ;
2013-04-07 14:56:58 +02:00
return metaData ? Em . empty ( Em . keys ( this . get ( 'metaData' ) ) ) : false ;
} . property ( 'metaData' ) ,
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
wouldLoseChanges : function ( ) {
return this . get ( 'reply' ) !== this . get ( 'originalText' ) ;
} ,
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
/ *
Open a composer
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
opts :
action - The action we ' re performing : edit , reply or createTopic
post - The post we ' re replying to , if present
topic - The topic we ' re replying to , if present
quote - If we 're opening a reply from a quote, the quote we' re making
* /
open : function ( opts ) {
2013-03-13 18:37:45 -04:00
var topicId ;
2013-02-22 15:41:12 -05:00
if ( ! opts ) opts = { } ;
this . set ( 'loading' , false ) ;
if ( opts . topic ) {
topicId = opts . topic . get ( 'id' ) ;
}
2013-03-13 18:37:45 -04:00
var replyBlank = ( this . get ( "reply" ) || "" ) === "" ;
var composer = this ;
2013-02-22 15:41:12 -05:00
if ( ! replyBlank &&
( opts . action !== this . get ( 'action' ) || ( ( opts . reply || opts . action === this . EDIT ) && this . get ( 'reply' ) !== this . get ( 'originalText' ) ) ) &&
! opts . tested ) {
opts . tested = true ;
this . cancel ( function ( ) {
2013-03-13 18:37:45 -04:00
return composer . open ( opts ) ;
2013-02-22 15:41:12 -05:00
} ) ;
return ;
}
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
this . set ( 'draftKey' , opts . draftKey ) ;
this . set ( 'draftSequence' , opts . draftSequence ) ;
if ( ! opts . draftKey ) throw 'draft key is required' ;
if ( opts . draftSequence === null ) throw 'draft sequence is required' ;
this . set ( 'composeState' , opts . composerState || OPEN ) ;
this . set ( 'action' , opts . action ) ;
this . set ( 'topic' , opts . topic ) ;
this . set ( 'targetUsernames' , opts . usernames ) ;
if ( opts . post ) {
this . set ( 'post' , opts . post ) ;
if ( ! this . get ( 'topic' ) ) {
this . set ( 'topic' , opts . post . get ( 'topic' ) ) ;
2013-02-20 13:15:50 -05:00
}
2013-02-22 15:41:12 -05:00
}
this . set ( 'categoryName' , opts . categoryName || this . get ( 'topic.category.name' ) ) ;
2013-05-24 11:22:17 -04:00
this . set ( 'archetypeId' , opts . archetypeId || Discourse . Site . instance ( ) . get ( 'default_archetype' ) ) ;
2013-02-22 15:41:12 -05:00
this . set ( 'metaData' , opts . metaData ? Em . Object . create ( opts . metaData ) : null ) ;
this . set ( 'reply' , opts . reply || this . get ( "reply" ) || "" ) ;
if ( opts . postId ) {
this . set ( 'loading' , true ) ;
2013-03-14 14:45:29 -04:00
Discourse . Post . load ( opts . postId ) . then ( function ( result ) {
2013-03-13 18:37:45 -04:00
composer . set ( 'post' , result ) ;
2013-03-14 14:45:29 -04:00
composer . set ( 'loading' , false ) ;
2013-02-20 13:15:50 -05:00
} ) ;
2013-02-22 15:41:12 -05:00
}
// If we are editing a post, load it.
if ( opts . action === EDIT && opts . post ) {
this . set ( 'title' , this . get ( 'topic.title' ) ) ;
this . set ( 'loading' , true ) ;
2013-03-14 14:45:29 -04:00
Discourse . Post . load ( opts . post . get ( 'id' ) ) . then ( function ( result ) {
2013-03-13 18:37:45 -04:00
composer . set ( 'reply' , result . get ( 'raw' ) ) ;
composer . set ( 'originalText' , composer . get ( 'reply' ) ) ;
composer . set ( 'loading' , false ) ;
2013-02-22 15:41:12 -05:00
} ) ;
}
if ( opts . title ) {
this . set ( 'title' , opts . title ) ;
}
if ( opts . draft ) {
this . set ( 'originalText' , '' ) ;
} else if ( opts . reply ) {
this . set ( 'originalText' , this . get ( 'reply' ) ) ;
}
return false ;
} ,
save : function ( opts ) {
2013-05-24 12:25:28 -04:00
if ( ! this . get ( 'cantSubmitPost' ) ) {
return this . get ( 'editingPost' ) ? this . editPost ( opts ) : this . createPost ( opts ) ;
}
2013-02-22 15:41:12 -05:00
} ,
// When you edit a post
editPost : function ( opts ) {
2013-03-13 18:37:45 -04:00
var post = this . get ( 'post' ) ;
var oldCooked = post . get ( 'cooked' ) ;
var composer = this ;
2013-02-22 15:41:12 -05:00
// Update the title if we've changed it
if ( this . get ( 'title' ) && post . get ( 'post_number' ) === 1 ) {
2013-03-13 18:37:45 -04:00
var topic = this . get ( 'topic' ) ;
2013-02-22 15:41:12 -05:00
topic . set ( 'title' , this . get ( 'title' ) ) ;
2013-03-13 18:37:45 -04:00
topic . set ( 'fancy_title' , this . get ( 'title' ) ) ;
2013-02-22 15:41:12 -05:00
topic . set ( 'categoryName' , this . get ( 'categoryName' ) ) ;
topic . save ( ) ;
}
2013-03-13 18:37:45 -04:00
2013-02-22 15:41:12 -05:00
post . set ( 'raw' , this . get ( 'reply' ) ) ;
post . set ( 'imageSizes' , opts . imageSizes ) ;
post . set ( 'cooked' , $ ( '#wmd-preview' ) . html ( ) ) ;
this . set ( 'composeState' , CLOSED ) ;
2013-03-13 18:37:45 -04:00
2013-03-14 14:45:29 -04:00
return Ember . Deferred . promise ( function ( promise ) {
post . save ( function ( savedPost ) {
var posts = composer . get ( 'topic.posts' ) ;
// perhaps our post came from elsewhere eg. draft
var idx = - 1 ;
var postNumber = post . get ( 'post_number' ) ;
posts . each ( function ( p , i ) {
if ( p . get ( 'post_number' ) === postNumber ) {
idx = i ;
}
} ) ;
if ( idx > - 1 ) {
savedPost . set ( 'topic' , composer . get ( 'topic' ) ) ;
posts . replace ( idx , 1 , [ savedPost ] ) ;
promise . resolve ( { post : post } ) ;
composer . set ( 'topic.draft_sequence' , savedPost . draft _sequence ) ;
2013-02-20 13:15:50 -05:00
}
2013-03-14 14:45:29 -04:00
} , function ( error ) {
2013-05-06 14:44:19 -04:00
var response = $ . parseJSON ( error . responseText ) ;
if ( response && response . errors ) {
2013-05-07 10:33:04 -04:00
promise . reject ( response . errors [ 0 ] ) ;
2013-05-06 14:44:19 -04:00
} else {
promise . reject ( Em . String . i18n ( 'generic_error' ) ) ;
}
2013-03-14 14:45:29 -04:00
post . set ( 'cooked' , oldCooked ) ;
2013-05-06 14:44:19 -04:00
composer . set ( 'composeState' , OPEN ) ;
2013-02-22 15:41:12 -05:00
} ) ;
} ) ;
} ,
// Create a new Post
createPost : function ( opts ) {
2013-03-14 14:45:29 -04:00
var post = this . get ( 'post' ) ,
2013-03-13 13:59:07 -04:00
topic = this . get ( 'topic' ) ,
currentUser = Discourse . get ( 'currentUser' ) ,
addedToStream = false ;
2013-03-27 17:40:35 -04:00
// The post number we'll probably get from the server
var probablePostNumber = this . get ( 'topic.highest_post_number' ) + 1 ;
2013-03-13 13:59:07 -04:00
// Build the post object
var createdPost = Discourse . Post . create ( {
raw : this . get ( 'reply' ) ,
title : this . get ( 'title' ) ,
category : this . get ( 'categoryName' ) ,
topic _id : this . get ( 'topic.id' ) ,
reply _to _post _number : post ? post . get ( 'post_number' ) : null ,
imageSizes : opts . imageSizes ,
2013-03-27 17:40:35 -04:00
post _number : probablePostNumber ,
index : probablePostNumber ,
2013-03-13 13:59:07 -04:00
cooked : $ ( '#wmd-preview' ) . html ( ) ,
reply _count : 0 ,
display _username : currentUser . get ( 'name' ) ,
username : currentUser . get ( 'username' ) ,
2013-04-17 11:41:22 -04:00
user _id : currentUser . get ( 'id' ) ,
2013-03-13 13:59:07 -04:00
metaData : this . get ( 'metaData' ) ,
archetype : this . get ( 'archetypeId' ) ,
2013-05-24 11:22:17 -04:00
post _type : Discourse . Site . instance ( ) . get ( 'post_types.regular' ) ,
2013-03-13 13:59:07 -04:00
target _usernames : this . get ( 'targetUsernames' ) ,
actions _summary : Em . A ( ) ,
moderator : currentUser . get ( 'moderator' ) ,
yours : true ,
2013-05-07 14:25:41 -04:00
newPost : true ,
auto _close _days : this . get ( 'auto_close_days' )
2013-03-13 13:59:07 -04:00
} ) ;
2013-02-22 15:41:12 -05:00
// If we're in a topic, we can append the post instantly.
if ( topic ) {
// Increase the reply count
if ( post ) {
post . set ( 'reply_count' , ( post . get ( 'reply_count' ) || 0 ) + 1 ) ;
2013-02-20 13:15:50 -05:00
}
2013-02-22 15:41:12 -05:00
topic . set ( 'posts_count' , topic . get ( 'posts_count' ) + 1 ) ;
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
// Update last post
topic . set ( 'last_posted_at' , new Date ( ) ) ;
topic . set ( 'highest_post_number' , createdPost . get ( 'post_number' ) ) ;
topic . set ( 'last_poster' , Discourse . get ( 'currentUser' ) ) ;
2013-03-27 17:40:35 -04:00
topic . set ( 'filtered_posts_count' , topic . get ( 'filtered_posts_count' ) + 1 ) ;
2013-02-20 13:15:50 -05:00
2013-02-22 15:41:12 -05:00
// Set the topic view for the new post
createdPost . set ( 'topic' , topic ) ;
createdPost . set ( 'created_at' , new Date ( ) ) ;
// If we're near the end of the topic, load new posts
2013-03-13 13:59:07 -04:00
var lastPost = topic . posts . last ( ) ;
2013-02-22 15:41:12 -05:00
if ( lastPost ) {
2013-03-13 13:59:07 -04:00
var diff = topic . get ( 'highest_post_number' ) - lastPost . get ( 'post_number' ) ;
2013-02-22 15:41:12 -05:00
// If the new post is within a threshold of the end of the topic,
// add it and scroll there instead of adding the link.
if ( diff < 5 ) {
createdPost . set ( 'scrollToAfterInsert' , createdPost . get ( 'post_number' ) ) ;
topic . pushPosts ( [ createdPost ] ) ;
addedToStream = true ;
2013-02-20 13:15:50 -05:00
}
}
2013-02-22 15:41:12 -05:00
}
// Save callback
2013-03-13 13:59:07 -04:00
var composer = this ;
2013-03-14 14:45:29 -04:00
return Ember . Deferred . promise ( function ( promise ) {
createdPost . save ( function ( result ) {
var addedPost = false ,
saving = true ;
2013-03-27 17:40:35 -04:00
2013-03-14 14:45:29 -04:00
createdPost . updateFromSave ( result ) ;
if ( topic ) {
// It's no longer a new post
createdPost . set ( 'newPost' , false ) ;
topic . set ( 'draft_sequence' , result . draft _sequence ) ;
} else {
// We created a new topic, let's show it.
composer . set ( 'composeState' , CLOSED ) ;
saving = false ;
}
2013-03-27 17:40:35 -04:00
2013-03-14 14:45:29 -04:00
composer . set ( 'reply' , '' ) ;
composer . set ( 'createdPost' , createdPost ) ;
if ( addedToStream ) {
composer . set ( 'composeState' , CLOSED ) ;
} else if ( saving ) {
composer . set ( 'composeState' , SAVING ) ;
}
return promise . resolve ( { post : result } ) ;
} , function ( error ) {
// If an error occurs
if ( topic ) {
topic . posts . removeObject ( createdPost ) ;
2013-03-27 17:40:35 -04:00
topic . set ( 'filtered_posts_count' , topic . get ( 'filtered_posts_count' ) - 1 ) ;
2013-03-14 14:45:29 -04:00
}
promise . reject ( $ . parseJSON ( error . responseText ) . errors [ 0 ] ) ;
composer . set ( 'composeState' , OPEN ) ;
} ) ;
2013-02-22 15:41:12 -05:00
} ) ;
} ,
saveDraft : function ( ) {
2013-03-16 18:14:54 +01:00
// Do not save when drafts are disabled
2013-02-22 15:41:12 -05:00
if ( this . get ( 'disableDrafts' ) ) return ;
2013-03-16 18:14:54 +01:00
// Do not save when there is no reply
2013-02-22 15:41:12 -05:00
if ( ! this . get ( 'reply' ) ) return ;
2013-03-16 18:14:54 +01:00
// Do not save when the reply's length is too small
2013-02-28 23:58:13 +01:00
if ( this . get ( 'replyLength' ) < Discourse . SiteSettings . min _post _length ) return ;
2013-02-22 15:41:12 -05:00
2013-03-13 18:37:45 -04:00
var data = {
2013-02-22 15:41:12 -05:00
reply : this . get ( 'reply' ) ,
action : this . get ( 'action' ) ,
title : this . get ( 'title' ) ,
categoryName : this . get ( 'categoryName' ) ,
postId : this . get ( 'post.id' ) ,
archetypeId : this . get ( 'archetypeId' ) ,
metaData : this . get ( 'metaData' ) ,
usernames : this . get ( 'targetUsernames' )
} ;
this . set ( 'draftStatus' , Em . String . i18n ( 'composer.saving_draft_tip' ) ) ;
2013-03-13 18:37:45 -04:00
var composer = this ;
2013-04-07 14:56:58 +02:00
// try to save the draft
return Discourse . Draft . save ( this . get ( 'draftKey' ) , this . get ( 'draftSequence' ) , data )
. then ( function ( ) {
composer . set ( 'draftStatus' , Em . String . i18n ( 'composer.saved_draft_tip' ) ) ;
} , function ( ) {
composer . set ( 'draftStatus' , Em . String . i18n ( 'composer.drafts_offline' ) ) ;
} ) ;
2013-02-22 15:41:12 -05:00
} ,
2013-04-28 02:37:53 +02:00
flashDraftStatusForNewUser : function ( ) {
var $draftStatus = $ ( '#draft-status' ) ;
if ( Discourse . get ( 'currentUser.trust_level' ) === 0 ) {
$draftStatus . toggleClass ( 'flash' , true ) ;
setTimeout ( function ( ) { $draftStatus . removeClass ( 'flash' ) ; } , 250 ) ;
}
} ,
2013-04-07 14:56:58 +02:00
updateDraftStatus : function ( ) {
var $title = $ ( '#reply-title' ) ,
$reply = $ ( '#wmd-input' ) ;
2013-03-15 12:56:14 +01:00
// 'title' is focused
2013-04-07 14:56:58 +02:00
if ( $title . is ( ':focus' ) ) {
var titleDiff = this . get ( 'missingTitleCharacters' ) ;
2013-03-15 12:56:14 +01:00
if ( titleDiff > 0 ) {
2013-04-28 02:37:53 +02:00
this . flashDraftStatusForNewUser ( ) ;
2013-03-15 12:56:14 +01:00
return this . set ( 'draftStatus' , Em . String . i18n ( 'composer.min_length.need_more_for_title' , { n : titleDiff } ) ) ;
}
// 'reply' is focused
2013-04-07 14:56:58 +02:00
} else if ( $reply . is ( ':focus' ) ) {
var replyDiff = this . get ( 'missingReplyCharacters' ) ;
2013-03-15 12:56:14 +01:00
if ( replyDiff > 0 ) {
return this . set ( 'draftStatus' , Em . String . i18n ( 'composer.min_length.need_more_for_reply' , { n : replyDiff } ) ) ;
}
2013-02-20 13:15:50 -05:00
}
2013-04-07 14:56:58 +02:00
2013-03-15 12:56:14 +01:00
// hide the counters if the currently focused text field is OK
this . set ( 'draftStatus' , null ) ;
2013-02-28 23:58:13 +01:00
2013-04-07 14:56:58 +02:00
} . observes ( 'missingTitleCharacters' , 'missingReplyCharacters' ) ,
/ * *
Number of missing characters in the title until valid .
@ property missingTitleCharacters
* * /
missingTitleCharacters : function ( ) {
return Discourse . SiteSettings . min _topic _title _length - this . get ( 'titleLength' ) ;
} . property ( 'titleLength' ) ,
/ * *
Number of missing characters in the reply until valid .
@ property missingReplyCharacters
* * /
missingReplyCharacters : function ( ) {
return Discourse . SiteSettings . min _post _length - this . get ( 'replyLength' ) ;
} . property ( 'replyLength' ) ,
2013-02-22 15:41:12 -05:00
2013-03-15 12:56:14 +01:00
/ * *
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' ) ,
2013-02-28 23:58:13 +01:00
/ * *
2013-03-12 23:54:29 +01:00
Computes the length of the reply minus the quote ( s ) and non - significant whitespaces
2013-02-28 23:58:13 +01:00
@ property replyLength
* * /
replyLength : function ( ) {
2013-03-15 12:56:14 +01:00
var reply = this . get ( 'reply' ) || "" ;
2013-02-28 23:58:13 +01:00
while ( Discourse . BBCode . QUOTE _REGEXP . test ( reply ) ) { reply = reply . replace ( Discourse . BBCode . QUOTE _REGEXP , "" ) ; }
2013-03-12 23:54:29 +01:00
return reply . replace ( /\s+/img , " " ) . trim ( ) . length ;
2013-05-15 15:19:41 -04:00
} . property ( 'reply' )
2013-02-28 23:58:13 +01:00
2013-02-22 15:41:12 -05:00
} ) ;
Discourse . Composer . reopenClass ( {
open : function ( opts ) {
2013-02-28 23:58:13 +01:00
var composer = Discourse . Composer . create ( ) ;
2013-02-22 15:41:12 -05:00
composer . open ( opts ) ;
return composer ;
} ,
loadDraft : function ( draftKey , draftSequence , draft , topic ) {
var composer ;
try {
if ( draft && typeof draft === 'string' ) {
draft = JSON . parse ( draft ) ;
2013-02-20 13:15:50 -05:00
}
2013-02-22 15:41:12 -05:00
} catch ( error ) {
draft = null ;
Discourse . Draft . clear ( draftKey , draftSequence ) ;
}
if ( draft && ( ( draft . title && draft . title !== '' ) || ( draft . reply && draft . reply !== '' ) ) ) {
composer = this . open ( {
draftKey : draftKey ,
draftSequence : draftSequence ,
topic : topic ,
action : draft . action ,
title : draft . title ,
categoryName : draft . categoryName ,
postId : draft . postId ,
archetypeId : draft . archetypeId ,
reply : draft . reply ,
metaData : draft . metaData ,
usernames : draft . usernames ,
draft : true ,
composerState : DRAFT
} ) ;
}
return composer ;
} ,
// The status the compose view can have
CLOSED : CLOSED ,
SAVING : SAVING ,
OPEN : OPEN ,
DRAFT : DRAFT ,
// The actions the composer can take
CREATE _TOPIC : CREATE _TOPIC ,
PRIVATE _MESSAGE : PRIVATE _MESSAGE ,
REPLY : REPLY ,
EDIT : EDIT ,
// Draft key
REPLY _AS _NEW _TOPIC _KEY : REPLY _AS _NEW _TOPIC _KEY
} ) ;