diff --git a/app/assets/javascripts/discourse/components/quote-button.js.es6 b/app/assets/javascripts/discourse/components/quote-button.js.es6
index 77a5c8192a2..97de8f927d8 100644
--- a/app/assets/javascripts/discourse/components/quote-button.js.es6
+++ b/app/assets/javascripts/discourse/components/quote-button.js.es6
@@ -1,4 +1,3 @@
-import computed from 'ember-addons/ember-computed-decorators';
 import { selectedText } from 'discourse/lib/utilities';
 
 // we don't want to deselect when we click on buttons that use it
@@ -10,17 +9,22 @@ function willQuote(e) {
 export default Ember.Component.extend({
   classNames: ['quote-button'],
   classNameBindings: ['visible'],
-
-  @computed('quoteState.buffer')
-  visible: buffer => buffer && buffer.length > 0,
+  visible: false,
 
   _isMouseDown: false,
   _reselected: false,
 
+  _hideButton() {
+    this.get('quoteState').clear();
+    this.set('visible', false);
+  },
+
   _selectionChanged() {
+    const quoteState = this.get('quoteState');
+
     const selection = window.getSelection();
     if (selection.isCollapsed) {
-      if (this.get("visible")) this.sendAction("deselectText");
+      if (this.get("visible")) { this._hideButton(); }
       return;
     }
 
@@ -34,12 +38,13 @@ export default Ember.Component.extend({
       postId = postId || $ancestor.closest('.boxed, .reply').data('post-id');
 
       if ($ancestor.closest(".contents").length === 0 || !postId) {
-        if (this.get("visible")) this.sendAction("deselectText");
+        if (this.get("visible")) { this._hideButton(); }
         return;
       }
     }
 
-    this.get("quoteState").setProperties({ postId, buffer: selectedText() });
+    quoteState.selected(postId, selectedText());
+    this.set('visible', quoteState.buffer.length > 0);
 
     // on Desktop, shows the button at the beginning of the selection
     // on Mobile, shows the button at the end of the selection
@@ -97,11 +102,11 @@ export default Ember.Component.extend({
     const wait = (isWinphone || isAndroid) ? 250 : 25;
     const onSelectionChanged = _.debounce(() => this._selectionChanged(), wait);
 
-    $(document).on("mousedown.quote-button", (e) => {
+    $(document).on("mousedown.quote-button", e => {
       this._isMouseDown = true;
       this._reselected = false;
       if (!willQuote(e)) {
-        this.sendAction("deselectText");
+        this._hideButton();
       }
     }).on("mouseup.quote-button", () => {
       this._isMouseDown = false;
@@ -120,7 +125,8 @@ export default Ember.Component.extend({
   },
 
   click() {
-    this.sendAction("selectText");
+    const { postId, buffer } = this.get('quoteState');
+    this.attrs.selectText(postId, buffer).then(() => this._hideButton());
     return false;
   }
 });
diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6
index ef4dfad0b63..89d11a01fc7 100644
--- a/app/assets/javascripts/discourse/controllers/topic.js.es6
+++ b/app/assets/javascripts/discourse/controllers/topic.js.es6
@@ -11,6 +11,7 @@ import { categoryBadgeHTML } from 'discourse/helpers/category-link';
 import Post from 'discourse/models/post';
 import debounce from 'discourse/lib/debounce';
 import isElementInViewport from "discourse/lib/is-element-in-viewport";
+import QuoteState from 'discourse/lib/quote-state';
 
 export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
   composer: Ember.inject.controller(),
@@ -119,7 +120,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
     this._super();
     this.set('selectedPosts', []);
     this.set('selectedReplies', []);
-    this.set('quoteState', Ember.Object.create({ buffer: null, postId: null }));
+    this.set('quoteState', new QuoteState());
   },
 
   showCategoryChooser: Ember.computed.not("model.isPrivateMessage"),
@@ -167,16 +168,8 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
       this.send('showFeatureTopic');
     },
 
-    deselectText() {
-      this.get('quoteState').setProperties({ buffer: null, postId: null });
-    },
-
-    selectText() {
-      const { postId, buffer } = this.get('quoteState');
-
-      this.send('deselectText');
-
-      this.get('model.postStream').loadPost(postId).then(post => {
+    selectText(postId, buffer) {
+      return this.get('model.postStream').loadPost(postId).then(post => {
         // If we can't create a post, delegate to reply as new topic
         if (!this.get('model.details.can_create_post')) {
           this.send('replyAsNewTopic', post);
@@ -196,15 +189,19 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
 
         // If the composer is associated with a different post, we don't change it.
         const composer = this.get('composer');
-        const composerPost = composer.get('content.post');
+        const composerPost = composer.get('model.post');
         if (composerPost && (composerPost.get('id') !== this.get('post.id'))) {
           composerOpts.post = composerPost;
         }
 
         const quotedText = Quote.build(post, buffer);
         composerOpts.quote = quotedText;
-        if (composer.get('content.viewOpen') || composer.get('content.viewDraft')) {
+        if (composer.get('model.viewOpen')) {
           this.appEvents.trigger('composer:insert-text', quotedText);
+        } else if (composer.get('model.viewDraft')) {
+          const model = composer.get('model');
+          model.set('reply', model.get('reply') + quotedText);
+          composer.send('openIfDraft');
         } else {
           composer.open(composerOpts);
         }
@@ -314,9 +311,10 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
 
       const quoteState = this.get('quoteState');
       const postStream = this.get('model.postStream');
-      const quotedPost = postStream.findLoadedPost(quoteState.get('postId'));
-      const quotedText = Quote.build(quotedPost, quoteState.get('buffer'));
-      this.send('deselectText');
+      const quotedPost = postStream.findLoadedPost(quoteState.postId);
+      const quotedText = Quote.build(quotedPost, quoteState.buffer);
+
+      quoteState.clear();
 
       if (composerController.get('content.topic.id') === topic.get('id') &&
           composerController.get('content.action') === Composer.REPLY) {
@@ -652,10 +650,9 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
     replyAsNewTopic(post) {
       const composerController = this.get('composer');
 
-      const quoteState = this.get('quoteState');
-      post = post || quoteState.get('post');
-      const quotedText = Quote.build(post, quoteState.get('buffer'));
-      this.send('deselectText');
+      const { quoteState } = this;
+      const quotedText = Quote.build(post, quoteState.buffer);
+      quoteState.clear();
 
       composerController.open({
         action: Composer.CREATE_TOPIC,
diff --git a/app/assets/javascripts/discourse/lib/quote-state.js.es6 b/app/assets/javascripts/discourse/lib/quote-state.js.es6
new file mode 100644
index 00000000000..db1e1826fb1
--- /dev/null
+++ b/app/assets/javascripts/discourse/lib/quote-state.js.es6
@@ -0,0 +1,15 @@
+export default class QuoteState {
+  constructor() {
+    this.clear();
+  }
+
+  selected(postId, buffer) {
+    this.postId = postId;
+    this.buffer = buffer;
+  }
+
+  clear() {
+    this.buffer = '';
+    this.postId = null;
+  }
+}
diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6
index 794c432a7b6..9cda61f8d7c 100644
--- a/app/assets/javascripts/discourse/routes/topic.js.es6
+++ b/app/assets/javascripts/discourse/routes/topic.js.es6
@@ -117,7 +117,6 @@ const TopicRoute = Discourse.Route.extend({
 
     willTransition() {
       this._super();
-      this.controllerFor("topic").send('deselectText');
       Em.run.cancel(scheduledReplace);
       isTransitioning = true;
       return true;
@@ -207,6 +206,7 @@ const TopicRoute = Discourse.Route.extend({
 
     // close the multi select when switching topics
     controller.set('multiSelect', false);
+    controller.get('quoteState').clear();
 
     this.controllerFor('composer').set('topic', model);
     this.topicTrackingState.trackIncoming('all');
diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs
index 23d43fb907f..bd02891d6bc 100644
--- a/app/assets/javascripts/discourse/templates/topic.hbs
+++ b/app/assets/javascripts/discourse/templates/topic.hbs
@@ -273,8 +273,6 @@
   {{share-popup topic=model replyAsNewTopic="replyAsNewTopic"}}
 
   {{#if currentUser.enable_quoting}}
-    {{quote-button quoteState=quoteState
-                   selectText="selectText"
-                   deselectText="deselectText"}}
+    {{quote-button quoteState=quoteState selectText=(action "selectText")}}
   {{/if}}
 {{/discourse-topic}}