@chat21/chat21-web-widget 5.0.59-rc.1 → 5.0.59-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/src/app/app.component.scss +64 -0
- package/src/app/component/last-message/last-message.component.scss +9 -9
- package/src/app/component/last-message/last-message.component.ts +3 -1
- package/src/app/component/message/bubble-message/bubble-message.component.html +1 -1
- package/src/app/component/message/buttons/action-button/action-button.component.html +1 -1
- package/src/app/component/message/buttons/link-button/link-button.component.html +2 -1
- package/src/app/component/message/buttons/text-button/text-button.component.html +5 -5
- package/src/app/component/message/image/image.component.html +0 -4
- package/src/app/component/message/info-message/info-message.component.html +1 -1
- package/src/app/directives/tooltip.directive.ts +117 -29
- package/src/chat21-core/utils/utils-message.ts +3 -0
- package/src/chat21-core/utils/utils.ts +20 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# chat21-web-widget ver 5.0
|
|
2
2
|
|
|
3
|
+
### 5.0.59-rc.2
|
|
4
|
+
- added: handler for buttons in last-message component
|
|
5
|
+
- changed: tooltip custom directive
|
|
6
|
+
- changed: user-avatar size in last-message component
|
|
7
|
+
|
|
3
8
|
### 5.0.59-rc.1
|
|
4
9
|
- added: hashing while building dist files
|
|
5
10
|
|
package/package.json
CHANGED
|
@@ -208,6 +208,8 @@ textarea::placeholder {
|
|
|
208
208
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
|
|
212
|
+
// TOOLTIP: start
|
|
211
213
|
.tooltip-container {
|
|
212
214
|
font-family: 'Roboto','Google Sans', Helvetica, Arial, sans-serif;
|
|
213
215
|
font-size: 12px;
|
|
@@ -245,6 +247,68 @@ textarea::placeholder {
|
|
|
245
247
|
}
|
|
246
248
|
}
|
|
247
249
|
|
|
250
|
+
.ng-tooltip {
|
|
251
|
+
position: absolute;
|
|
252
|
+
max-width: 150px;
|
|
253
|
+
font-size: 14px;
|
|
254
|
+
text-align: center;
|
|
255
|
+
color: black;
|
|
256
|
+
padding: 3px 8px;
|
|
257
|
+
background:rgb(255, 255, 255);
|
|
258
|
+
-webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.3);
|
|
259
|
+
box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.3);
|
|
260
|
+
border-radius: 10px;
|
|
261
|
+
z-index: 1000;
|
|
262
|
+
opacity: 0;
|
|
263
|
+
|
|
264
|
+
font-family: 'Roboto','Google Sans', Helvetica, Arial, sans-serif;
|
|
265
|
+
font-size: 12px;
|
|
266
|
+
font-style: normal;
|
|
267
|
+
letter-spacing: normal;
|
|
268
|
+
font-stretch: normal;
|
|
269
|
+
font-variant: normal;
|
|
270
|
+
font-weight: 300;
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
.ng-tooltip:after {
|
|
274
|
+
content: "";
|
|
275
|
+
position: absolute;
|
|
276
|
+
border-style: solid;
|
|
277
|
+
}
|
|
278
|
+
.ng-tooltip-top:after {
|
|
279
|
+
top: 100%;
|
|
280
|
+
left: 50%;
|
|
281
|
+
margin-left: -5px;
|
|
282
|
+
border-width: 5px;
|
|
283
|
+
border-color: rgb(255, 255, 255) transparent transparent transparent;
|
|
284
|
+
}
|
|
285
|
+
.ng-tooltip-bottom:after {
|
|
286
|
+
bottom: 100%;
|
|
287
|
+
left: 50%;
|
|
288
|
+
margin-left: -5px;
|
|
289
|
+
border-width: 5px;
|
|
290
|
+
border-color: transparent transparent rgb(255, 255, 255) transparent;
|
|
291
|
+
}
|
|
292
|
+
.ng-tooltip-left:after {
|
|
293
|
+
top: 50%;
|
|
294
|
+
left: 100%;
|
|
295
|
+
margin-top: -5px;
|
|
296
|
+
border-width: 5px;
|
|
297
|
+
border-color: transparent transparent transparent rgb(255, 255, 255);
|
|
298
|
+
}
|
|
299
|
+
.ng-tooltip-right:after {
|
|
300
|
+
top: 50%;
|
|
301
|
+
right: 100%;
|
|
302
|
+
margin-top: -5px;
|
|
303
|
+
border-width: 5px;
|
|
304
|
+
border-color: transparent rgb(255, 255, 255) transparent transparent;
|
|
305
|
+
}
|
|
306
|
+
.ng-tooltip-show {
|
|
307
|
+
opacity: 1;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
//TOOLTIP : end
|
|
311
|
+
|
|
248
312
|
chat-root {
|
|
249
313
|
position: absolute;
|
|
250
314
|
display: block;
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
:host .c21-avatar-image ::ng-deep > chat-avatar-image {
|
|
4
4
|
|
|
5
5
|
.c21-icon-avatar {
|
|
6
|
-
height:
|
|
7
|
-
width:
|
|
8
|
-
min-width:
|
|
9
|
-
min-height:
|
|
6
|
+
height: 38px;
|
|
7
|
+
width: 38px;
|
|
8
|
+
min-width: 38px;
|
|
9
|
+
min-height: 38px;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
:host .previewNewMessagge ::ng-deep > chat-bubble-message > #bubble-message > div > div > chat-text {
|
|
@@ -152,10 +152,10 @@
|
|
|
152
152
|
|
|
153
153
|
.c21-icon-avatar {
|
|
154
154
|
position: absolute;
|
|
155
|
-
width:
|
|
156
|
-
height:
|
|
155
|
+
width: 38px;
|
|
156
|
+
height: 38px;
|
|
157
157
|
bottom: 0px;
|
|
158
|
-
left: -
|
|
158
|
+
left: -46px;
|
|
159
159
|
box-shadow: rgba(35, 47, 53, 0.09) 0px 2px 8px 0px;
|
|
160
160
|
border-radius: 100%; //GAB
|
|
161
161
|
border: 1px solid #eee;
|
|
@@ -163,8 +163,8 @@
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
.c21-avatar-image {
|
|
166
|
-
width:
|
|
167
|
-
height:
|
|
166
|
+
width: 38px;
|
|
167
|
+
height: 38px;
|
|
168
168
|
display: block;
|
|
169
169
|
position: absolute;
|
|
170
170
|
}
|
|
@@ -167,8 +167,10 @@ export class LastMessageComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
167
167
|
onAttachmentButtonClicked(event: any){
|
|
168
168
|
// this.onAttachmentButtonClicked.emit(event)
|
|
169
169
|
this.logger.debug('[LASTMESSAGE] onAttachmentButtonClicked', event)
|
|
170
|
-
this.events.publish('lastMessage:attachmentButtonClicked', event)
|
|
171
170
|
this.openConversationByID(this.conversation);
|
|
171
|
+
setTimeout(() => {
|
|
172
|
+
this.events.publish('lastMessage:attachmentButtonClicked', event)
|
|
173
|
+
}, 500);
|
|
172
174
|
}
|
|
173
175
|
/** */
|
|
174
176
|
openConversationByID(conversation) {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
<!-- <div *ngIf="message.type == 'text'"> -->
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
<div *ngIf="message?.text" tooltip="{{message.timestamp | dateAgo}} ({{message.timestamp | date:'shortDate'}} {{message.timestamp | date:'HH:mm:ss'}})">
|
|
49
|
+
<div *ngIf="message?.text" tooltip="{{message.timestamp | dateAgo}} ({{message.timestamp | date:'shortDate'}} {{message.timestamp | date:'HH:mm:ss'}})" placement="bottom">
|
|
50
50
|
|
|
51
51
|
<!-- [htmlEnabled]="(message?.type==='html')? true : false" -->
|
|
52
52
|
<chat-text *ngIf="message?.type !=='html'"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div #actionButton id="actionButton" class="button-in-msg action"
|
|
2
2
|
[ngClass]="{'disabled': isConversationArchived}"
|
|
3
|
-
title="{{button?.value}}"
|
|
4
3
|
(click)="actionButtonAction()"
|
|
5
4
|
(mouseover)="onMouseOver($event)"
|
|
6
5
|
(mouseout)="onMouseOut($event)">
|
|
7
6
|
{{button?.value}}
|
|
8
7
|
</div>
|
|
8
|
+
<!-- title="{{button?.value}}" -->
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
<!-- title="{{button?.value}}" -->
|
|
2
|
+
<div class="button-in-msg url" (click)="actionButtonUrl()"
|
|
2
3
|
(mouseover)="onMouseOver($event)" (mouseout)="onMouseOut($event)">
|
|
3
4
|
<span *ngIf="button?.target !== 'self'" class="icon-button-action">
|
|
4
5
|
<!-- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="12px" height="12px">
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
<!-- title="{{button?.value}}" -->
|
|
1
2
|
<div class="button-in-msg text"
|
|
2
|
-
[ngClass]="{'disabled': isConversationArchived}"
|
|
3
|
-
|
|
4
|
-
(
|
|
5
|
-
(
|
|
6
|
-
(mouseout)="onMouseOut($event)">
|
|
3
|
+
[ngClass]="{'disabled': isConversationArchived}"
|
|
4
|
+
(click)="actionButtonText()"
|
|
5
|
+
(mouseover)="onMouseOver($event)"
|
|
6
|
+
(mouseout)="onMouseOut($event)">
|
|
7
7
|
{{button?.value}}
|
|
8
8
|
</div>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<!-- [ngStyle] = "{ 'max-width': width +'px', 'max-height': height +'px' }" style="position: relative; text-align: center; margin: auto"-->
|
|
2
2
|
<div class="c21-img-container" >
|
|
3
|
-
<!-- <div *ngIf="loading" class="loader" [ngStyle] = "{ 'width': width , 'height': height }"></div> -->
|
|
4
3
|
<img
|
|
5
4
|
class="message-contentX message-content-imageX"
|
|
6
5
|
[alt]="metadata?.name"
|
|
@@ -9,7 +8,4 @@
|
|
|
9
8
|
[src]="metadata.src"
|
|
10
9
|
(load)="onLoaded($event)"
|
|
11
10
|
(click)="downloadImage(metadata.src, metadata.name)"/>
|
|
12
|
-
<ng-template #timeTooltipRight>
|
|
13
|
-
<span>{{ tooltipMessage }}</span>
|
|
14
|
-
</ng-template>
|
|
15
11
|
</div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div style="max-width: 70%;">
|
|
9
9
|
|
|
10
|
-
<span class="base_info" [innerHTML]="message?.text | marked" tooltip="{{message.timestamp | dateAgo}} ({{message.timestamp | date:'shortDate'}} {{message.timestamp | date:'HH:mm:ss'}})"
|
|
10
|
+
<span class="base_info" [innerHTML]="message?.text | marked" tooltip="{{message.timestamp | dateAgo}} ({{message.timestamp | date:'shortDate'}} {{message.timestamp | date:'HH:mm:ss'}})" placement="left"></span>
|
|
11
11
|
<!-- <ng-template #timeTooltipLeft>
|
|
12
12
|
<span>{{message.timestamp | amTimeAgo}} ({{message.timestamp | amLocal | amDateFormat: 'L HH:mm:ss'}})</span>
|
|
13
13
|
</ng-template> -->
|
|
@@ -1,46 +1,134 @@
|
|
|
1
|
-
import { Directive, ElementRef, HostListener, Input,
|
|
1
|
+
import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';
|
|
2
|
+
import { isOnMobileDevice } from 'src/chat21-core/utils/utils';
|
|
2
3
|
|
|
3
4
|
@Directive({
|
|
4
5
|
selector: '[tooltip]'
|
|
5
6
|
})
|
|
6
|
-
export class TooltipDirective
|
|
7
|
+
export class TooltipDirective {
|
|
7
8
|
|
|
8
|
-
@Input()
|
|
9
|
-
@Input()
|
|
9
|
+
@Input('tooltip') tooltipTitle: string;
|
|
10
|
+
@Input() placement: string;
|
|
11
|
+
@Input() delay: string;
|
|
12
|
+
tooltip: HTMLElement;
|
|
13
|
+
|
|
14
|
+
offset = 10;
|
|
15
|
+
isMobile = isOnMobileDevice()
|
|
10
16
|
|
|
11
|
-
private
|
|
12
|
-
private timer;
|
|
17
|
+
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
@HostListener('mouseenter') onMouseEnter() {
|
|
20
|
+
if (!this.tooltip && !this.isMobile) { this.show(); }
|
|
21
|
+
}
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
if (this.
|
|
23
|
+
@HostListener('mouseleave') onMouseLeave() {
|
|
24
|
+
if (this.tooltip) { this.hide(); }
|
|
18
25
|
}
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.createTooltipPopup(x, y);
|
|
25
|
-
}, this.delay)
|
|
27
|
+
show() {
|
|
28
|
+
this.create();
|
|
29
|
+
this.setPosition();
|
|
30
|
+
this.renderer.addClass(this.tooltip, 'ng-tooltip-show');
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
hide() {
|
|
34
|
+
this.renderer.removeClass(this.tooltip, 'ng-tooltip-show');
|
|
35
|
+
window.setTimeout(() => {
|
|
36
|
+
this.renderer.removeChild(document.body, this.tooltip);
|
|
37
|
+
this.tooltip = null;
|
|
38
|
+
}, +this.delay);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
create() {
|
|
42
|
+
this.tooltip = this.renderer.createElement('span');
|
|
43
|
+
|
|
44
|
+
this.renderer.appendChild(
|
|
45
|
+
this.tooltip,
|
|
46
|
+
this.renderer.createText(this.tooltipTitle) // textNode
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
this.renderer.appendChild(document.body, this.tooltip);
|
|
50
|
+
// this.renderer.appendChild(this.el.nativeElement, this.tooltip);
|
|
51
|
+
|
|
52
|
+
this.renderer.addClass(this.tooltip, 'ng-tooltip');
|
|
53
|
+
this.renderer.addClass(this.tooltip, `ng-tooltip-${this.placement}`);
|
|
54
|
+
|
|
55
|
+
// delay 설정
|
|
56
|
+
this.renderer.setStyle(this.tooltip, '-webkit-transition', `opacity ${this.delay}ms`);
|
|
57
|
+
this.renderer.setStyle(this.tooltip, '-moz-transition', `opacity ${this.delay}ms`);
|
|
58
|
+
this.renderer.setStyle(this.tooltip, '-o-transition', `opacity ${this.delay}ms`);
|
|
59
|
+
this.renderer.setStyle(this.tooltip, 'transition', `opacity ${this.delay}ms`);
|
|
31
60
|
}
|
|
32
61
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
setPosition() {
|
|
63
|
+
const hostPos = this.el.nativeElement.getBoundingClientRect();
|
|
64
|
+
const tooltipPos = this.tooltip.getBoundingClientRect();
|
|
65
|
+
|
|
66
|
+
const scrollPos = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
|
|
67
|
+
|
|
68
|
+
let top, left;
|
|
69
|
+
|
|
70
|
+
if (this.placement === 'top') {
|
|
71
|
+
top = hostPos.top - tooltipPos.height - this.offset;
|
|
72
|
+
left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.placement === 'bottom') {
|
|
76
|
+
top = hostPos.bottom + this.offset;
|
|
77
|
+
left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (this.placement === 'left') {
|
|
81
|
+
top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
|
|
82
|
+
left = hostPos.left - tooltipPos.width - this.offset;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this.placement === 'right') {
|
|
86
|
+
top = hostPos.top + (hostPos.height - tooltipPos.height) / 2;
|
|
87
|
+
left = hostPos.right + this.offset;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.renderer.setStyle(this.tooltip, 'top', `${top + scrollPos}px`);
|
|
91
|
+
this.renderer.setStyle(this.tooltip, 'left', `${left}px`);
|
|
44
92
|
}
|
|
45
93
|
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
// @Input() tooltip2: any; // The text for the tooltip to display
|
|
97
|
+
// @Input() delay? = 190; // Optional delay input, in ms
|
|
98
|
+
|
|
99
|
+
// private myPopup;
|
|
100
|
+
// private timer;
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
// ngOnDestroy(): void {
|
|
104
|
+
// if (this.myPopup) { this.myPopup.remove() }
|
|
105
|
+
// }
|
|
106
|
+
|
|
107
|
+
// @HostListener('mouseenter') onMouseEnter() {
|
|
108
|
+
// this.timer = setTimeout(() => {
|
|
109
|
+
// let x = this.el.nativeElement.getBoundingClientRect().left + this.el.nativeElement.offsetWidth / 2; // Get the middle of the element
|
|
110
|
+
// let y = this.el.nativeElement.getBoundingClientRect().top + this.el.nativeElement.offsetHeight + 6; // Get the bottom of the element, plus a little extra
|
|
111
|
+
// this.createTooltipPopup(x, y);
|
|
112
|
+
// }, this.delay)
|
|
113
|
+
// }
|
|
114
|
+
|
|
115
|
+
// @HostListener('mouseleave') onMouseLeave() {
|
|
116
|
+
// if (this.timer) clearTimeout(this.timer);
|
|
117
|
+
// if (this.myPopup) { this.myPopup.remove() }
|
|
118
|
+
// }
|
|
119
|
+
|
|
120
|
+
// private createTooltipPopup(x: number, y: number) {
|
|
121
|
+
// let popup = document.createElement('div');
|
|
122
|
+
// popup.innerHTML = this.tooltip2;
|
|
123
|
+
// popup.setAttribute("class", "tooltip-container");
|
|
124
|
+
// popup.style.top = y.toString() + "px";
|
|
125
|
+
// popup.style.left = x.toString() + "px";
|
|
126
|
+
// document.body.appendChild(popup);
|
|
127
|
+
// this.myPopup = popup;
|
|
128
|
+
// setTimeout(() => {
|
|
129
|
+
// if (this.myPopup) this.myPopup.remove();
|
|
130
|
+
// }, 5000); // Remove tooltip after 5 seconds
|
|
131
|
+
// }
|
|
132
|
+
|
|
133
|
+
|
|
46
134
|
}
|
|
@@ -220,6 +220,7 @@ export function conversationToMessage(conversation: ConversationModel, currentUs
|
|
|
220
220
|
message.sender_fullname = conversation.sender_fullname
|
|
221
221
|
message.recipient = conversation.recipient
|
|
222
222
|
message.recipient_fullname = conversation.recipient_fullname
|
|
223
|
+
message.conversation_with = conversation.conversation_with
|
|
223
224
|
message.status = +conversation.status
|
|
224
225
|
message.timestamp = conversation.timestamp
|
|
225
226
|
message.metadata = conversation['metadata']
|
|
@@ -239,6 +240,7 @@ export function commandToMessage(msg: MessageModel, conversation: ConversationMo
|
|
|
239
240
|
message.sender_fullname = conversation.sender_fullname
|
|
240
241
|
message.recipient = conversation.recipient
|
|
241
242
|
message.recipient_fullname = conversation.recipient_fullname
|
|
243
|
+
message.conversation_with = conversation.conversation_with
|
|
242
244
|
message.status = +conversation.status
|
|
243
245
|
message.timestamp = conversation.timestamp
|
|
244
246
|
message.metadata = msg['metadata']
|
|
@@ -246,6 +248,7 @@ export function commandToMessage(msg: MessageModel, conversation: ConversationMo
|
|
|
246
248
|
message.type = msg['type']
|
|
247
249
|
message.isSender = isSender(message.sender, currentUserId)
|
|
248
250
|
message.attributes = { ...conversation.attributes, ...msg['attributes']}
|
|
251
|
+
|
|
249
252
|
|
|
250
253
|
return message as MessageModel
|
|
251
254
|
}
|
|
@@ -19,6 +19,26 @@ export function windowsMatchMedia() {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/** */
|
|
23
|
+
export function isOniOSMobileDevice(): boolean {
|
|
24
|
+
let IS_ON_IOS_MOBILE_DEVICE = false;
|
|
25
|
+
if (/iPad|iPhone|iPod/i.test(window.navigator.userAgent)) {
|
|
26
|
+
IS_ON_IOS_MOBILE_DEVICE = true;
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
// console.log('[CONVS-DETAIL][HEADER] IS_ON_IOS_MOBILE_DEVICE ', this.IS_ON_IOS_MOBILE_DEVICE)
|
|
30
|
+
return IS_ON_IOS_MOBILE_DEVICE;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function isOnMobileDevice() {
|
|
34
|
+
let IS_ON_MOBILE_DEVICE = false;
|
|
35
|
+
if (/Android|iPhone/i.test(window.navigator.userAgent)) {
|
|
36
|
+
IS_ON_MOBILE_DEVICE = true;
|
|
37
|
+
}
|
|
38
|
+
// this.logger.log('[APP-COMP] IS_ON_MOBILE_DEVICE', this.IS_ON_MOBILE_DEVICE)
|
|
39
|
+
return IS_ON_MOBILE_DEVICE;
|
|
40
|
+
}
|
|
41
|
+
|
|
22
42
|
/**
|
|
23
43
|
* chiamata da ChatConversationsHandler
|
|
24
44
|
* restituisce url '/conversations'
|