|
@@ -68,7 +68,55 @@ EscapeActions.register('textcomplete',
|
|
() => dropdownMenuIsOpened
|
|
() => dropdownMenuIsOpened
|
|
);
|
|
);
|
|
|
|
|
|
|
|
+// XXX I believe we should compute a HTML rendered field on the server that
|
|
|
|
+// would handle markdown, emojies and user mentions. We can simply have two
|
|
|
|
+// fields, one source, and one compiled version (in HTML) and send only the
|
|
|
|
+// compiled version to most users -- who don't need to edit.
|
|
|
|
+// In the meantime, all the transformation are done on the client using the
|
|
|
|
+// Blaze API.
|
|
|
|
+const at = HTML.CharRef({html: '@', str: '@'});
|
|
|
|
+Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
|
|
|
|
+ const view = this;
|
|
|
|
+ const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
|
|
|
+ const knowedUsers = _.map(currentBoard.members, (member) => {
|
|
|
|
+ member.username = Users.findOne(member.userId).username;
|
|
|
|
+ return member;
|
|
|
|
+ });
|
|
|
|
+ const mentionRegex = /\B@(\w*)/gi;
|
|
|
|
+ let content = Blaze.toHTML(view.templateContentBlock);
|
|
|
|
+
|
|
|
|
+ let currentMention, knowedUser, linkClass, linkValue, link;
|
|
|
|
+ while (Boolean(currentMention = mentionRegex.exec(content))) {
|
|
|
|
+
|
|
|
|
+ knowedUser = _.findWhere(knowedUsers, { username: currentMention[1] });
|
|
|
|
+ if (!knowedUser)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ linkValue = [' ', at, knowedUser.username];
|
|
|
|
+ linkClass = 'atMention js-open-member';
|
|
|
|
+ if (knowedUser.userId === Meteor.userId())
|
|
|
|
+ linkClass += ' me';
|
|
|
|
+ link = HTML.A({
|
|
|
|
+ 'class': linkClass,
|
|
|
|
+ // XXX Hack. Since we stringify this render function result below with
|
|
|
|
+ // `Blaze.toHTML` we can't rely on blaze data contexts to pass the
|
|
|
|
+ // `userId` to the popup as usual, and we need to store it in the DOM
|
|
|
|
+ // using a data attribute.
|
|
|
|
+ 'data-userId': knowedUser.userId,
|
|
|
|
+ }, linkValue);
|
|
|
|
+
|
|
|
|
+ content = content.replace(currentMention[0], Blaze.toHTML(link));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return HTML.Raw(content);
|
|
|
|
+}));
|
|
|
|
+
|
|
Template.viewer.events({
|
|
Template.viewer.events({
|
|
|
|
+ 'click .js-open-member'(evt, tpl) {
|
|
|
|
+ const userId = evt.currentTarget.dataset.userid;
|
|
|
|
+ Popup.open('member').call({ userId }, evt, tpl);
|
|
|
|
+ },
|
|
|
|
+
|
|
// Viewer sometimes have click-able wrapper around them (for instance to edit
|
|
// Viewer sometimes have click-able wrapper around them (for instance to edit
|
|
// the corresponding text). Clicking a link shouldn't fire these actions, stop
|
|
// the corresponding text). Clicking a link shouldn't fire these actions, stop
|
|
// we stop these event at the viewer component level.
|
|
// we stop these event at the viewer component level.
|
|
@@ -81,6 +129,8 @@ Template.viewer.events({
|
|
// by using directly `_blank` attribute in the rendered HTML.
|
|
// by using directly `_blank` attribute in the rendered HTML.
|
|
evt.preventDefault();
|
|
evt.preventDefault();
|
|
const href = evt.currentTarget.href;
|
|
const href = evt.currentTarget.href;
|
|
- window.open(href, '_blank');
|
|
|
|
|
|
+ if (href) {
|
|
|
|
+ window.open(href, '_blank');
|
|
|
|
+ }
|
|
},
|
|
},
|
|
});
|
|
});
|