Show quote button when post text is selected

closes #19 closes flarum/core#320
This commit is contained in:
Sajjad Hasehmian 2016-04-16 00:44:33 +04:30 committed by Toby Zerner
parent 8c280b0b15
commit a05600b91e
7 changed files with 310 additions and 66 deletions

View File

@ -638,48 +638,76 @@ System.register('flarum/mentions/addPostMentionPreviews', ['flarum/extend', 'fla
});;
'use strict';
System.register('flarum/mentions/addPostReplyAction', ['flarum/extend', 'flarum/components/Button', 'flarum/components/CommentPost', 'flarum/utils/DiscussionControls'], function (_export, _context) {
var extend, Button, CommentPost, DiscussionControls;
System.register('flarum/mentions/addPostQuoteButton', ['flarum/extend', 'flarum/components/CommentPost', 'flarum/mentions/components/PostQuoteButton'], function (_export, _context) {
var extend, CommentPost, PostQuoteButton;
function addPostQuoteButton() {
extend(CommentPost.prototype, 'config', function (original, isInitialized) {
var post = this.props.post;
if (isInitialized || post.isHidden() || app.session.user && !post.discussion().canReply()) return;
var $postBody = this.$().find('.Post-body');
// Wrap the quote button in a wrapper element so that we can render
// button into it.
var $container = $('<div class="Post-quoteButtonContainer"></div>');
this.$().after($container).on('mouseup', function (e) {
setTimeout(function () {
var selection = window.getSelection();
if (selection.rangeCount) {
var range = selection.getRangeAt(0);
var parent = range.commonAncestorContainer;
if ($postBody[0] === parent || $.contains($postBody[0], parent)) {
var content = $.trim(selection.toString());
if (content) {
var button = new PostQuoteButton({ post: post, content: content });
m.render($container[0], button.render());
var rect = range.getClientRects()[0];
button.show(rect.left, $(window).scrollTop() + rect.top);
}
}
}
}, 1);
});
});
}
_export('default', addPostQuoteButton);
return {
setters: [function (_flarumExtend) {
extend = _flarumExtend.extend;
}, function (_flarumComponentsCommentPost) {
CommentPost = _flarumComponentsCommentPost.default;
}, function (_flarumMentionsComponentsPostQuoteButton) {
PostQuoteButton = _flarumMentionsComponentsPostQuoteButton.default;
}],
execute: function () {}
};
});;
'use strict';
System.register('flarum/mentions/addPostReplyAction', ['flarum/extend', 'flarum/components/Button', 'flarum/components/CommentPost', 'flarum/mentions/utils/reply'], function (_export, _context) {
var extend, Button, CommentPost, reply;
_export('default', function () {
extend(CommentPost.prototype, 'actionItems', function (items) {
var post = this.props.post;
if (post.isHidden() || app.session.user && !post.discussion().canReply()) return;
function insertMention(component, quote) {
var user = post.user();
var mention = '@' + (user ? user.username() : post.number()) + '#' + post.id() + ' ';
// If the composer is empty, then assume we're starting a new reply.
// In which case we don't want the user to have to confirm if they
// close the composer straight away.
if (!component.content()) {
component.props.originalContent = mention;
}
var cursorPosition = component.editor.getSelectionRange()[0];
var preceding = component.editor.value().slice(0, cursorPosition);
var precedingNewlines = preceding.length == 0 ? 0 : 3 - preceding.match(/(\n{0,2})$/)[0].length;
component.editor.insertAtCursor(Array(precedingNewlines).join('\n') + ( // Insert up to two newlines, depending on preceding whitespace
quote ? '> ' + mention + quote.trim().replace(/\n/g, '\n> ') + '\n\n' : mention));
}
items.add('reply', Button.component({
className: 'Button Button--link',
children: app.translator.trans('flarum-mentions.forum.post.reply_link'),
onclick: function onclick() {
var quote = window.getSelection().toString();
var component = app.composer.component;
if (component && component.props.post && component.props.post.discussion() === post.discussion()) {
insertMention(component, quote);
} else {
DiscussionControls.replyAction.call(post.discussion()).then(function (newComponent) {
return insertMention(newComponent, quote);
});
}
reply(post, quote);
}
}));
});
@ -692,8 +720,8 @@ System.register('flarum/mentions/addPostReplyAction', ['flarum/extend', 'flarum/
Button = _flarumComponentsButton.default;
}, function (_flarumComponentsCommentPost) {
CommentPost = _flarumComponentsCommentPost.default;
}, function (_flarumUtilsDiscussionControls) {
DiscussionControls = _flarumUtilsDiscussionControls.default;
}, function (_flarumMentionsUtilsReply) {
reply = _flarumMentionsUtilsReply.default;
}],
execute: function () {}
};
@ -915,6 +943,75 @@ System.register('flarum/mentions/components/PostMentionedNotification', ['flarum
});;
'use strict';
System.register('flarum/mentions/components/PostQuoteButton', ['flarum/components/Button', 'flarum/utils/extract', 'flarum/mentions/utils/reply'], function (_export, _context) {
var Button, extract, reply, PostQuoteButton;
return {
setters: [function (_flarumComponentsButton) {
Button = _flarumComponentsButton.default;
}, function (_flarumUtilsExtract) {
extract = _flarumUtilsExtract.default;
}, function (_flarumMentionsUtilsReply) {
reply = _flarumMentionsUtilsReply.default;
}],
execute: function () {
PostQuoteButton = function (_Button) {
babelHelpers.inherits(PostQuoteButton, _Button);
function PostQuoteButton() {
babelHelpers.classCallCheck(this, PostQuoteButton);
return babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(PostQuoteButton).apply(this, arguments));
}
babelHelpers.createClass(PostQuoteButton, [{
key: 'view',
value: function view() {
var _this2 = this;
var post = extract(this.props, 'post');
var content = extract(this.props, 'content');
this.props.className = 'Button PostQuoteButton';
this.props.icon = 'quote-left';
this.props.children = app.translator.trans('flarum-mentions.forum.post.quote_button');
this.props.onclick = function () {
_this2.hide();
reply(post, content);
};
this.props.onmousedown = function (e) {
return e.stopPropagation();
};
return babelHelpers.get(Object.getPrototypeOf(PostQuoteButton.prototype), 'view', this).call(this);
}
}, {
key: 'config',
value: function config(isInitialized) {
if (isInitialized) return;
$(document).on('mousedown', this.hide.bind(this));
}
}, {
key: 'show',
value: function show(left, top) {
var $this = this.$();
$this.show().css('top', top - $this.outerHeight() - 5).css('left', left);
}
}, {
key: 'hide',
value: function hide() {
this.$().hide();
}
}]);
return PostQuoteButton;
}(Button);
_export('default', PostQuoteButton);
}
};
});;
'use strict';
System.register('flarum/mentions/components/UserMentionedNotification', ['flarum/components/Notification'], function (_export, _context) {
var Notification, UserMentionedNotification;
return {
@ -964,8 +1061,8 @@ System.register('flarum/mentions/components/UserMentionedNotification', ['flarum
});;
'use strict';
System.register('flarum/mentions/main', ['flarum/extend', 'flarum/app', 'flarum/components/NotificationGrid', 'flarum/utils/string', 'flarum/mentions/addPostMentionPreviews', 'flarum/mentions/addMentionedByList', 'flarum/mentions/addPostReplyAction', 'flarum/mentions/addComposerAutocomplete', 'flarum/mentions/components/PostMentionedNotification', 'flarum/mentions/components/UserMentionedNotification', 'flarum/components/UserPage', 'flarum/components/LinkButton', 'flarum/mentions/components/MentionsUserPage'], function (_export, _context) {
var extend, app, NotificationGrid, getPlainContent, addPostMentionPreviews, addMentionedByList, addPostReplyAction, addComposerAutocomplete, PostMentionedNotification, UserMentionedNotification, UserPage, LinkButton, MentionsUserPage;
System.register('flarum/mentions/main', ['flarum/extend', 'flarum/app', 'flarum/components/NotificationGrid', 'flarum/utils/string', 'flarum/mentions/addPostMentionPreviews', 'flarum/mentions/addMentionedByList', 'flarum/mentions/addPostReplyAction', 'flarum/mentions/addPostQuoteButton', 'flarum/mentions/addComposerAutocomplete', 'flarum/mentions/components/PostMentionedNotification', 'flarum/mentions/components/UserMentionedNotification', 'flarum/components/UserPage', 'flarum/components/LinkButton', 'flarum/mentions/components/MentionsUserPage'], function (_export, _context) {
var extend, app, NotificationGrid, getPlainContent, addPostMentionPreviews, addMentionedByList, addPostReplyAction, addPostQuoteButton, addComposerAutocomplete, PostMentionedNotification, UserMentionedNotification, UserPage, LinkButton, MentionsUserPage;
return {
setters: [function (_flarumExtend) {
extend = _flarumExtend.extend;
@ -981,6 +1078,8 @@ System.register('flarum/mentions/main', ['flarum/extend', 'flarum/app', 'flarum/
addMentionedByList = _flarumMentionsAddMentionedByList.default;
}, function (_flarumMentionsAddPostReplyAction) {
addPostReplyAction = _flarumMentionsAddPostReplyAction.default;
}, function (_flarumMentionsAddPostQuoteButton) {
addPostQuoteButton = _flarumMentionsAddPostQuoteButton.default;
}, function (_flarumMentionsAddComposerAutocomplete) {
addComposerAutocomplete = _flarumMentionsAddComposerAutocomplete.default;
}, function (_flarumMentionsComponentsPostMentionedNotification) {
@ -1009,6 +1108,9 @@ System.register('flarum/mentions/main', ['flarum/extend', 'flarum/app', 'flarum/
// open up the composer and add a post mention to its contents.
addPostReplyAction();
// Show a Quote button when Post text is selected
addPostQuoteButton();
// After typing '@' in the composer, show a dropdown suggesting a bunch of
// posts or users that the user could mention.
addComposerAutocomplete();
@ -1047,4 +1149,49 @@ System.register('flarum/mentions/main', ['flarum/extend', 'flarum/app', 'flarum/
});
}
};
});;
'use strict';
System.register('flarum/mentions/utils/reply', ['flarum/utils/DiscussionControls'], function (_export, _context) {
var DiscussionControls;
function insertMention(post, component, quote) {
var user = post.user();
var mention = '@' + (user ? user.username() : post.number()) + '#' + post.id() + ' ';
// If the composer is empty, then assume we're starting a new reply.
// In which case we don't want the user to have to confirm if they
// close the composer straight away.
if (!component.content()) {
component.props.originalContent = mention;
}
var cursorPosition = component.editor.getSelectionRange()[0];
var preceding = component.editor.value().slice(0, cursorPosition);
var precedingNewlines = preceding.length == 0 ? 0 : 3 - preceding.match(/(\n{0,2})$/)[0].length;
component.editor.insertAtCursor(Array(precedingNewlines).join('\n') + ( // Insert up to two newlines, depending on preceding whitespace
quote ? '> ' + mention + quote.trim().replace(/\n/g, '\n> ') + '\n\n' : mention));
}
function reply(post, quote) {
var component = app.composer.component;
if (component && component.props.post && component.props.post.discussion() === post.discussion()) {
insertMention(post, component, quote);
} else {
DiscussionControls.replyAction.call(post.discussion()).then(function (newComponent) {
return insertMention(post, newComponent, quote);
});
}
}
_export('default', reply);
return {
setters: [function (_flarumUtilsDiscussionControls) {
DiscussionControls = _flarumUtilsDiscussionControls.default;
}],
execute: function () {}
};
});

View File

@ -0,0 +1,43 @@
import { extend } from 'flarum/extend';
import CommentPost from 'flarum/components/CommentPost';
import PostQuoteButton from 'flarum/mentions/components/PostQuoteButton';
export default function addPostQuoteButton() {
extend(CommentPost.prototype, 'config', function(original, isInitialized) {
const post = this.props.post;
if (isInitialized || post.isHidden() || (app.session.user && !post.discussion().canReply())) return;
const $postBody = this.$().find('.Post-body');
// Wrap the quote button in a wrapper element so that we can render
// button into it.
const $container = $('<div class="Post-quoteButtonContainer"></div>');
this.$()
.after($container)
.on('mouseup', function(e) {
setTimeout(() => {
const selection = window.getSelection();
if (selection.rangeCount) {
const range = selection.getRangeAt(0);
const parent = range.commonAncestorContainer;
if ($postBody[0] === parent || $.contains($postBody[0], parent)) {
const content = $.trim(selection.toString());
if (content) {
const button = new PostQuoteButton({post, content});
m.render($container[0], button.render());
const rect = range.getClientRects()[0];
button.show(rect.left, $(window).scrollTop() + rect.top);
}
}
}
}, 1);
});
});
}

View File

@ -1,51 +1,23 @@
import { extend } from 'flarum/extend';
import Button from 'flarum/components/Button';
import CommentPost from 'flarum/components/CommentPost';
import DiscussionControls from 'flarum/utils/DiscussionControls';
import reply from 'flarum/mentions/utils/reply';
export default function () {
extend(CommentPost.prototype, 'actionItems', function (items) {
const post = this.props.post;
if (post.isHidden() || (app.session.user && !post.discussion().canReply())) return;
function insertMention(component, quote) {
const user = post.user();
const mention = '@' + (user ? user.username() : post.number()) + '#' + post.id() + ' ';
// If the composer is empty, then assume we're starting a new reply.
// In which case we don't want the user to have to confirm if they
// close the composer straight away.
if (!component.content()) {
component.props.originalContent = mention;
}
const cursorPosition = component.editor.getSelectionRange()[0];
const preceding = component.editor.value().slice(0, cursorPosition);
const precedingNewlines = preceding.length == 0 ? 0 : 3 - preceding.match(/(\n{0,2})$/)[0].length;
component.editor.insertAtCursor(
Array(precedingNewlines).join('\n') + // Insert up to two newlines, depending on preceding whitespace
(quote
? '> ' + mention + quote.trim().replace(/\n/g, '\n> ') + '\n\n'
: mention)
);
}
items.add('reply',
Button.component({
className: 'Button Button--link',
children: app.translator.trans('flarum-mentions.forum.post.reply_link'),
onclick: () => {
const quote = window.getSelection().toString();
const component = app.composer.component;
if (component && component.props.post && component.props.post.discussion() === post.discussion()) {
insertMention(component, quote);
} else {
DiscussionControls.replyAction.call(post.discussion())
.then(newComponent => insertMention(newComponent, quote));
}
reply(post, quote);
}
})
);

View File

@ -0,0 +1,40 @@
import Button from 'flarum/components/Button';
import extract from 'flarum/utils/extract';
import reply from 'flarum/mentions/utils/reply';
export default class PostQuoteButton extends Button {
view() {
const post = extract(this.props, 'post');
const content = extract(this.props, 'content');
this.props.className = 'Button PostQuoteButton';
this.props.icon = 'quote-left';
this.props.children = app.translator.trans('flarum-mentions.forum.post.quote_button');
this.props.onclick = () => {
this.hide();
reply(post, content);
};
this.props.onmousedown = (e) => e.stopPropagation();
return super.view();
}
config(isInitialized) {
if (isInitialized) return;
$(document).on('mousedown', this.hide.bind(this));
}
show(left, top) {
const $this = this.$();
$this.show()
.css('top', top - $this.outerHeight() - 5)
.css('left', left);
}
hide() {
this.$().hide();
}
}

View File

@ -6,6 +6,7 @@ import { getPlainContent } from 'flarum/utils/string';
import addPostMentionPreviews from 'flarum/mentions/addPostMentionPreviews';
import addMentionedByList from 'flarum/mentions/addMentionedByList';
import addPostReplyAction from 'flarum/mentions/addPostReplyAction';
import addPostQuoteButton from 'flarum/mentions/addPostQuoteButton';
import addComposerAutocomplete from 'flarum/mentions/addComposerAutocomplete';
import PostMentionedNotification from 'flarum/mentions/components/PostMentionedNotification';
import UserMentionedNotification from 'flarum/mentions/components/UserMentionedNotification';
@ -26,6 +27,9 @@ app.initializers.add('flarum-mentions', function() {
// open up the composer and add a post mention to its contents.
addPostReplyAction();
// Show a Quote button when Post text is selected
addPostQuoteButton();
// After typing '@' in the composer, show a dropdown suggesting a bunch of
// posts or users that the user could mention.
addComposerAutocomplete();

View File

@ -0,0 +1,34 @@
import DiscussionControls from 'flarum/utils/DiscussionControls';
function insertMention(post, component, quote) {
const user = post.user();
const mention = '@' + (user ? user.username() : post.number()) + '#' + post.id() + ' ';
// If the composer is empty, then assume we're starting a new reply.
// In which case we don't want the user to have to confirm if they
// close the composer straight away.
if (!component.content()) {
component.props.originalContent = mention;
}
const cursorPosition = component.editor.getSelectionRange()[0];
const preceding = component.editor.value().slice(0, cursorPosition);
const precedingNewlines = preceding.length == 0 ? 0 : 3 - preceding.match(/(\n{0,2})$/)[0].length;
component.editor.insertAtCursor(
Array(precedingNewlines).join('\n') + // Insert up to two newlines, depending on preceding whitespace
(quote
? '> ' + mention + quote.trim().replace(/\n/g, '\n> ') + '\n\n'
: mention)
);
}
export default function reply(post, quote) {
const component = app.composer.component;
if (component && component.props.post && component.props.post.discussion() === post.discussion()) {
insertMention(post, component, quote);
} else {
DiscussionControls.replyAction.call(post.discussion())
.then(newComponent => insertMention(post, newComponent, quote));
}
}

View File

@ -86,3 +86,7 @@
font-weight: bold !important;
white-space: normal !important;
}
.PostQuoteButton {
position: absolute;
box-shadow: 0 2px 4px @shadow-color;
}