Skip to content
Snippets Groups Projects
Commit 2f3a6f1e authored by Diego Sampaio's avatar Diego Sampaio
Browse files

initial implementation of external app

parent e45c72e2
No related branches found
No related tags found
No related merge requests found
Showing
with 460 additions and 15 deletions
......@@ -78,3 +78,4 @@ kadira:flow-router
kadira:blaze-layout
mystor:device-detection
fastclick
rocketchat:external
......@@ -110,6 +110,7 @@ reload@1.1.3
retry@1.0.3
rocketchat:autolinker@0.0.1
rocketchat:emojione@0.0.1
rocketchat:external@0.0.1
rocketchat:favico@0.0.1
rocketchat:file@0.0.1
rocketchat:highlight@0.0.1
......
......@@ -22,3 +22,12 @@ underscore
jquery
random
ejson
coffeescript
arunoda:streams
kadira:flow-router
kadira:blaze-layout
konecty:nrr
less
underscorestring:underscore.string
momentjs:moment
mizzao:timesync
arunoda:streams@0.1.17
base64@1.0.3
binary-heap@1.0.3
blaze@2.1.2
......@@ -5,20 +6,29 @@ blaze-tools@1.0.3
boilerplate-generator@1.0.3
callback-hook@1.0.3
check@1.0.5
coffeescript@1.0.6
cosmos:browserify@0.5.0
ddp@1.1.0
deps@1.0.7
ejson@1.0.6
geojson-utils@1.0.3
html-tools@1.0.4
htmljs@1.0.4
http@1.1.0
id-map@1.0.3
jquery@1.11.3_2
json@1.0.3
kadira:blaze-layout@2.0.0
kadira:flow-router@2.1.0
konecty:nrr@2.0.2
less@1.0.14
livedata@1.0.13
logging@1.0.7
meteor@1.1.6
minifiers@1.1.5
minimongo@1.0.8
mizzao:timesync@0.3.3
momentjs:moment@2.10.6
mongo@1.1.0
observe-sequence@1.0.6
ordered-dict@1.0.3
......@@ -34,5 +44,7 @@ templating@1.1.1
tracker@1.0.7
ui@1.0.6
underscore@1.0.3
underscorestring:underscore.string@3.1.1
url@1.0.4
webapp@1.2.0
webapp-hashing@1.0.3
@getAvatarUrlFromUsername = (username) ->
key = "avatar_random_#{username}"
random = Session.keys[key] or 0
if not username?
return
return "#{Meteor.absoluteUrl()}avatar/#{username}.jpg?_dc=#{random}"
@updateAvatarOfUsername = (username) ->
key = "avatar_random_#{username}"
Session.set key, Math.round(Math.random() * 1000)
for key, room of RoomManager.openedRooms
url = getAvatarUrlFromUsername username
$(room.dom).find(".message[data-username='#{username}'] .avatar-image").css('background-image', "url(#{url})");
return true
class @ChatMessages
init: (node) ->
this.editing = {}
# this.messageMaxSize = RocketChat.settings.get('Message_MaxAllowedSize')
this.wrapper = $(node).find(".wrapper")
this.input = $(node).find(".input-message").get(0)
# this.bindEvents()
return
resize: ->
dif = 60 + $(".messages-container").find("footer").outerHeight()
$(".messages-box").css
height: "calc(100% - #{dif}px)"
toPrevMessage: ->
msgs = this.wrapper.get(0).querySelectorAll(".own:not(.system)")
if msgs.length
if this.editing.element
if msgs[this.editing.index - 1]
this.edit msgs[this.editing.index - 1], this.editing.index - 1
else
this.edit msgs[msgs.length - 1], msgs.length - 1
toNextMessage: ->
if this.editing.element
msgs = this.wrapper.get(0).querySelectorAll(".own:not(.system)")
if msgs[this.editing.index + 1]
this.edit msgs[this.editing.index + 1], this.editing.index + 1
else
this.clearEditing()
getEditingIndex: (element) ->
msgs = this.wrapper.get(0).querySelectorAll(".own:not(.system)")
index = 0
for msg in msgs
if msg is element
return index
index++
return -1
edit: (element, index) ->
return if element.classList.contains("system")
this.clearEditing()
id = element.getAttribute("id")
message = ChatMessage.findOne { _id: id, 'u._id': Meteor.userId() }
this.input.value = message.msg
this.editing.element = element
this.editing.index = index or this.getEditingIndex(element)
this.editing.id = id
element.classList.add("editing")
this.input.classList.add("editing")
setTimeout =>
this.input.focus()
, 5
clearEditing: ->
if this.editing.element
this.editing.element.classList.remove("editing")
this.input.classList.remove("editing")
this.editing.id = null
this.editing.element = null
this.editing.index = null
this.input.value = this.editing.saved or ""
else
this.editing.saved = this.input.value
send: (rid, input) ->
if _.trim(input.value) isnt ''
if this.isMessageTooLong(input)
return Errors.throw t('Error_message_too_long')
# KonchatNotification.removeRoomNotification(rid)
msg = input.value
input.value = ''
msgObject = { _id: Random.id(), rid: rid, msg: msg}
# this.stopTyping(rid)
#Check if message starts with /command
if msg[0] is '/'
match = msg.match(/^\/([^\s]+)(?:\s+(.*))?$/m)
if(match?)
command = match[1]
param = match[2]
Meteor.call 'slashCommand', {cmd: command, params: param, msg: msgObject }
else
#Run to allow local encryption
#Meteor.call 'onClientBeforeSendMessage', {}
Meteor.call 'sendMessageExternal', msgObject
deleteMsg: (message) ->
Meteor.call 'deleteMessage', message, (error, result) ->
if error
return Errors.throw error.reason
update: (id, rid, input) ->
if _.trim(input.value) isnt ''
msg = input.value
Meteor.call 'updateMessage', { id: id, msg: msg }
this.clearEditing()
# this.stopTyping(rid)
startTyping: (rid, input) ->
if _.trim(input.value) isnt ''
MsgTyping.start(rid)
else
MsgTyping.stop(rid)
stopTyping: (rid) ->
MsgTyping.stop(rid)
bindEvents: ->
if this.wrapper?.length
$(".input-message").autogrow
postGrowCallback: =>
this.resize()
tryCompletion: (input) ->
value = input.value.match(/[^\s]+$/)
if value?.length > 0
value = value[0]
re = new RegExp value, 'i'
user = Meteor.users.findOne username: re
if user?
input.value = input.value.replace value, "@#{user.username} "
keyup: (rid, event) ->
input = event.currentTarget
k = event.which
keyCodes = [
13, # Enter
20, # Caps lock
16, # Shift
9, # Tab
27, # Escape Key
17, # Control Key
91, # Windows Command Key
19, # Pause Break
18, # Alt Key
93, # Right Click Point Key
45, # Insert Key
34, # Page Down
35, # Page Up
144, # Num Lock
145 # Scroll Lock
]
keyCodes.push i for i in [35..40] # Home, End, Arrow Keys
keyCodes.push i for i in [112..123] # F1 - F12
# unless k in keyCodes
# this.startTyping(rid, input)
keydown: (rid, event) ->
input = event.currentTarget
k = event.which
this.resize(input)
if k is 13 and not event.shiftKey
event.preventDefault()
event.stopPropagation()
if this.editing.id
this.update(this.editing.id, rid, input)
else
this.send(rid, input)
return
if k is 9
event.preventDefault()
event.stopPropagation()
@tryCompletion input
if k is 27
if this.editing.id
event.preventDefault()
event.stopPropagation()
this.clearEditing()
return
else if k is 38 or k is 40 # Arrow Up or down
if k is 38
return if input.value.slice(0, input.selectionStart).match(/[\n]/) isnt null
this.toPrevMessage()
else
return if input.value.slice(input.selectionEnd, input.value.length).match(/[\n]/) isnt null
this.toNextMessage()
event.preventDefault()
event.stopPropagation()
# ctrl (command) + shift + k -> clear room messages
else if k is 75 and ((navigator?.platform?.indexOf('Mac') isnt -1 and event.metaKey and event.shiftKey) or (navigator?.platform?.indexOf('Mac') is -1 and event.ctrlKey and event.shiftKey))
RoomHistoryManager.clear rid
isMessageTooLong: (input) ->
input?.value.length > this.messageMaxSize
@ChatMessage = new Meteor.Collection null
// This will add underscore.string methods to Underscore.js
// except for include, contains, reverse and join that are
// dropped because they collide with the functions already
// defined by Underscore.js.
_.mixin(s.exports())
Meteor.methods
sendMessageExternal: (message) ->
# if not Meteor.userId()
# throw new Meteor.Error 203, t('User_logged_out')
if _.trim(message.msg) isnt ''
message.ts = new Date(Date.now() + TimeSync.serverOffset())
message.u =
# _id: Meteor.userId()
username: 'visitor'
message.temp = true
# message = RocketChat.callbacks.run 'beforeSaveMessage', message
ChatMessage.insert message
FlowRouter.route '/',
name: 'index'
action: ->
BlazeLayout.render 'main', {center: 'room'}
body {
padding: 0;
margin: 0;
}
.external-room {
position: fixed;
top: 0;
bottom: 0;
background-color: blue;
.title {
background-color: green;
position: fixed;
top: 0;
width: 100%;
height: 60px;
}
.wrapper {
background-color: purple;
top: 60px;
bottom: 60px;
position: fixed;
width: 100%;
overflow-y: auto;
}
.footer {
background-color: red;
position: fixed;
bottom: 0;
width: 100%;
height: 60px;
}
}
<template name="test">
<button>teste</button>
</template>
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});
Template.hello.events({
'click button': function () {
// increment the counter when button is clicked
Session.set('counter', Session.get('counter') + 1);
}
});
\ No newline at end of file
Template.avatar.helpers
imageUrl: ->
username = this.username
if not username? and this.userId?
username = Meteor.users.findOne(this.userId)?.username
if not username?
return
Session.get "avatar_random_#{username}"
url = getAvatarUrlFromUsername(username)
return "background-image:url(#{url});"
<template name="avatar">
<div class="avatar">
<div class="avatar-image" style="{{imageUrl}}"></div>
</div>
</template>
<head>
<title>Rocket.Chat</title>
<meta charset="utf-8" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="expires" content="-1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="fragment" content="!" />
<meta name="distribution" content="global" />
<meta name="rating" content="general" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
</head>
<body>
</body>
<template name="main">
{{> Template.dynamic template=center}}
</template>
Template.message.helpers
own: ->
return ''
# return 'own' if this.u?._id is Meteor.userId()
time: ->
return moment(this.ts).format('HH:mm')
date: ->
return moment(this.ts).format('LL')
isTemp: ->
if @temp is true
return 'temp'
return
body: ->
switch this.t
when 'r' then t('Room_name_changed', { room_name: this.msg, user_by: this.u.username })
when 'au' then t('User_added_by', { user_added: this.msg, user_by: this.u.username })
when 'ru' then t('User_removed_by', { user_removed: this.msg, user_by: this.u.username })
when 'ul' then tr('User_left', { context: this.u.gender }, { user_left: this.u.username })
when 'nu' then t('User_added', { user_added: this.u.username })
when 'uj' then tr('User_joined_channel', { context: this.u.gender }, { user: this.u.username })
when 'wm' then t('Welcome', { user: this.u.username })
# when 'rtc' then RocketChat.callbacks.run 'renderRtcMessage', this
else
this.html = this.msg
if _.trim(this.html) isnt ''
this.html = _.escapeHTML this.html
# message = RocketChat.callbacks.run 'renderMessage', this
message = this
this.html = message.html.replace /\n/gm, '<br/>'
return this.html
system: ->
return 'system' if this.t in ['s', 'p', 'f', 'r', 'au', 'ru', 'ul', 'nu', 'wm', 'uj']
Template.message.onViewRendered = (context) ->
view = this
this._domrange.onAttached (domRange) ->
lastNode = domRange.lastNode()
if lastNode.previousElementSibling?.dataset?.date isnt lastNode.dataset.date
$(lastNode).addClass('new-day')
$(lastNode).removeClass('sequential')
else if lastNode.previousElementSibling?.dataset?.username isnt lastNode.dataset.username
$(lastNode).removeClass('sequential')
if lastNode.nextElementSibling?.dataset?.date is lastNode.dataset.date
$(lastNode.nextElementSibling).removeClass('new-day')
$(lastNode.nextElementSibling).addClass('sequential')
else
$(lastNode.nextElementSibling).addClass('new-day')
$(lastNode.nextElementSibling).removeClass('sequential')
if lastNode.nextElementSibling?.dataset?.username isnt lastNode.dataset.username
$(lastNode.nextElementSibling).removeClass('sequential')
ul = lastNode.parentElement
wrapper = ul.parentElement
if context.urls?.length > 0 and Template.oembedBaseWidget?
for item in context.urls
do (item) ->
urlNode = lastNode.querySelector('.body a[href="'+item.url+'"]')
if urlNode?
$(urlNode).replaceWith Blaze.toHTMLWithData Template.oembedBaseWidget, item
if not lastNode.nextElementSibling?
if lastNode.classList.contains('own') is true
view.parentView.parentView.parentView.parentView.parentView.templateInstance().atBottom = true
# else
# if view.parentView.parentView.parentView.parentView.parentView.templateInstance().atBottom isnt true
# newMessage = document.querySelector(".new-message")
# newMessage.className = "new-message"
<template name="message">
<li id="{{_id}}" class="message sequential {{system}} {{t}} {{own}} {{isTemp}}" data-username="{{u.username}}" data-date="{{date}}">
<a class="thumb user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{> avatar username=u.username}}</a>
<a class="user user-card-message" href="#" data-username="{{u.username}}" tabindex="1">{{u.username}}</a>
<span class="info">
<span class="time">{{time}}</span>
{{#if ets}}
<span class="edited">({{_ "edited"}})</span>
{{/if}}
<i class="icon-pencil edit-message"></i>
<i class="icon-trash-1 delete-message"></i>
</span>
<div class="body" dir="auto">
{{{body}}}
</div>
</li>
</template>
Template.room.helpers
messages: ->
return ChatMessage.find { rid: this._id, t: { '$ne': 't' } }, { sort: { ts: 1 } }
Template.room.events
'keyup .input-message': (event) ->
Template.instance().chatMessages.keyup(@_id, event, Template.instance())
'keydown .input-message': (event) ->
Template.instance().chatMessages.keydown(@_id, event, Template.instance())
Template.room.onRendered ->
this.chatMessages = new ChatMessages
this.chatMessages.init(this.firstNode)
<template name="room">
<div class="external-room">
<div class="title">
<h1>sala</h1>
</div>
<div class="wrapper">
<ul>
{{#each messages}}
{{#nrr nrrargs 'message' .}}{{/nrr}}
{{/each}}
</ul>
</div>
<div class="footer">
<textarea class="input-message"></textarea>
</div>
</div>
</template>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment