Merge pull request #1733 from RocketChat/mail-messages

Mail messages
pull/1738/merge
Gabriel Engel 10 years ago
commit 13d0558bfa
  1. 1
      .meteor/packages
  2. 1
      .meteor/versions
  3. 11
      packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee
  4. 24
      packages/rocketchat-channel-settings-mail-messages/client/stylesheets/mail-messages.less
  5. 10
      packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee
  6. 8
      packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.html
  7. 79
      packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee
  8. 44
      packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.html
  9. 17
      packages/rocketchat-channel-settings-mail-messages/i18n/en.i18n.json
  10. 51
      packages/rocketchat-channel-settings-mail-messages/package.js
  11. 3
      packages/rocketchat-channel-settings-mail-messages/server/lib/startup.coffee
  12. 46
      packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee
  13. 29
      packages/rocketchat-channel-settings/client/lib/ChannelSettings.coffee
  14. 30
      packages/rocketchat-channel-settings/client/stylesheets/channel-settings.less
  15. 2
      packages/rocketchat-channel-settings/client/views/channelSettings.coffee
  16. 89
      packages/rocketchat-channel-settings/client/views/channelSettings.html
  17. 3
      packages/rocketchat-channel-settings/package.js
  18. 2
      packages/rocketchat-lib/client/lib/roomExit.coffee
  19. 26
      packages/rocketchat-lib/lib/Message.coffee
  20. 0
      packages/rocketchat-lib/lib/MessageTypes.coffee
  21. 3
      packages/rocketchat-lib/package.js
  22. 9
      packages/rocketchat-lib/server/models/Messages.coffee
  23. 6
      packages/rocketchat-theme/assets/stylesheets/base.less
  24. 72
      packages/rocketchat-ui/views/app/room.coffee
  25. 2
      packages/rocketchat-ui/views/app/room.html

@ -41,6 +41,7 @@ rocketchat:lib
rocketchat:authorization
rocketchat:autolinker
rocketchat:channel-settings
rocketchat:channel-settings-mail-messages
rocketchat:colors
rocketchat:custom-oauth
rocketchat:emojione

@ -125,6 +125,7 @@ rocketchat:assets@0.0.1
rocketchat:authorization@0.0.1
rocketchat:autolinker@0.0.1
rocketchat:channel-settings@0.0.1
rocketchat:channel-settings-mail-messages@0.0.1
rocketchat:colors@0.0.1
rocketchat:cors@0.0.1
rocketchat:custom-oauth@1.0.0

@ -0,0 +1,11 @@
Meteor.startup ->
RocketChat.ChannelSettings.addOption
id: 'mail-messages'
template: 'channelSettingsMailMessages'
validation: ->
return RocketChat.authz.hasAllPermission('mail-messages')
RocketChat.callbacks.add 'roomExit', (mainNode) ->
instance = Blaze.getView($('.messages-box')?[0])?.templateInstance()
instance?.resetSelection(false)
, RocketChat.callbacks.priority.MEDIUM, 'room-exit-mail-messages'

@ -0,0 +1,24 @@
.flex-tab {
.mail-message {
form {
margin-top: 20px;
.input-line.double-col {
margin-bottom: 20px;
label {
line-height: 15px;
}
div {
line-height: 15px;
i.octicon {
font-size: 13px;
opacity: 0.4;
vertical-align: top;
}
}
}
}
}
}

@ -0,0 +1,10 @@
Template.channelSettingsMailMessages.events
'click button.mail-messages': (e, t) ->
Session.set 'channelSettingsMailMessages', Session.get('openedRoom')
RocketChat.TabBar.setTemplate('mailMessagesInstructions')
view = Blaze.getView($('.messages-box')[0])
view?.templateInstance?().resetSelection?(true)
Template.channelSettingsMailMessages.onCreated ->
view = Blaze.getView($('.messages-box')[0])
view?.templateInstance?().resetSelection?(false)

@ -0,0 +1,8 @@
<template name="channelSettingsMailMessages">
<li>
<label>{{_ "Mail_Messages"}}</label>
<div>
<button type="button" class="button primary mail-messages">{{_ "Choose_messages"}}</button>
</div>
</li>
</template>

@ -0,0 +1,79 @@
Template.mailMessagesInstructions.helpers
name: ->
return Meteor.user().name
email: ->
return Meteor.user().emails?[0]?.address
roomName: ->
return ChatRoom.findOne(Session.get('openedRoom'))?.name
erroredEmails: ->
return Template.instance()?.erroredEmails.get().join(', ')
Template.mailMessagesInstructions.events
'click .cancel': (e, t) ->
t.reset()
'click .send': (e, t) ->
t.$('.error').hide()
$btn = t.$('button.send')
oldBtnValue = $btn.html()
$btn.html(TAPi18n.__('Sending'))
selectedMessages = $('.messages-box .message.selected')
error = false
if selectedMessages.length is 0
t.$('.error-select').show()
error = true
if t.$('input[name=to]').val().trim()
rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/
emails = t.$('input[name=to]').val().trim().split(',')
erroredEmails = []
for email in emails
unless rfcMailPatternWithName.test email.trim()
erroredEmails.push email.trim()
t.erroredEmails.set erroredEmails
if erroredEmails.length > 0
t.$('.error-invalid-emails').show()
error = true
else
t.$('.error-missing-to').show()
error = true
if error
$btn.html(oldBtnValue)
else
data =
rid: Session.get('openedRoom')
to: t.$('input[name=to]').val().trim()
subject: t.$('input[name=subject]').val().trim()
messages: selectedMessages.map((i, message) -> return message.id).toArray()
language: localStorage.getItem('userLanguage')
Meteor.call 'mailMessages', data, (err, result) ->
$btn.html(oldBtnValue)
if err?
return toastr.error(err.reason or err.message)
toastr.success(TAPi18n.__('Your_email_has_been_queued_for_sending'))
t.reset()
'click .select-all': (e, t) ->
t.$('.error-select').hide()
view = Blaze.getView($('.messages-box')[0])
view?.templateInstance?().selectedMessages = _.pluck(ChatMessage.find({rid: Session.get('openedRoom')})?.fetch(), '_id')
$(".messages-box .message").addClass('selected')
Template.mailMessagesInstructions.onCreated ->
@erroredEmails = new ReactiveVar []
@reset = ->
RocketChat.TabBar.setTemplate('channelSettings')
view = Blaze.getView($('.messages-box')[0])
view?.templateInstance?().resetSelection?(false)
@autorun =>
if Session.get('channelSettingsMailMessages') isnt Session.get('openedRoom')
this.reset()

@ -0,0 +1,44 @@
<template name="mailMessagesInstructions">
<div class="content">
<div class="list-view mail-message">
<div class="status">
<h2>{{_ "Mail_Messages"}}</h2>
</div>
<p>{{_ "Mail_Messages_Instructions"}}</p>
<form>
<fieldset>
<div class="input-line double-col">
<label>{{_ "From"}}</label>
<div>{{name}}</div>
<div>{{email}}</div>
</div>
<div class="input-line double-col">
<label>{{_ "To"}}</label>
<div>
<input type="text" name="to" value="" />
</div>
</div>
<div class="input-line double-col">
<label>{{_ "Subject"}}</label>
<div>
<input type="text" name="subject" value="{{_ "Mail_Messages_Subject" roomName}}" />
</div>
</div>
</fieldset>
</form>
<div class="error error-missing-to alert alert-danger" style="display: none">
{{_ "Mail_Message_Missing_to"}}
</div>
<div class="error error-invalid-emails alert alert-danger" style="display: none">
{{_ "Mail_Message_Invalid_emails" erroredEmails}}
</div>
<div class="error error-select alert alert-danger" style="display: none">
{{{_ "Mail_Message_No_messages_selected_select_all"}}}
</div>
<p style="margin-top: 30px">
<button type="button" class="button secondary cancel">{{_ "Cancel"}}</button>
<button type="button" class="button primary send">{{_ "Send"}}</button>
</p>
</div>
</div>
</template>

@ -0,0 +1,17 @@
{
"Body" : "Body",
"Cancel" : "Cancel",
"Choose_messages" : "Choose messages",
"From" : "From",
"Mail_Message_Missing_to" : "You must provide one or more To e-mail addresses, separated by commas.",
"Mail_Message_No_messages_selected_select_all" : "You haven't selected any messages. Would you like to <a href='#' class='select-all'>select all</a> visible messages?",
"Mail_Messages" : "Mail Messages",
"Mail_Messages_Instructions" : "Choose which messages you want to send via e-mail by clicking the messages",
"Mail_Messages_Subject" : "Here's a selected portion of %s messages",
"Mail_Message_Invalid_emails" : "You have provided one or more invalid e-mails: %s",
"Send" : "Send",
"Sending" : "Sending...",
"Subject" : "Subject",
"To" : "To",
"Your_email_has_been_queued_for_sending" : "Your email has been queued for sending"
}

@ -0,0 +1,51 @@
Package.describe({
name: 'rocketchat:channel-settings-mail-messages',
version: '0.0.1',
summary: 'Channel Settings - Mail Messages',
git: ''
});
Package.onUse(function(api) {
api.versionsFrom('1.0');
api.use([
'coffeescript',
'templating',
'reactive-var',
'less@2.5.0',
'rocketchat:lib@0.0.1',
'rocketchat:channel-settings',
'momentjs:moment'
]);
api.addFiles([
'client/lib/startup.coffee',
'client/stylesheets/mail-messages.less',
'client/views/channelSettingsMailMessages.html',
'client/views/channelSettingsMailMessages.coffee',
'client/views/mailMessagesInstructions.html',
'client/views/mailMessagesInstructions.coffee'
], 'client');
api.addFiles([
'server/lib/startup.coffee',
'server/methods/mailMessages.coffee'
], 'server');
// TAPi18n
var _ = Npm.require('underscore');
var fs = Npm.require('fs');
tapi18nFiles = _.compact(_.map(fs.readdirSync('packages/rocketchat-channel-settings-mail-messages/i18n'), function(filename) {
if (fs.statSync('packages/rocketchat-channel-settings-mail-messages/i18n/' + filename).size > 16) {
return 'i18n/' + filename;
}
}));
api.use('tap:i18n@1.6.1');
api.imply('tap:i18n');
api.addFiles(tapi18nFiles);
});
Package.onTest(function(api) {
});

@ -0,0 +1,3 @@
Meteor.startup ->
permission = { _id: 'mail-messages', roles : [ 'admin' ] }
RocketChat.models.Permissions.upsert( permission._id, { $setOnInsert : permission })

@ -0,0 +1,46 @@
Meteor.methods
'mailMessages': (data) ->
if not Meteor.userId()
throw new Meteor.Error('invalid-user', "[methods] mailMessages -> Invalid user")
check(data, Match.ObjectIncluding({ rid: String, to: String, subject: String, messages: [ String ], language: String }))
room = Meteor.call 'canAccessRoom', data.rid, Meteor.userId()
unless room
throw new Meteor.Error('invalid-room', "[methods] mailMessages -> Invalid room")
unless RocketChat.authz.hasPermission(Meteor.userId(), 'mail-messages')
throw new Meteor.Error 'not-authorized'
rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/
emails = data.to.trim().split(',')
for email in emails
unless rfcMailPatternWithName.test email.trim()
throw new Meteor.Error('invalid-email', "[methods] mailMessages -> Invalid e-mail")
user = Meteor.user()
name = user.name
email = user.emails?[0]?.address
if data.language isnt 'en'
localeFn = Meteor.call 'loadLocale', data.language
if localeFn
Function(localeFn)()
html = ""
RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) ->
dateTime = moment(message.ts).locale(data.language).format('L LT')
html += "<p style='margin-bottom: 5px'><b>#{message.u.username}</b> <span style='color: #aaa; font-size: 12px'>#{dateTime}</span><br />" + RocketChat.Message.parse(message, data.language) + "</p>"
Meteor.defer ->
Email.send
to: emails
from: RocketChat.settings.get('From_Email')
replyTo: email
subject: data.subject
html: html
console.log 'Sending email to ' + emails.join(', ')
return true

@ -0,0 +1,29 @@
RocketChat.ChannelSettings = new class
options = new ReactiveVar {}
###
# Adds an option in Channel Settings
# @config (object)
# id: option id (required)
# template (string): template name to render (required)
# validation (function): if option should be displayed
###
addOption = (config) ->
unless config?.id
throw new Meteor.Error "ChannelSettings-addOption-error", "Option id was not informed."
Tracker.nonreactive ->
opts = options.get()
opts[config.id] = config
options.set opts
getOptions = ->
allOptions = _.toArray options.get()
allowedOptions = _.compact _.map allOptions, (option) ->
if not option.validation? or option.validation()
return option
return _.sortBy allowedOptions, 'order'
addOption: addOption
getOptions: getOptions

@ -1,11 +1,25 @@
.flex-tab {
.channel-settings {
margin-top: 60px;
padding: 20px;
ul {
li {
margin-bottom: 20px;
}
}
form {
label {
display: block;
font-weight: bold;
margin-bottom: 5px;
}
div span {
font-size: 14px;
i.octicon {
font-size: 12px;
vertical-align: middle;
margin-left: 3px;
}
}
}
@ -19,15 +33,3 @@
}
}
}
.input-line.double-col {
div {
line-height: 15px;
padding: 10px 20px 10px 0;
i.octicon {
font-size: 13px;
opacity: 0.4;
vertical-align: top;
}
}
}

@ -7,6 +7,8 @@ Template.channelSettings.helpers
return ChatRoom.findOne(@rid)?.t isnt 'd'
roomType: ->
return ChatRoom.findOne(@rid)?.t
channelSettings: ->
return RocketChat.ChannelSettings.getOptions()
roomTypeDescription: ->
roomType = ChatRoom.findOne(@rid)?.t
if roomType is 'c'

@ -1,50 +1,53 @@
<template name="channelSettings">
<div class="control">
<div class="header">
<h2>{{_ "Room_Info"}}</h2>
</div>
</div>
<div class="channel-settings scrollable">
<form>
<fieldset>
{{#if notDirect}}
<div class="input-line double-col">
<label>{{_ "Name"}}</label>
<div class="content">
<div class="list-view channel-settings">
<div class="status">
<h2>{{_ "Room_Info"}}</h2>
</div>
<form>
<ul class="list clearfix">
{{#if notDirect}}
<li>
<label>{{_ "Name"}}</label>
<div>
{{#if editing 'roomName'}}
<input type="text" name="roomName" value="{{roomName}}" class="editing" /> <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary save">{{_ "Save"}}</button>
{{else}}
<span>{{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomName"></i>{{/if}}</span>
{{/if}}
</div>
</li>
{{/if}}
<li>
<label>{{_ "Topic"}}</label>
<div>
{{#if editing 'roomName'}}
<input type="text" name="roomName" value="{{roomName}}" class="editing" /> <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary save">{{_ "Save"}}</button>
{{#if editing 'roomTopic'}}
<input type="text" name="roomTopic" value="{{roomTopic}}" class="editing" /> <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary save">{{_ "Save"}}</button>
{{else}}
{{roomName}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomName"></i>{{/if}}
<span>{{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomTopic"></i>{{/if}}</span>
{{/if}}
</div>
</div>
{{/if}}
<div class="input-line double-col">
<label>{{_ "Topic"}}</label>
<div>
{{#if editing 'roomTopic'}}
<input type="text" name="roomTopic" value="{{roomTopic}}" class="editing" /> <button type="button" class="button secondary cancel">{{_ "Cancel"}}</button> <button type="button" class="button primary save">{{_ "Save"}}</button>
{{else}}
{{roomTopic}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomTopic"></i>{{/if}}
{{/if}}
</div>
</div>
{{#if notDirect}}
<div class="input-line double-col">
<label>{{_ "Type"}}</label>
<div>
{{#if editing 'roomType'}}
<label><input type="radio" name="roomType" class="editing" value="c" checked="{{$eq roomType 'c'}}" /> {{_ "Channel"}}</label>
<label><input type="radio" name="roomType" value="p" checked="{{$eq roomType 'p'}}" /> {{_ "Private_Group"}}</label>
<button type="button" class="button secondary cancel">{{_ "Cancel"}}</button>
<button type="button" class="button primary save">{{_ "Save"}}</button>
{{else}}
{{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomType"></i>{{/if}}
{{/if}}
</div>
</div>
{{/if}}
</fieldset>
</form>
</li>
{{#if notDirect}}
<li>
<label>{{_ "Type"}}</label>
<div>
{{#if editing 'roomType'}}
<label><input type="radio" name="roomType" class="editing" value="c" checked="{{$eq roomType 'c'}}" /> {{_ "Channel"}}</label>
<label><input type="radio" name="roomType" value="p" checked="{{$eq roomType 'p'}}" /> {{_ "Private_Group"}}</label>
<button type="button" class="button secondary cancel">{{_ "Cancel"}}</button>
<button type="button" class="button primary save">{{_ "Save"}}</button>
{{else}}
<span>{{roomTypeDescription}}{{#if canEdit}} <i class="octicon octicon-pencil" data-edit="roomType"></i>{{/if}}</span>
{{/if}}
</div>
</li>
{{/if}}
{{#each channelSettings}}
{{> Template.dynamic template=template data=data}}
{{/each}}
</ul>
</form>
</div>
</div>
</template>

@ -10,12 +10,15 @@ Package.onUse(function(api) {
api.use([
'coffeescript',
'reactive-var',
'tracker',
'templating',
'less@2.5.0',
'rocketchat:lib@0.0.1'
]);
api.addFiles([
'client/lib/ChannelSettings.coffee',
'client/startup/messageTypes.coffee',
'client/startup/tabBar.coffee',
'client/startup/trackSettingsChange.coffee',

@ -1,4 +1,6 @@
@roomExit = ->
RocketChat.callbacks.run 'roomExit'
BlazeLayout.render 'main', {center: 'none'}
if currentTracker?

@ -0,0 +1,26 @@
RocketChat.Message =
parse: (msg, language) ->
messageType = RocketChat.MessageTypes.getType(msg)
if messageType?.render?
return messageType.render(msg)
else if messageType?.template?
# render template
else if messageType?.message?
if not language and localStorage?.getItem('userLanguage')
language = localStorage.getItem('userLanguage')
if messageType.data?(msg)?
return TAPi18n.__(messageType.message, messageType.data(msg), language)
else
return TAPi18n.__(messageType.message, {}, language)
else
if msg.u?.username is RocketChat.settings.get('Chatops_Username')
msg.html = msg.msg
return msg.html
msg.html = msg.msg
if _.trim(msg.html) isnt ''
msg.html = _.escapeHTML msg.html
# message = RocketChat.callbacks.run 'renderMessage', msg
msg.html = msg.html.replace /\n/gm, '<br/>'
return msg.html

@ -33,6 +33,8 @@ Package.onUse(function(api) {
api.addFiles('lib/settings.coffee');
api.addFiles('lib/callbacks.coffee');
api.addFiles('lib/slashCommand.coffee');
api.addFiles('lib/Message.coffee');
api.addFiles('lib/MessageTypes.coffee');
// SERVER LIB
api.addFiles('server/lib/RateLimiter.coffee', 'server');
@ -92,7 +94,6 @@ Package.onUse(function(api) {
api.addFiles('client/Notifications.coffee', 'client');
api.addFiles('client/TabBar.coffee', 'client');
api.addFiles('client/MessageAction.coffee', 'client');
api.addFiles('client/MessageTypes.coffee', 'client');
// VERSION
api.addFiles('rocketchat.info');

@ -116,6 +116,14 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base
return @find(query, options)?.fetch?()?[0]?.ts
findByRoomIdAndMessageIds: (rid, messageIds, options) ->
query =
rid: rid
_id:
$in: messageIds
return @find query, options
cloneAndSaveAsHistoryById: (_id) ->
me = RocketChat.models.Users.findOneById Meteor.userId()
record = @findOneById _id
@ -134,7 +142,6 @@ RocketChat.models.Messages = new class extends RocketChat.models._Base
return @insert record
# UPDATE
setHiddenById: (_id, hidden=true) ->
query =

@ -2475,6 +2475,12 @@ a.github-fork {
border-radius: 4px;
}
}
&.selectable .message {
cursor: pointer;
&.selected {
background-color: #FFD;
}
}
}
.ticks-bar {

@ -201,6 +201,8 @@ Template.room.helpers
compactView: ->
return 'compact' if Meteor.user()?.settings?.preferences?.compactView
selectable: ->
return Template.instance().selectable.get()
Template.room.events
"click, touchend": (e, t) ->
@ -408,6 +410,33 @@ Template.room.events
template.atBottom = true
RoomHistoryManager.clear(template?.data?._id)
'click .message': (e, template) ->
e.preventDefault()
e.stopPropagation()
if template.selectable.get()
document.selection?.empty() or window.getSelection?().removeAllRanges()
data = Blaze.getData(e.currentTarget)
_id = data?._arguments?[1]?._id
if !template.selectablePointer
template.selectablePointer = _id
if !e.shiftKey
template.selectedMessages = template.getSelectedMessages()
template.selectedRange = []
template.selectablePointer = _id
template.selectMessages _id
selectedMessages = $('.messages-box .message.selected').map((i, message) -> message.id)
removeClass = _.difference selectedMessages, template.getSelectedMessages()
addClass = _.difference template.getSelectedMessages(), selectedMessages
for message in removeClass
$(".messages-box ##{message}").removeClass('selected')
for message in addClass
$(".messages-box ##{message}").addClass('selected')
Template.room.onCreated ->
# this.scrollOnBottom = true
# this.typing = new msgTyping this.data._id
@ -415,10 +444,47 @@ Template.room.onCreated ->
this.atBottom = true
this.unreadCount = new ReactiveVar 0
self = @
this.selectable = new ReactiveVar false
this.selectedMessages = []
this.selectedRange = []
this.selectablePointer = null
this.resetSelection = (enabled) =>
this.selectable.set(enabled)
$('.messages-box .message.selected').removeClass 'selected'
this.selectedMessages = []
this.selectedRange = []
this.selectablePointer = null
this.selectMessages = (to) =>
if this.selectablePointer is to and this.selectedRange.length > 0
this.selectedRange = []
else
message1 = ChatMessage.findOne this.selectablePointer
message2 = ChatMessage.findOne to
minTs = _.min([message1.ts, message2.ts])
maxTs = _.max([message1.ts, message2.ts])
this.selectedRange = _.pluck(ChatMessage.find({ rid: message1.rid, ts: { $gte: minTs, $lte: maxTs } }).fetch(), '_id')
this.getSelectedMessages = =>
messages = this.selectedMessages
addMessages = false
for message in this.selectedRange
if messages.indexOf(message) is -1
addMessages = true
break
if addMessages
previewMessages = _.compact(_.uniq(this.selectedMessages.concat(this.selectedRange)))
else
previewMessages = _.compact(_.difference(this.selectedMessages, this.selectedRange))
return previewMessages
@autorun ->
self.subscribe 'fullUserData', Session.get('showUserInfo'), 1
@autorun =>
@subscribe 'fullUserData', Session.get('showUserInfo'), 1
Template.room.onDestroyed ->

@ -47,7 +47,7 @@
{{/if}}
{{/if}}
</div>
<div class="messages-box {{compactView}}">
<div class="messages-box {{#if selectable}}selectable{{/if}} {{compactView}}">
<div class="ticks-bar"></div>
<div class="wrapper {{#if hasMoreNext}}has-more-next{{/if}}">
<ul aria-live="polite">

Loading…
Cancel
Save