mirror of
https://github.com/discourse/discourse.git
synced 2025-04-01 15:35:42 +08:00
displays the number of characters left when editing the topic title
This commit is contained in:
parent
2a5cbd8072
commit
aef014f439
app/assets/javascripts/discourse
controllers
models
templates
views
config/locales
@ -19,12 +19,13 @@ Discourse.ComposerController = Discourse.Controller.extend({
|
|||||||
return this.get('content').importQuote();
|
return this.get('content').importQuote();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resetDraftStatus: function() {
|
||||||
|
this.get('content').resetDraftStatus();
|
||||||
|
},
|
||||||
|
|
||||||
appendText: function(text) {
|
appendText: function(text) {
|
||||||
var c;
|
var c = this.get('content');
|
||||||
c = this.get('content');
|
if (c) return c.appendText(text);
|
||||||
if (c) {
|
|
||||||
return c.appendText(text);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function(force) {
|
save: function(force) {
|
||||||
@ -95,16 +96,11 @@ Discourse.ComposerController = Discourse.Controller.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
checkReplyLength: function() {
|
checkReplyLength: function() {
|
||||||
if (this.present('content.reply')) {
|
this.set('hasReply', this.present('content.reply'));
|
||||||
this.set('hasReply', true);
|
|
||||||
} else {
|
|
||||||
this.set('hasReply', false);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
saveDraft: function() {
|
saveDraft: function() {
|
||||||
var model;
|
var model = this.get('content');
|
||||||
model = this.get('content');
|
|
||||||
if (model) model.saveDraft();
|
if (model) model.saveDraft();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ Discourse.Composer = Discourse.Model.extend({
|
|||||||
this._super();
|
this._super();
|
||||||
var val = Discourse.KeyValueStore.get('composer.showPreview') || 'true';
|
var val = Discourse.KeyValueStore.get('composer.showPreview') || 'true';
|
||||||
this.set('showPreview', val === 'true');
|
this.set('showPreview', val === 'true');
|
||||||
return this.set('archetypeId', Discourse.get('site.default_archetype'));
|
this.set('archetypeId', Discourse.get('site.default_archetype'));
|
||||||
},
|
},
|
||||||
|
|
||||||
creatingTopic: (function() {
|
creatingTopic: (function() {
|
||||||
@ -142,10 +142,7 @@ Discourse.Composer = Discourse.Model.extend({
|
|||||||
}).property('action', 'post', 'topic', 'topic.title'),
|
}).property('action', 'post', 'topic', 'topic.title'),
|
||||||
|
|
||||||
toggleText: (function() {
|
toggleText: (function() {
|
||||||
if (this.get('showPreview')) {
|
return this.get('showPreview') ? Em.String.i18n('composer.hide_preview') : Em.String.i18n('composer.show_preview');
|
||||||
return Em.String.i18n('composer.hide_preview');
|
|
||||||
}
|
|
||||||
return Em.String.i18n('composer.show_preview');
|
|
||||||
}).property('showPreview'),
|
}).property('showPreview'),
|
||||||
|
|
||||||
hidePreview: (function() {
|
hidePreview: (function() {
|
||||||
@ -159,14 +156,11 @@ Discourse.Composer = Discourse.Model.extend({
|
|||||||
if (this.get('loading')) return true;
|
if (this.get('loading')) return true;
|
||||||
|
|
||||||
// Title is required on new posts
|
// Title is required on new posts
|
||||||
if (this.get('creatingTopic')) {
|
if (this.get('creatingTopic') && this.get('titleLength') < Discourse.SiteSettings.min_topic_title_length) return true;
|
||||||
if (this.blank('title')) return true;
|
|
||||||
if (this.get('title').trim().length < Discourse.SiteSettings.min_topic_title_length) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise just reply is required
|
// Otherwise just reply is required
|
||||||
if (this.blank('reply')) return true;
|
if (this.get('replyLength') < Discourse.SiteSettings.min_post_length) return true;
|
||||||
if (this.get('reply').trim().length < Discourse.SiteSettings.min_post_length) return true;
|
|
||||||
return false;
|
return false;
|
||||||
}).property('reply', 'title', 'creatingTopic', 'loading'),
|
}).property('reply', 'title', 'creatingTopic', 'loading'),
|
||||||
|
|
||||||
@ -438,6 +432,7 @@ Discourse.Composer = Discourse.Model.extend({
|
|||||||
saveDraft: function() {
|
saveDraft: function() {
|
||||||
if (this.get('disableDrafts')) return;
|
if (this.get('disableDrafts')) return;
|
||||||
if (!this.get('reply')) return;
|
if (!this.get('reply')) return;
|
||||||
|
if (this.get('titleLength') < Discourse.SiteSettings.min_topic_title_length) return;
|
||||||
if (this.get('replyLength') < Discourse.SiteSettings.min_post_length) return;
|
if (this.get('replyLength') < Discourse.SiteSettings.min_post_length) return;
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
@ -457,28 +452,38 @@ Discourse.Composer = Discourse.Model.extend({
|
|||||||
return Discourse.Draft.save(this.get('draftKey'), this.get('draftSequence'), data).then((function() {
|
return Discourse.Draft.save(this.get('draftKey'), this.get('draftSequence'), data).then((function() {
|
||||||
composer.set('draftStatus', Em.String.i18n('composer.saved_draft_tip'));
|
composer.set('draftStatus', Em.String.i18n('composer.saved_draft_tip'));
|
||||||
}), (function() {
|
}), (function() {
|
||||||
composer.set('draftStatus', 'drafts offline');
|
composer.set('draftStatus', Em.String.i18n('composer.drafts_offline'));
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
resetDraftStatus: (function() {
|
resetDraftStatus: (function() {
|
||||||
var len = Discourse.SiteSettings.min_post_length,
|
// 'title' is focused
|
||||||
replyLength = this.get('replyLength');
|
if ($('#reply-title').is(':focus')) {
|
||||||
|
var titleDiff = Discourse.SiteSettings.min_topic_title_length - this.get('titleLength');
|
||||||
if (replyLength === 0) {
|
if (titleDiff > 0) {
|
||||||
this.set('draftStatus', Em.String.i18n('composer.min_length.at_least', { n: len }));
|
return this.set('draftStatus', Em.String.i18n('composer.min_length.need_more_for_title', { n: titleDiff }));
|
||||||
} else if (replyLength < len) {
|
}
|
||||||
this.set('draftStatus', Em.String.i18n('composer.min_length.more', { n: len - replyLength }));
|
// 'reply' is focused
|
||||||
} else {
|
} else if ($('#wmd-input').is(':focus')) {
|
||||||
this.set('draftStatus', null);
|
var replyDiff = Discourse.SiteSettings.min_post_length - this.get('replyLength');
|
||||||
|
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('reply', 'title'),
|
}).observes('reply', 'title'),
|
||||||
|
|
||||||
blank: function(prop) {
|
/**
|
||||||
var p = this.get(prop);
|
Computes the length of the title minus non-significant whitespaces
|
||||||
return !(p && p.length > 0);
|
|
||||||
},
|
@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
|
Computes the length of the reply minus the quote(s) and non-significant whitespaces
|
||||||
@ -486,8 +491,7 @@ Discourse.Composer = Discourse.Model.extend({
|
|||||||
@property replyLength
|
@property replyLength
|
||||||
**/
|
**/
|
||||||
replyLength: function() {
|
replyLength: function() {
|
||||||
var reply = this.get('reply');
|
var reply = this.get('reply') || "";
|
||||||
if(!reply) reply = "";
|
|
||||||
while (Discourse.BBCode.QUOTE_REGEXP.test(reply)) { reply = reply.replace(Discourse.BBCode.QUOTE_REGEXP, ""); }
|
while (Discourse.BBCode.QUOTE_REGEXP.test(reply)) { reply = reply.replace(Discourse.BBCode.QUOTE_REGEXP, ""); }
|
||||||
return reply.replace(/\s+/img, " ").trim().length;
|
return reply.replace(/\s+/img, " ").trim().length;
|
||||||
}.property('reply')
|
}.property('reply')
|
||||||
@ -547,5 +551,3 @@ Discourse.Composer.reopenClass({
|
|||||||
// Draft key
|
// Draft key
|
||||||
REPLY_AS_NEW_TOPIC_KEY: REPLY_AS_NEW_TOPIC_KEY
|
REPLY_AS_NEW_TOPIC_KEY: REPLY_AS_NEW_TOPIC_KEY
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
{{#if content.editTitle}}
|
{{#if content.editTitle}}
|
||||||
<div class='form-element clearfix'>
|
<div class='form-element clearfix'>
|
||||||
|
|
||||||
{{#if content.creatingPrivateMessage}}
|
{{#if content.creatingPrivateMessage}}
|
||||||
{{view Discourse.TextField id="private-message-users" class="span8" placeholderKey="composer.users_placeholder"}}
|
{{view Discourse.TextField id="private-message-users" class="span8" placeholderKey="composer.users_placeholder"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@ -31,7 +30,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
<div class='wmd-controls'>
|
<div class='wmd-controls'>
|
||||||
<div class='textarea-wrapper'>
|
<div class='textarea-wrapper'>
|
||||||
<div class='wmd-button-bar' id='wmd-button-bar'></div>
|
<div class='wmd-button-bar' id='wmd-button-bar'></div>
|
||||||
@ -43,7 +41,6 @@
|
|||||||
{{#if Discourse.currentUser}}
|
{{#if Discourse.currentUser}}
|
||||||
<a href="#" {{action togglePreview target="controller"}} class='toggle-preview'>{{{content.toggleText}}}</a>
|
<a href="#" {{action togglePreview target="controller"}} class='toggle-preview'>{{{content.toggleText}}}</a>
|
||||||
<div class='saving-draft'></div>
|
<div class='saving-draft'></div>
|
||||||
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -51,7 +48,6 @@
|
|||||||
<div class='submit-panel'>
|
<div class='submit-panel'>
|
||||||
<button {{action save target="controller"}} tabindex="3" {{bindAttr disabled="content.cantSubmitPost"}} class='btn btn-primary create'>{{view.content.saveText}}</button>
|
<button {{action save target="controller"}} tabindex="3" {{bindAttr disabled="content.cantSubmitPost"}} class='btn btn-primary create'>{{view.content.saveText}}</button>
|
||||||
<a href='#' {{action cancel target="controller"}} class='cancel' tabindex="4">{{i18n cancel}}</a>
|
<a href='#' {{action cancel target="controller"}} class='cancel' tabindex="4">{{i18n cancel}}</a>
|
||||||
|
|
||||||
{{#if view.loadingImage}}
|
{{#if view.loadingImage}}
|
||||||
<div id="image-uploading">
|
<div id="image-uploading">
|
||||||
{{i18n image_selector.uploading_image}} {{view.uploadProgress}}% <a {{action cancelUpload target="view"}}>{{i18n cancel}}</a>
|
{{i18n image_selector.uploading_image}} {{view.uploadProgress}}% <a {{action cancelUpload target="view"}}>{{i18n cancel}}</a>
|
||||||
|
@ -22,8 +22,7 @@ Discourse.ComposerView = Discourse.View.extend({
|
|||||||
educationClosed: null,
|
educationClosed: null,
|
||||||
|
|
||||||
composeState: (function() {
|
composeState: (function() {
|
||||||
var state;
|
var state = this.get('content.composeState');
|
||||||
state = this.get('content.composeState');
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
state = Discourse.Composer.CLOSED;
|
state = Discourse.Composer.CLOSED;
|
||||||
}
|
}
|
||||||
@ -103,8 +102,7 @@ Discourse.ComposerView = Discourse.View.extend({
|
|||||||
}).property('content.composeState', 'content.reply', 'educationClosed', 'educationContents'),
|
}).property('content.composeState', 'content.reply', 'educationClosed', 'educationContents'),
|
||||||
|
|
||||||
newUserEducationVisibilityChanged: (function() {
|
newUserEducationVisibilityChanged: (function() {
|
||||||
var $panel;
|
var $panel = $('#new-user-education');
|
||||||
$panel = $('#new-user-education');
|
|
||||||
if (this.get('newUserEducationVisible')) {
|
if (this.get('newUserEducationVisible')) {
|
||||||
return $panel.slideDown('fast');
|
return $panel.slideDown('fast');
|
||||||
} else {
|
} else {
|
||||||
@ -116,6 +114,11 @@ Discourse.ComposerView = Discourse.View.extend({
|
|||||||
$('#new-user-education').css('bottom', sizePx);
|
$('#new-user-education').css('bottom', sizePx);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
focusIn: (function() {
|
||||||
|
var controller = this.get('controller');
|
||||||
|
if(controller) controller.resetDraftStatus();
|
||||||
|
}),
|
||||||
|
|
||||||
resize: (function() {
|
resize: (function() {
|
||||||
// this still needs to wait on animations, need a clean way to do that
|
// this still needs to wait on animations, need a clean way to do that
|
||||||
var _this = this;
|
var _this = this;
|
||||||
@ -130,15 +133,13 @@ Discourse.ComposerView = Discourse.View.extend({
|
|||||||
}).observes('content.composeState'),
|
}).observes('content.composeState'),
|
||||||
|
|
||||||
keyUp: function(e) {
|
keyUp: function(e) {
|
||||||
var controller;
|
var controller = this.get('controller');
|
||||||
controller = this.get('controller');
|
|
||||||
controller.checkReplyLength();
|
controller.checkReplyLength();
|
||||||
if (e.which === 27) controller.hitEsc();
|
if (e.which === 27) controller.hitEsc();
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
var replyControl;
|
var replyControl = $('#reply-control');
|
||||||
replyControl = $('#reply-control');
|
|
||||||
replyControl.DivResizer({
|
replyControl.DivResizer({
|
||||||
resize: this.resize,
|
resize: this.resize,
|
||||||
onDrag: this.moveNewUserEducation
|
onDrag: this.moveNewUserEducation
|
||||||
|
@ -267,10 +267,11 @@ en:
|
|||||||
saving_draft_tip: "saving"
|
saving_draft_tip: "saving"
|
||||||
saved_draft_tip: "saved"
|
saved_draft_tip: "saved"
|
||||||
saved_local_draft_tip: "saved locally"
|
saved_local_draft_tip: "saved locally"
|
||||||
|
drafts_offline: "drafts offline"
|
||||||
|
|
||||||
min_length:
|
min_length:
|
||||||
at_least: "enter at least {{n}} characters"
|
need_more_for_title: "{{n}} to go for the title"
|
||||||
more: "{{n}} to go..."
|
need_more_for_reply: "{{n}} to go for the reply"
|
||||||
|
|
||||||
save_edit: "Save Edit"
|
save_edit: "Save Edit"
|
||||||
reply_original: "Reply on Original Topic"
|
reply_original: "Reply on Original Topic"
|
||||||
|
@ -271,10 +271,11 @@ fr:
|
|||||||
saving_draft_tip: "sauvegarde..."
|
saving_draft_tip: "sauvegarde..."
|
||||||
saved_draft_tip: "sauvegardé"
|
saved_draft_tip: "sauvegardé"
|
||||||
saved_local_draft_tip: "sauvegardé en local"
|
saved_local_draft_tip: "sauvegardé en local"
|
||||||
|
drafts_offline: "sauvegardé hors ligne"
|
||||||
|
|
||||||
min_length:
|
min_length:
|
||||||
at_least: "Saisir au moins {{n}} caractères"
|
need_more_for_title: "{{n}} caractères restant pour le titre"
|
||||||
more: "{{n}} restants..."
|
need_more_for_reply: "{{n}} caractères restant pour le message"
|
||||||
|
|
||||||
save_edit: "Sauvegarder la modification"
|
save_edit: "Sauvegarder la modification"
|
||||||
reply_original: Répondre à la discussion initiale
|
reply_original: Répondre à la discussion initiale
|
||||||
|
Loading…
x
Reference in New Issue
Block a user