diff --git a/packages/rocketchat-external/app/.meteor/packages b/packages/rocketchat-external/app/.meteor/packages
index 537f9ccc83b4..99c0ef6edf1a 100644
--- a/packages/rocketchat-external/app/.meteor/packages
+++ b/packages/rocketchat-external/app/.meteor/packages
@@ -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
diff --git a/packages/rocketchat-external/app/.meteor/versions b/packages/rocketchat-external/app/.meteor/versions
index 36edd40e71e0..22a2bc14a7d6 100644
--- a/packages/rocketchat-external/app/.meteor/versions
+++ b/packages/rocketchat-external/app/.meteor/versions
@@ -1,3 +1,4 @@
+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
diff --git a/packages/rocketchat-external/app/client/lib/avatar.coffee b/packages/rocketchat-external/app/client/lib/avatar.coffee
new file mode 100644
index 000000000000..7988062501b2
--- /dev/null
+++ b/packages/rocketchat-external/app/client/lib/avatar.coffee
@@ -0,0 +1,18 @@
+@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
diff --git a/packages/rocketchat-external/app/client/lib/chatMessages.coffee b/packages/rocketchat-external/app/client/lib/chatMessages.coffee
new file mode 100644
index 000000000000..041d6586abd7
--- /dev/null
+++ b/packages/rocketchat-external/app/client/lib/chatMessages.coffee
@@ -0,0 +1,193 @@
+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
diff --git a/packages/rocketchat-external/app/client/lib/collections.coffee b/packages/rocketchat-external/app/client/lib/collections.coffee
new file mode 100644
index 000000000000..c658d09a0fc0
--- /dev/null
+++ b/packages/rocketchat-external/app/client/lib/collections.coffee
@@ -0,0 +1 @@
+@ChatMessage = new Meteor.Collection null
diff --git a/packages/rocketchat-external/app/client/lib/underscore.string.js b/packages/rocketchat-external/app/client/lib/underscore.string.js
new file mode 100644
index 000000000000..6c0564b8be5f
--- /dev/null
+++ b/packages/rocketchat-external/app/client/lib/underscore.string.js
@@ -0,0 +1,5 @@
+// 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())
diff --git a/packages/rocketchat-external/app/client/methods/sendMessageExternal.coffee b/packages/rocketchat-external/app/client/methods/sendMessageExternal.coffee
new file mode 100644
index 000000000000..50e3366ec9a1
--- /dev/null
+++ b/packages/rocketchat-external/app/client/methods/sendMessageExternal.coffee
@@ -0,0 +1,18 @@
+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
diff --git a/packages/rocketchat-external/app/client/routes/router.coffee b/packages/rocketchat-external/app/client/routes/router.coffee
new file mode 100644
index 000000000000..559a3ed8e4b1
--- /dev/null
+++ b/packages/rocketchat-external/app/client/routes/router.coffee
@@ -0,0 +1,5 @@
+FlowRouter.route '/',
+ name: 'index'
+
+ action: ->
+ BlazeLayout.render 'main', {center: 'room'}
diff --git a/packages/rocketchat-external/app/client/stylesheets/main.less b/packages/rocketchat-external/app/client/stylesheets/main.less
new file mode 100644
index 000000000000..fc874885348f
--- /dev/null
+++ b/packages/rocketchat-external/app/client/stylesheets/main.less
@@ -0,0 +1,32 @@
+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;
+ }
+}
diff --git a/packages/rocketchat-external/app/client/test.html b/packages/rocketchat-external/app/client/test.html
deleted file mode 100644
index 1db3493c0e24..000000000000
--- a/packages/rocketchat-external/app/client/test.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/packages/rocketchat-external/app/client/test.js b/packages/rocketchat-external/app/client/test.js
deleted file mode 100644
index 161be057a727..000000000000
--- a/packages/rocketchat-external/app/client/test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-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
diff --git a/packages/rocketchat-external/app/client/views/avatar.coffee b/packages/rocketchat-external/app/client/views/avatar.coffee
new file mode 100644
index 000000000000..b0abe8754a17
--- /dev/null
+++ b/packages/rocketchat-external/app/client/views/avatar.coffee
@@ -0,0 +1,14 @@
+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});"
diff --git a/packages/rocketchat-external/app/client/views/avatar.html b/packages/rocketchat-external/app/client/views/avatar.html
new file mode 100644
index 000000000000..70781f54c7b5
--- /dev/null
+++ b/packages/rocketchat-external/app/client/views/avatar.html
@@ -0,0 +1,5 @@
+
+
You've pressed the button {{counter}} times.
- diff --git a/packages/rocketchat-external/app/empty.js b/packages/rocketchat-external/app/empty.js deleted file mode 100644 index 9096b102199f..000000000000 --- a/packages/rocketchat-external/app/empty.js +++ /dev/null @@ -1,10 +0,0 @@ -if (Meteor.isClient) { - // counter starts at 0 - Session.setDefault('counter', 0); -} - -if (Meteor.isServer) { - Meteor.startup(function () { - // code to run on server at startup - }); -} diff --git a/packages/rocketchat-external/methods.coffee b/packages/rocketchat-external/methods.coffee new file mode 100644 index 000000000000..10e73670c916 --- /dev/null +++ b/packages/rocketchat-external/methods.coffee @@ -0,0 +1,3 @@ +Meteor.methods + sendMessageExternal: -> + console.log 'sendMessageExternal ->',arguments diff --git a/packages/rocketchat-external/package.js b/packages/rocketchat-external/package.js index a9857031ae46..e6125c609f27 100755 --- a/packages/rocketchat-external/package.js +++ b/packages/rocketchat-external/package.js @@ -23,6 +23,7 @@ Package.onUse(function(api) { api.use('autoupdate', 'server'); api.addFiles('external.coffee', 'server'); + api.addFiles('methods.coffee', 'server'); api.addFiles('public/external.css', 'client', {isAsset: true}); api.addFiles('public/external.js', 'client', {isAsset: true});