Created
August 24, 2015 08:30
-
-
Save GrahamLinagora/364d1abe0a9cfa948b25 to your computer and use it in GitHub Desktop.
2 users with history patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| '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 | |
| }; | |
| }]); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @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