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

Merge pull request #1636 from RocketChat/livechat-popout

Livechat popout
parents 3930c7ab 0231db98
No related branches found
No related tags found
No related merge requests found
Showing
with 759 additions and 216 deletions
......@@ -9,7 +9,4 @@ FlowRouter.route '/livechat',
]
action: ->
if Meteor.userId()
BlazeLayout.render 'main', {center: 'room'}
else
BlazeLayout.render 'main', {center: 'register'}
BlazeLayout.render 'main', {center: 'room'}
@header-min-height: 30px;
@footer-min-height: 52px;
@footer-min-height: 42px;
@rooms-box-width: 260px;
@flex-tab-width: 400px;
......
This diff is collapsed.
......@@ -49,7 +49,7 @@ input:focus {
height: 100%;
.title {
flex: 1 1 @header-min-height;
flex: 1 0 @header-min-height;
line-height: @header-min-height;
......@@ -62,8 +62,13 @@ input:focus {
margin: 0;
padding: 0 5px;
font-size: 9pt;
display: table-cell;
vertical-align: middle;
display: inline-block;
}
.toolbar {
display: inline-block;
float: right;
padding-right: 5px;
}
}
.messages {
......@@ -286,7 +291,7 @@ input:focus {
}
}
.footer {
flex: 1 1 @footer-min-height;
flex: 1 0 @footer-min-height;
z-index: 10;
......@@ -320,62 +325,30 @@ input:focus {
}
}
.livechat-registration {
position: fixed;
top: 0;
bottom: 0;
.title {
border-top-right-radius: 5px;
border-top-left-radius: 5px;
color: #FFF;
position: fixed;
top: 0;
width: 100%;
height: @header-min-height;
display: table;
z-index: 10;
cursor: pointer;
h1 {
margin: 0;
padding: 0 5px;
font-size: 9pt;
display: table-cell;
vertical-align: middle;
}
}
.livechat-form {
display: block;
background-color: #FFF;
top: @header-min-height;
bottom: @footer-min-height;
border-left: 1px solid #E7E7E7;
border-right: 1px solid #E7E7E7;
position: fixed;
width: 100%;
.wrapper {
height: 100%;
overflow-y: auto;
padding-bottom: 6px;
.livechat-form {
flex: 1 1 100%;
display: block;
background-color: #FFF;
border-left: 1px solid #E7E7E7;
border-right: 1px solid #E7E7E7;
input, button {
display: block;
padding: 5px;
margin: 5px;
}
}
.error {
bottom: 50px;
position: fixed;
width: 100%;
background-color: #F7D799;
padding: 5px;
input, button {
display: block;
padding: 5px;
margin: 5px;
}
.error {
display: none;
// width: 100%;
background-color: #F7D799;
padding: 5px;
.transition(transform 0.3s ease-out);
.transform(translateY(200%));
// .transition(transform 0.3s ease-out);
// .transform(translateY(-100%));
&.show {
.transform(translateY(8px));
}
&.show {
display: block;
// .transform(translateY(0px));
}
}
}
......
<template name="messages">
<div class="messages">
<div class="wrapper">
<ul>
{{#each messages}}
{{#nrr nrrargs 'message' .}}{{/nrr}}
{{/each}}
</ul>
</div>
<div class="new-message not">
<span>New messages</span>
</div>
<div class="error">
<span></span>
</div>
</div>
<div class="footer">
<div class="input-wrapper">
<textarea class="input-message" placeholder="Type your message"></textarea>
</div>
</div>
</template>
Template.messages.helpers({
messages: function() {
return ChatMessage.find({
rid: visitor.getRoom(),
t: {
'$ne': 't'
}
}, {
sort: {
ts: 1
}
});
},
});
Template.messages.events({
'keyup .input-message': function(event) {
// Inital height is 28. If the scrollHeight is greater than that( we have more text than area ),
// increase the size of the textarea. The max-height is set at 200
// even if the scrollHeight become bigger than that it should never exceed that.
// Account for no text in the textarea when increasing the height.
// If there is no text, reset the height.
var inputScrollHeight;
Template.instance().chatMessages.keyup(visitor.getRoom(), event, Template.instance());
inputScrollHeight = $(event.currentTarget).prop('scrollHeight');
if (inputScrollHeight > 28) {
return $(event.currentTarget).height($(event.currentTarget).val() === '' ? '15px' : (inputScrollHeight >= 200 ? inputScrollHeight - 50 : inputScrollHeight - 20));
}
},
'keydown .input-message': function(event) {
return Template.instance().chatMessages.keydown(visitor.getRoom(), event, Template.instance());
},
'click .new-message': function() {
Template.instance().atBottom = true;
return Template.instance().find('.input-message').focus();
},
'click .error': function(event) {
return $(event.currentTarget).removeClass('show');
},
});
Template.messages.onCreated(function() {
var self;
self = this;
self.autorun(function() {
self.subscribe('livechat:visitorRoom', visitor.getToken(), function() {
var room;
room = ChatRoom.findOne();
if (room != null) {
visitor.setRoom(room._id);
RoomHistoryManager.getMoreIfIsEmpty(room._id);
}
});
});
self.subscribe('settings', ['Livechat_title', 'Livechat_title_color']);
self.atBottom = true;
});
Template.messages.onRendered(function() {
this.chatMessages = new ChatMessages;
this.chatMessages.init(this.firstNode);
});
Template.messages.onRendered(function() {
var messages, newMessage, onscroll, template;
messages = this.find('.messages');
newMessage = this.find(".new-message");
template = this;
if (messages) {
onscroll = _.throttle(function() {
template.atBottom = messages.scrollTop >= messages.scrollHeight - messages.clientHeight;
}, 200);
Meteor.setInterval(function() {
if (template.atBottom) {
messages.scrollTop = messages.scrollHeight - messages.clientHeight;
newMessage.className = "new-message not";
}
}, 100);
messages.addEventListener('touchstart', function() {
template.atBottom = false;
});
messages.addEventListener('touchend', function() {
onscroll();
});
messages.addEventListener('scroll', function() {
template.atBottom = false;
onscroll();
});
messages.addEventListener('mousewheel', function() {
template.atBottom = false;
onscroll();
});
messages.addEventListener('wheel', function() {
template.atBottom = false;
onscroll();
});
}
});
......@@ -21,21 +21,30 @@ Template.register.events
$email = instance.$('input[name=email]')
unless $name.val().trim() and $email.val().trim()
instance.error.set(TAPi18n.__('Please_fill_name_and_email'))
return instance.showError TAPi18n.__('Please_fill_name_and_email')
else
Meteor.call 'registerGuest', visitor.getToken(), $name.val(), $email.val(), (error, result) ->
if error?
return instance.error.set error.reason
return instance.showError error.reason
Meteor.loginWithPassword result.user, result.pass, (error) ->
if error
return instance.error.set error.reason
BlazeLayout.render 'main', {center: 'room'}
return instance.showError error.reason
'click .error': (e, instance) ->
instance.error.set()
instance.hideError()
Template.register.onCreated ->
@subscribe 'settings', ['Livechat_title', 'Livechat_title_color']
@error = new ReactiveVar
@showError = (msg) =>
$('.error').addClass('show')
@error.set msg
return
@hideError = =>
$('.error').removeClass('show')
@error.set()
return
<template name="register">
<div class="livechat-registration">
<div class="title" style="background-color:{{color}}">
<h1>{{title}}</h1>
<form id="livechat-registration" class="livechat-form">
<div class="error">
<span>{{error}}</span>
</div>
<form id="livechat-registration" class="livechat-form">
<div class="wrapper">
<label>
{{{welcomeMessage}}}
</label>
<input type="text" name="name" id="guestName" placeholder="{{_ "Name"}}">
<input type="email" name="email" id="guestEmail" placeholder="{{_ "E-mail"}}">
<button type="submit" id="btnEntrar" class="-btn"> {{_ "Start_Chat"}} </button>
</div>
{{#if error}}
<div class="error show">
<span>{{error}}</span>
</div>
{{/if}}
</form>
</div>
<label>
{{{welcomeMessage}}}
</label>
<input type="text" name="name" id="guestName" placeholder="{{_ "Name"}}">
<input type="email" name="email" id="guestEmail" placeholder="{{_ "E-mail"}}">
<button type="submit" id="btnEntrar" class="-btn"> {{_ "Start_Chat"}} </button>
</form>
</template>
Template.room.helpers
messages: ->
return ChatMessage.find { rid: visitor.getRoom(), t: { '$ne': 't' } }, { sort: { ts: 1 } }
title: ->
return '' unless Template.instance().subscriptionsReady()
return Settings.findOne('Livechat_title')?.value or 'Rocket.Chat'
color: ->
return 'transparent' unless Template.instance().subscriptionsReady()
return Settings.findOne('Livechat_title_color')?.value or '#C1272D'
Template.room.events
'keyup .input-message': (event) ->
Template.instance().chatMessages.keyup(visitor.getRoom(), event, Template.instance())
# Inital height is 28. If the scrollHeight is greater than that( we have more text than area ),
# increase the size of the textarea. The max-height is set at 200
# even if the scrollHeight become bigger than that it should never exceed that.
# Account for no text in the textarea when increasing the height.
# If there is no text, reset the height.
inputScrollHeight = $(event.currentTarget).prop('scrollHeight')
if inputScrollHeight > 28
$(event.currentTarget).height( if $(event.currentTarget).val() == '' then '15px' else (if inputScrollHeight >= 200 then inputScrollHeight-50 else inputScrollHeight-20))
'keydown .input-message': (event) ->
Template.instance().chatMessages.keydown(visitor.getRoom(), event, Template.instance())
'click .new-message': (e) ->
Template.instance().atBottom = true
Template.instance().find('.input-message').focus()
'click .title': ->
parentCall 'toggleWindow'
'click .error': (e) ->
$(e.currentTarget).removeClass('show')
Template.room.onCreated ->
self = @
self.autorun ->
self.subscribe 'livechat:visitorRoom', visitor.getToken(), ->
room = ChatRoom.findOne()
if room?
visitor.setRoom room._id
RoomHistoryManager.getMoreIfIsEmpty room._id
self.subscribe 'settings', ['Livechat_title', 'Livechat_title_color']
self.atBottom = true
Template.room.onRendered ->
unless Meteor.userId()
return BlazeLayout.render 'main', {center: 'register'}
this.chatMessages = new ChatMessages
this.chatMessages.init(this.firstNode)
Template.room.onRendered ->
messages = this.find('.messages')
newMessage = this.find(".new-message")
template = this
onscroll = _.throttle ->
template.atBottom = messages.scrollTop >= messages.scrollHeight - messages.clientHeight
, 200
Meteor.setInterval ->
if template.atBottom
messages.scrollTop = messages.scrollHeight - messages.clientHeight
newMessage.className = "new-message not"
, 100
messages.addEventListener 'touchstart', ->
template.atBottom = false
messages.addEventListener 'touchend', ->
onscroll()
# readMessage.enable()
# readMessage.read()
messages.addEventListener 'scroll', ->
template.atBottom = false
onscroll()
messages.addEventListener 'mousewheel', ->
template.atBottom = false
onscroll()
# readMessage.enable()
# readMessage.read()
messages.addEventListener 'wheel', ->
template.atBottom = false
onscroll()
# readMessage.enable()
# readMessage.read()
# salva a data da renderização para exibir alertas de novas mensagens
# $.data(this.firstNode, 'renderedAt', new Date)
<template name="room">
<div class="livechat-room">
<div class="title" style="background-color:{{color}}">
<h1>{{title}}</h1>
</div>
<div class="messages">
<div class="wrapper">
<ul>
{{#each messages}}
{{#nrr nrrargs 'message' .}}{{/nrr}}
{{/each}}
</ul>
</div>
<div class="new-message not">
<span>New messages</span>
</div>
<div class="error">
<span></span>
</div>
</div>
<div class="footer">
<div class="input-wrapper">
<textarea class="input-message" placeholder="Type your message"></textarea>
<div class="toolbar">
{{#unless popoutActive}}
<i class="popout icon-link-ext" title="Open in a new window"></i>
{{/unless}}
</div>
<h1>{{title}}</h1>
</div>
{{#if currentUser}}
{{> messages}}
{{else}}
{{> register}}
{{/if}}
</div>
</template>
Template.room.helpers({
title: function() {
var ref;
if (!Template.instance().subscriptionsReady()) {
return '';
}
return ((ref = Settings.findOne('Livechat_title')) != null ? ref.value : void 0) || 'Rocket.Chat';
},
color: function() {
var ref;
if (!Template.instance().subscriptionsReady()) {
return 'transparent';
}
return ((ref = Settings.findOne('Livechat_title_color')) != null ? ref.value : void 0) || '#C1272D';
},
popoutActive: function() {
return FlowRouter.getQueryParam('mode') === 'popout';
}
});
Template.room.events({
'click .title': function() {
console.log('toggleWindow');
return parentCall('toggleWindow');
},
'click .popout': function(event) {
event.stopPropagation();
parentCall('openPopout');
}
});
......@@ -8,12 +8,14 @@
var h = d.getElementsByTagName(s)[0],
j = d.createElement(s);
j.async = true;
j.src = '/packages/rocketchat_livechat/rocket-livechat.js';
j.src = '/packages/rocketchat_livechat/assets/rocket-livechat.js';
h.parentNode.insertBefore(j, h);
})(window, document, 'script', 'initRocket', '/livechat');
</script>
</head>
<!-- Access: http://localhost:3000/packages/rocketchat_livechat/assets/demo.html -->
<body style="background-color: #EFEFEF">
<h1 style="color:#000">test</h1>
<p style="color:#000">Talk to us.</p>
......
......@@ -4,24 +4,38 @@
// var h = d.getElementsByTagName(s)[0],
// j = d.createElement(s);
// j.async = true;
// j.src = 'rocket-livechat.js';
// j.src = '/packages/rocketchat_livechat/assets/rocket-livechat.js';
// h.parentNode.insertBefore(j, h);
// })(window, document, 'script', 'initRocket', 'http://localhost:5000/livechat');
// </script>
;(function(w) {
var exports = {};
var config = {};
var widget;
var closeWidget = () => {
widget.dataset.state = 'closed';
widget.style.height = '30px';
};
var openWidget = () => {
widget.dataset.state = 'opened';
widget.style.height = '300px';
};
var api = {
toggleWindow: function() {
var widget = document.querySelector('.rocketchat-widget');
toggleWindow: function(forceClose) {
if (widget.dataset.state === 'closed') {
widget.dataset.state = 'opened';
widget.style.height = '300px';
openWidget();
} else {
widget.dataset.state = 'closed';
widget.style.height = '30px';
closeWidget();
}
},
openPopout: function() {
closeWidget();
var popup = window.open(config.url + '?mode=popout', 'livechat-popout', 'width=400, height=450, toolbars=no');
popup.focus();
}
};
......@@ -30,6 +44,8 @@
return;
}
config.url = url;
var chatWidget = document.createElement('div');
chatWidget.dataset.state = 'closed';
chatWidget.className = 'rocketchat-widget';
......@@ -48,6 +64,8 @@
document.getElementsByTagName('body')[0].appendChild(chatWidget);
widget = document.querySelector('.rocketchat-widget');
w.addEventListener('message', function(msg) {
if (typeof msg.data === 'object' && msg.data.src !== undefined && msg.data.src === 'rocketchat') {
if (api[msg.data.fn] !== undefined && typeof api[msg.data.fn] === 'function') {
......
......@@ -70,7 +70,8 @@ Package.onUse(function(api) {
api.addFiles('server/publications/visitorRoom.js', 'server');
// livechat app
api.addAssets('rocket-livechat.js', 'client');
api.addAssets('assets/demo.html', 'client');
api.addAssets('assets/rocket-livechat.js', 'client');
api.addAssets('public/livechat.css', 'client');
api.addAssets('public/livechat.js', 'client');
api.addAssets('public/head.html', 'server');
......
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