Merge pull request #767 from ZogStriP/refactor-quote-reply

improve & refactor quote reply
This commit is contained in:
Sam 2013-04-24 21:22:50 -07:00
commit 0a13b78c05
3 changed files with 102 additions and 64 deletions

View File

@ -29,17 +29,15 @@ Discourse.QuoteButtonController = Discourse.Controller.extend({
@method selectText
**/
selectText: function(e) {
selectText: function(postId) {
// anonymous users cannot "quote-reply"
if (!Discourse.get('currentUser')) return;
// don't display the "quote-reply" button if we can't create a post
if (!this.get('controllers.topic.content.can_create_post')) return;
var selection = window.getSelection();
// no selections
if (selection.rangeCount === 0) return;
// retrieve the selected range
var range = selection.getRangeAt(0),
cloned = range.cloneRange(),
@ -51,9 +49,17 @@ Discourse.QuoteButtonController = Discourse.Controller.extend({
var selectedText = Discourse.Utilities.selectedText();
if (this.get('buffer') === selectedText) return;
if (this.get('lastSelected') === selectedText) return;
this.set('post', e.context);
// we need to retrieve the post data from the posts collection in the topic controller
var posts = this.get('controllers.topic.posts'),
length = posts.length,
post;
for (var p = 0; p < length; p++) {
if (posts[p].id === postId) { post = posts[p]; break; }
}
this.set('post', post);
this.set('buffer', selectedText);
// collapse the range at the beginning of the selection
@ -117,6 +123,18 @@ Discourse.QuoteButtonController = Discourse.Controller.extend({
}
this.set('buffer', '');
return false;
},
/**
Deselect the currently selected text
@method deselectText
**/
deselectText: function() {
// clear selected text
window.getSelection().removeAllRanges();
// clean up the buffer
this.set('buffer', '');
}
});

View File

@ -43,34 +43,19 @@ Discourse.PostView = Discourse.View.extend({
this.set('context', this.get('content'));
},
mouseDown: function(e) {
this.set('isMouseDown', true);
},
mouseUp: function(e) {
if (this.get('controller.multiSelect') && (e.metaKey || e.ctrlKey)) {
this.toggleProperty('post.selected');
}
if (!Discourse.get('currentUser.enable_quoting')) return;
if ($(e.target).closest('.topic-body').length === 0) return;
var qbc = this.get('controller.controllers.quoteButton');
if (qbc) {
e.context = this.get('post');
qbc.selectText(e);
}
this.set('isMouseDown', false);
},
selectText: (function() {
selectText: function() {
return this.get('post.selected') ? Em.String.i18n('topic.multi_select.selected', { count: this.get('controller.selectedCount') }) : Em.String.i18n('topic.multi_select.select');
}).property('post.selected', 'controller.selectedCount'),
}.property('post.selected', 'controller.selectedCount'),
repliesHidden: (function() {
repliesHidden: function() {
return !this.get('repliesShown');
}).property('repliesShown'),
}.property('repliesShown'),
// Click on the replies button
showReplies: function() {
@ -262,30 +247,5 @@ Discourse.PostView = Discourse.View.extend({
if (controller && controller.postRendered) {
controller.postRendered(post);
}
// make the selection work under iOS
// "selectionchange" event is only supported in IE, Safari & Chrome
var postView = this;
$(document).on('selectionchange', function(e) {
// quoting as been disabled by the user
if (!Discourse.get('currentUser.enable_quoting')) return;
// there is no need to handle this event when the mouse is down
if (postView.get('isMouseDown')) return;
// find out whether we currently are selecting inside a post
var closestPosts = $(window.getSelection().anchorNode).closest('.topic-post');
if (closestPosts.length === 0) return;
// this event is bound for every posts in the topic, but is triggered on "document"
// we should therefore filter the event to only the right post
if (closestPosts[0].id !== postView.elementId) return;
var qbc = postView.get('controller.controllers.quoteButton');
if (qbc) {
e.context = postView.get('post');
qbc.selectText(e);
}
});
},
willDestroyElement: function() {
$(document).off('selectionchange');
}
});

View File

@ -8,32 +8,92 @@
**/
Discourse.QuoteButtonView = Discourse.View.extend({
classNames: ['quote-button'],
classNameBindings: ['hasBuffer'],
classNameBindings: ['visible'],
isMouseDown: false,
/**
Determines whether the pop-up quote button should be visible.
The button is visible whenever there is something in the buffer
(ie. something has been selected)
@property visible
**/
visible: function() {
return this.present('controller.buffer');
}.property('controller.buffer'),
/**
Renders the pop-up quote button.
@method render
**/
render: function(buffer) {
buffer.push('<i class="icon-quote-right"></i>&nbsp;&nbsp;');
buffer.push(Em.String.i18n("post.quote_reply"));
},
hasBuffer: function() {
return this.present('controller.buffer') ? 'visible' : null;
}.property('controller.buffer'),
willDestroyElement: function() {
$(document).off("mousedown.quote-button");
},
/**
Binds to the following global events:
- `mousedown` to clear the quote button if they click elsewhere.
- `mouseup` to trigger the display of the quote button.
- `selectionchange` to make the selection work under iOS
@method didInsertElement
**/
didInsertElement: function() {
// Clear quote button if they click elsewhere
var quoteButtonView = this;
$(document).on("mousedown.quote-button", function(e) {
if ($(e.target).hasClass('quote-button')) return;
if ($(e.target).hasClass('create')) return;
quoteButtonView.set('controller.lastSelected', quoteButtonView.get('controller.buffer'));
quoteButtonView.set('controller.buffer', '');
var controller = this.get('controller'),
view = this;
$(document)
.on("mousedown.quote-button", function(e) {
view.set('isMouseDown', true);
if ($(e.target).hasClass('quote-button') || $(e.target).hasClass('create')) return;
controller.deselectText();
})
.on('mouseup.quote-button', function(e) {
view.selectText(e.target, controller);
view.set('isMouseDown', false);
})
.on('selectionchange', function() {
// there is no need to handle this event when the mouse is down
if (view.get('isMouseDown')) return;
// `selection.anchorNode` is used as a target
view.selectText(window.getSelection().anchorNode, controller);
});
},
/**
Selects the text
@method selectText
**/
selectText: function(target, controller) {
var $target = $(target);
// quoting as been disabled by the user
if (!Discourse.get('currentUser.enable_quoting')) return;
// retrieve the post id from the DOM
var postId = $target.closest('.boxed').data('post-id');
// select the text
if (postId) controller.selectText(postId);
},
/**
Unbinds from global `mouseup, mousedown, selectionchange` events
@method willDestroyElement
**/
willDestroyElement: function() {
$(document)
.off("mousedown.quote-button")
.off("mouseup.quote-button")
.off("selectionchange");
},
/**
Quote the selected text when clicking on the quote button.
@method click
**/
click: function(e) {
e.stopPropagation();
return this.get('controller').quoteText(e);