Skip to content

Instantly share code, notes, and snippets.

@GrahamLinagora
Created August 24, 2015 08:30
Show Gist options
  • Select an option

  • Save GrahamLinagora/364d1abe0a9cfa948b25 to your computer and use it in GitHub Desktop.

Select an option

Save GrahamLinagora/364d1abe0a9cfa948b25 to your computer and use it in GitHub Desktop.
2 users with history patch
'use strict';
angular.module('esn.chat')
.factory('ChatMessage', function() {
function ChatMessage(object) {
this.author = object.author;
this.authorAvatar = object.authorAvatar;
this.published = object.published;
this.message = object.message;
this.displayName = object.displayName;
}
return ChatMessage;
})
.factory('yArraySynchronizer', ['yjsService', '$window', function(yjsService, $window) {
function onChange(jsArray) {
return function(events) {
events.forEach(function(event) {
var type = event.type,
value = event.value,
position = event.position;
if (type === 'delete') {
jsArray.splice(position, 1);
} else if (type === 'insert') {
console.log('onChange: new event', position, 0, value);
jsArray.splice(position, 0, value);
} else if (type === 'update') {
jsArray[position] = value;
}
});
};
}
function mapToYList(id, jsArray, callback) {
callback = callback || function() {};
var observer = 1;
var y = yjsService.y;
yjsService.connector.whenSynced(function() {
var ylist = y.val(id);
console.log('time0 ylist ', ylist);
var onChangeObserver = onChange(jsArray);
y.observe(function(events) {
var me = observer;
observer++;
events.filter(function(event) {
console.log('event', event.name, event.type);
return event.name === id;
}).forEach(function() {
console.log('observer ', me);
var newYList = y.val(id);
if (ylist !== newYList) {
console.log('replacing ylist id', id);
var olds = ylist.val();
ylist = newYList;
olds.forEach(ylist.push.bind(ylist));
ylist.observe(onChangeObserver);
callback(ylist);
}
});
});
if (!ylist) {
console.log('new list')
ylist = new $window.Y.List(jsArray);
y.val(id, ylist);
}
ylist.observe(onChangeObserver);
callback(ylist);
});
}
return mapToYList;
}])
.factory('yListToMessages', ['ChatMessage', function(ChatMessage) {
return function yListToMessages(ylist, messages) {
var ymsgs = ylist.val();
ymsgs.forEach(function(msg) {
messages.push(new ChatMessage(msg));
});
};
}])
.factory('chat', ['$rootScope', 'yjsService', 'yArraySynchronizer', 'yListToMessages',
function($rootScope, yjsService, yArraySynchronizer, yListToMessages) {
function sendMessage(chatMessage) {
if (!chatMessage) {
throw new Error('No message provided');
}
(ret.yMessages || ret.messages).push(chatMessage);
$rootScope.$broadcast('chat:message:sent', chatMessage);
}
function toggleWindow() {
ret.opened = !ret.opened;
ret.unread = ret.opened ? 0 : ret.unread;
$rootScope.$broadcast('chat:window:visibility', {visible: ret.opened});
}
var ret = {
yMessages: null,
messages: [],
opened: false,
unread: 0,
toggleWindow: toggleWindow,
sendMessage: sendMessage
};
var callback = function(yList) {
ret.yMessages = yList;
// yJS will send us back the messages we sent before being connected to peers
// that's why we flush messages
var oldLenth = ret.messages.length;
var oldyListLength = ret.yMessages.val().length;
ret.messages.splice(0, ret.messages.length);
yListToMessages(ret.yMessages, ret.messages);
console.log('========================== initialized yListToMessages with', ret.yMessages.val(), ret.messages);
console.log('========================== ', oldLenth, oldyListLength);
$rootScope.$applyAsync();
ret.yMessages.observe(function(events) {
events.forEach(function(event) {
if (event.type === 'insert') {
$rootScope.$broadcast('chat:message:received', event.value);
console.log('had new event', event.value);
if (ret.opened) {
ret.unread = 0;
} else {
ret.unread++;
}
} else if (event.type === 'update') {
// Don't do anything for now!
} else if (event.type === 'delete') {
// Don't do anything for now!
}
});
});
};
yArraySynchronizer('chat:messages', ret.messages, callback);
return ret;
}])
.factory('messageAvatarService', ['newCanvas', 'currentConferenceState', 'attendeeColorsService', 'drawHelper', 'CHAT_AVATAR_SIZE', 'DEFAULT_AVATAR', function(newCanvas, currentConferenceState, attendeeColorsService, drawHelper, CHAT_AVATAR_SIZE, DEFAULT_AVATAR) {
function generate(author, callback) {
var attendee = currentConferenceState.getAttendeeByEasyrtcid(author);
if (!attendee || !attendee.avatar) {
return callback(null, DEFAULT_AVATAR);
}
currentConferenceState.getAvatarImageByIndex(attendee.index, function(err, image) {
if (err) {
return callback(null, DEFAULT_AVATAR);
}
var canvas = newCanvas(CHAT_AVATAR_SIZE, CHAT_AVATAR_SIZE),
context = canvas.getContext('2d');
context.fillStyle = attendeeColorsService.getColorForAttendeeAtIndex(attendee.index);
context.fillRect(0, 0, CHAT_AVATAR_SIZE, CHAT_AVATAR_SIZE);
drawHelper.drawImage(context, image, 0, 0, CHAT_AVATAR_SIZE, CHAT_AVATAR_SIZE);
return callback(null, canvas.toDataURL());
});
}
return {
generate: generate
};
}]);
@chat-window-width: 300px;
@chat-window-height: 250px;
@user-control-bar-height: 50px;
@screen-md: 992px;
@chat-main-background: rgba(27, 27, 27, 0.6);
@chat-header-background: rgb(51, 109, 190, .6);
@message-background: rgb(255, 255, 255);
@new-message-background: rgb(223, 235, 251);
@chat-transition-speed: 0.2s;
@new-message-animation-length: 4s;
.chat-window-wrapper {
display: block;
position: absolute;
bottom: @user-control-bar-height;
right: 0px;
z-index: 5;
transition: opacity @chat-transition-speed ease-in;
pointer-events: none;
opacity: 0;
width: @chat-window-width;
height: @chat-window-height;
@media screen and (min-width: @screen-md) {
height: 100%;
bottom: 0;
}
chat-message-display {
display: block;
transition: transform 0s ease-in;
transform: translate3d(300px, 0, 0);
}
&.visible {
opacity: 1;
pointer-events: auto;
chat-message-display {
transform: translate3d(0, 0, 0);
}
}
}
.chat-window {
button.close {
color:#fff; text-shadow: none; opacity: 0.9
}
width: 100%;
height: 100%;
background: @chat-main-background;
.flexbox-parent {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start; /* align items in Main Axis */
align-items: stretch; /* align items in Cross Axis */
align-content: stretch; /* Extra space in Cross Axis */
}
.flexbox-item {
padding: 8px;
}
.flexbox-item-grow {
flex: 1; /* same as flex: 1 1 auto; */
}
.flexbox-item.header {
background-color: @chat-header-background;
}
.flexbox-item.footer {
.send-button {
padding: 3px 10px 0px 10px;
.svg-button {
width:24px;
height:20px;
}
}
}
.flexbox-item.content {
}
.fill-area {
display: flex;
flex-direction: row;
justify-content: flex-start; /* align items in Main Axis */
align-items: stretch; /* align items in Cross Axis */
align-content: stretch; /* Extra space in Cross Axis */
min-height: 0; // get scrolling on firefox: http://stackoverflow.com/a/14964944
}
.fill-area-content {
//background: #e5e5e5;
/* Needed for when the area gets squished too far and there is content that can't be displayed */
overflow: auto;
.ng-move {
transition-duration: 0;
}
}
.chat {
height: 100%;
}
.msg-container-base {
margin: 0;
padding: 0 0px 0px;
overflow-x: hidden;
}
.top-bar {
color: #FFF;
padding: 0;
position: relative;
overflow: hidden;
}
.msg-receive {
padding-left: 0;
margin-left: 0;
}
.msg-sent {
padding-bottom: 10px;
margin-right: 0;
}
.messages {
background: @message-background;
padding: 10px;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
max-width: 100%;
width: 100%;
p {
font-size: 13px;
margin: 0 0 0.2rem 0;
line-height: 1;
text-align: justify;
color: #333;
}
.author {
font-size: 12px;
color: #777;
font-weight: bold;
}
.divider {
margin: 0 2px;
}
.published {
font-style: italic;
}
.avatar {
float: left;
margin-right: 8px;
}
&.myself {
.avatar {
float: right;
margin-left: 8px;
}
}
}
.msg-container {
padding-bottom: 10px;
padding-right: 0px;
padding-left: 0px;
overflow: hidden;
display: flex;
}
img {
display: block;
width: 48px;
height: 48px;
}
.avatar {
padding-left: 3px;
position: relative;
}
.base-sent {
justify-content: flex-end;
align-items: flex-end;
}
.msg-container-base::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #F5F5F5;
}
.msg-container-base::-webkit-scrollbar {
width: 12px;
background-color: #F5F5F5;
}
.msg-container-base::-webkit-scrollbar-thumb {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
background-color: #555;
}
chat-message-display.ng-enter {
animation: enter_sequence @new-message-animation-length linear;
transform-origin: bottom;
}
chat-message-display.ng-enter .messages{
animation: enter_sequence_message @new-message-animation-length linear;
}
}
.popover-cursor {
cursor: pointer;
}
.notificationButton {
.badge {
position: absolute;
right: 0;
bottom: -5px;
padding: 3px 5px;
&.danger {
background-color: #d9534f;
color: white;
}
}
}
@keyframes enter_sequence {
0% { transform: scale(0); }
2% { transform: scale(1); }
100% { transform: scale(1);}
}
@keyframes enter_sequence_message {
0% { background-color: @new-message-background;}
90% { background-color: @new-message-background;}
100% { background-color: @message-background; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment