/
messages.ts
130 lines (110 loc) · 3.37 KB
/
messages.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { Component, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { NavParams } from 'ionic-angular';
import { Chat, Message, MessageType } from 'api/models';
import { Messages } from 'api/collections';
import { MeteorObservable } from 'meteor-rxjs';
import * as moment from 'moment';
import * as _ from 'lodash';
@Component({
selector: 'messages-page',
templateUrl: 'messages.html'
})
export class MessagesPage implements OnInit, OnDestroy {
selectedChat: Chat;
title: string;
picture: string;
messagesDayGroups;
message: string = '';
autoScroller: MutationObserver;
scrollOffset = 0;
senderId: string;
constructor(
navParams: NavParams,
private el: ElementRef
) {
this.selectedChat = <Chat>navParams.get('chat');
this.title = this.selectedChat.title;
this.picture = this.selectedChat.picture;
this.senderId = Meteor.userId();
}
private get messagesPageContent(): Element {
return this.el.nativeElement.querySelector('.messages-page-content');
}
private get messagesList(): Element {
return this.messagesPageContent.querySelector('.messages');
}
private get scroller(): Element {
return this.messagesList.querySelector('.scroll-content');
}
ngOnInit() {
this.autoScroller = this.autoScroll();
this.subscribeMessages();
}
ngOnDestroy() {
this.autoScroller.disconnect();
}
subscribeMessages() {
this.scrollOffset = this.scroller.scrollHeight;
this.messagesDayGroups = this.findMessagesDayGroups();
}
findMessagesDayGroups() {
return Messages.find({
chatId: this.selectedChat._id
}, {
sort: { createdAt: 1 }
})
.map((messages: Message[]) => {
const format = 'D MMMM Y';
// Compose missing data that we would like to show in the view
messages.forEach((message) => {
message.ownership = this.senderId == message.senderId ? 'mine' : 'other';
return message;
});
// Group by creation day
const groupedMessages = _.groupBy(messages, (message) => {
return moment(message.createdAt).format(format);
});
// Transform dictionary into an array since Angular's view engine doesn't know how
// to iterate through it
return Object.keys(groupedMessages).map((timestamp: string) => {
return {
timestamp: timestamp,
messages: groupedMessages[timestamp],
today: moment().format(format) === timestamp
};
});
});
}
autoScroll(): MutationObserver {
const autoScroller = new MutationObserver(this.scrollDown.bind(this));
autoScroller.observe(this.messagesList, {
childList: true,
subtree: true
});
return autoScroller;
}
scrollDown(): void {
// Scroll down and apply specified offset
this.scroller.scrollTop = this.scroller.scrollHeight - this.scrollOffset;
// Zero offset for next invocation
this.scrollOffset = 0;
}
onInputKeypress({ keyCode }: KeyboardEvent): void {
if (keyCode === 13) {
this.sendTextMessage();
}
}
sendTextMessage(): void {
// If message was yet to be typed, abort
if (!this.message) {
return;
}
MeteorObservable.call('addMessage', MessageType.TEXT,
this.selectedChat._id,
this.message
).zone().subscribe(() => {
// Zero the input field
this.message = '';
});
}
}