diff --git a/app/assets/javascripts/discourse/components/composer-body.js.es6 b/app/assets/javascripts/discourse/components/composer-body.js.es6
index e9e4552a2b4..1078c2d7ef9 100644
--- a/app/assets/javascripts/discourse/components/composer-body.js.es6
+++ b/app/assets/javascripts/discourse/components/composer-body.js.es6
@@ -3,8 +3,9 @@ import Composer from 'discourse/models/composer';
import afterTransition from 'discourse/lib/after-transition';
import positioningWorkaround from 'discourse/lib/safari-hacks';
import { headerHeight } from 'discourse/components/site-header';
+import KeyEnterEscape from 'discourse/mixins/key-enter-escape';
-export default Ember.Component.extend({
+export default Ember.Component.extend(KeyEnterEscape, {
elementId: 'reply-control',
classNameBindings: ['composer.creatingPrivateMessage:private-message',
@@ -65,17 +66,6 @@ export default Ember.Component.extend({
}, 1000);
},
- keyDown(e) {
- if (e.which === 27) {
- this.sendAction('cancelled');
- return false;
- } else if (e.which === 13 && (e.ctrlKey || e.metaKey)) {
- // CTRL+ENTER or CMD+ENTER
- this.sendAction('save');
- return false;
- }
- },
-
@observes('composeState')
disableFullscreen() {
if (this.get('composeState') !== Composer.OPEN && positioningWorkaround.blur) {
diff --git a/app/assets/javascripts/discourse/components/topic-title.js.es6 b/app/assets/javascripts/discourse/components/topic-title.js.es6
new file mode 100644
index 00000000000..05c6c37b696
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/topic-title.js.es6
@@ -0,0 +1,5 @@
+import KeyEnterEscape from 'discourse/mixins/key-enter-escape';
+
+export default Ember.Component.extend(KeyEnterEscape, {
+ elementId: 'topic-title',
+});
diff --git a/app/assets/javascripts/discourse/mixins/key-enter-escape.js.es6 b/app/assets/javascripts/discourse/mixins/key-enter-escape.js.es6
new file mode 100644
index 00000000000..f9037da98d1
--- /dev/null
+++ b/app/assets/javascripts/discourse/mixins/key-enter-escape.js.es6
@@ -0,0 +1,14 @@
+// A mixin where hitting ESC calls `cancelled` and ctrl+enter calls `save.
+export default {
+ keyDown(e) {
+ if (e.which === 27) {
+ this.sendAction('cancelled');
+ return false;
+ } else if (e.which === 13 && (e.ctrlKey || e.metaKey)) {
+ // CTRL+ENTER or CMD+ENTER
+ this.sendAction('save');
+ return false;
+ }
+ },
+};
+
diff --git a/app/assets/javascripts/discourse/templates/components/topic-title.hbs b/app/assets/javascripts/discourse/templates/components/topic-title.hbs
new file mode 100644
index 00000000000..8cea0f5c6cc
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/topic-title.hbs
@@ -0,0 +1,6 @@
+
+
+ {{yield}}
+
+ {{plugin-outlet name="topic-title" args=(hash model=model)}}
+
diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs
index 0f745489c9c..35b9ed33752 100644
--- a/app/assets/javascripts/discourse/templates/topic.hbs
+++ b/app/assets/javascripts/discourse/templates/topic.hbs
@@ -10,59 +10,53 @@
{{#if model.postStream.loaded}}
{{#if model.postStream.firstPostPresent}}
-
-
+ {{#topic-title cancelled="cancelEditingTopic" save="finishedEditingTopic"}}
+ {{#if editingTopic}}
+ {{#if model.isPrivateMessage}}
+
{{fa-icon "envelope"}}
+ {{/if}}
-
- {{#if editingTopic}}
- {{#if model.isPrivateMessage}}
+ {{text-field id="edit-title" value=buffered.title maxlength=siteSettings.max_topic_title_length autofocus="true"}}
+ {{#if showCategoryChooser}}
+
+ {{category-chooser valueAttribute="id" value=buffered.category_id}}
+ {{/if}}
+
+ {{#if canEditTags}}
+
+ {{tag-chooser tags=buffered.tags categoryId=buffered.category_id}}
+ {{/if}}
+
+ {{plugin-outlet name="edit-topic" args=(hash model=model buffered=buffered)}}
+
+
+ {{d-button action="finishedEditingTopic" class="btn-primary btn-small submit-edit" icon="check"}}
+ {{d-button action="cancelEditingTopic" class="btn-small cancel-edit" icon="times"}}
+ {{else}}
+
+ {{#unless model.is_warning}}
+
{{fa-icon "envelope"}}
- {{/if}}
+
+ {{/unless}}
- {{text-field id="edit-title" value=buffered.title maxlength=siteSettings.max_topic_title_length autofocus="true"}}
- {{#if showCategoryChooser}}
-
- {{category-chooser valueAttribute="id" value=buffered.category_id}}
- {{/if}}
-
- {{#if canEditTags}}
-
- {{tag-chooser tags=buffered.tags categoryId=buffered.category_id}}
- {{/if}}
-
- {{plugin-outlet name="edit-topic" args=(hash model=model buffered=buffered)}}
-
-
- {{d-button action="finishedEditingTopic" class="btn-primary btn-small submit-edit" icon="check"}}
- {{d-button action="cancelEditingTopic" class="btn-small cancel-edit" icon="times"}}
- {{else}}
-
- {{#unless model.is_warning}}
-
- {{fa-icon "envelope"}}
-
- {{/unless}}
-
- {{#if model.details.loaded}}
- {{topic-status topic=model}}
-
- {{{model.fancyTitle}}}
-
- {{/if}}
-
- {{#if model.details.can_edit}}
- {{fa-icon "pencil"}}
- {{/if}}
-
-
- {{#unless model.isPrivateMessage}}
- {{topic-category topic=model class="topic-category"}}
- {{/unless}}
+ {{#if model.details.loaded}}
+ {{topic-status topic=model}}
+
+ {{{model.fancyTitle}}}
+
{{/if}}
-
- {{plugin-outlet name="topic-title" args=(hash model=model)}}
-
-
+
+ {{#if model.details.can_edit}}
+ {{fa-icon "pencil"}}
+ {{/if}}
+
+
+ {{#unless model.isPrivateMessage}}
+ {{topic-category topic=model class="topic-category"}}
+ {{/unless}}
+ {{/if}}
+ {{/topic-title}}
{{/if}}