@chat21/chat21-web-widget 5.0.59-rc.1 → 5.0.59-rc.3
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 +8 -0
- package/package.json +1 -1
- package/src/app/app.component.scss +64 -0
- package/src/app/app.component.ts +188 -177
- package/src/app/app.module.ts +5 -3
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +1 -1
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +43 -0
- package/src/app/component/home/home.component.html +1 -1
- package/src/app/component/home/home.component.ts +45 -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/app/providers/global-settings.service.ts +1 -0
- package/src/app/utils/globals.ts +12 -0
- package/src/chat21-core/providers/scripts/script.service.spec.ts +12 -0
- package/src/chat21-core/providers/scripts/script.service.ts +71 -0
- 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,13 @@
|
|
|
1
1
|
# chat21-web-widget ver 5.0
|
|
2
2
|
|
|
3
|
+
### 5.0.59-rc.3
|
|
4
|
+
- bug-fixed: if mobileMarginX or MobileMarginY is set, widget do not fit on fullscreen once is opened
|
|
5
|
+
|
|
6
|
+
### 5.0.59-rc.2
|
|
7
|
+
- added: handler for buttons in last-message component
|
|
8
|
+
- changed: tooltip custom directive
|
|
9
|
+
- changed: user-avatar size in last-message component
|
|
10
|
+
|
|
3
11
|
### 5.0.59-rc.1
|
|
4
12
|
- added: hashing while building dist files
|
|
5
13
|
|
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;
|
package/src/app/app.component.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ScriptService } from './../chat21-core/providers/scripts/script.service';
|
|
1
2
|
import { TYPE_DIRECT } from './../chat21-core/utils/constants';
|
|
2
3
|
/** ANGULAR MODULES */
|
|
3
4
|
import { AfterViewInit, Component, ElementRef, HostListener, NgZone, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
|
@@ -113,6 +114,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
113
114
|
private appStorageService: AppStorageService,
|
|
114
115
|
private translatorService: TranslatorService,
|
|
115
116
|
private translateService: CustomTranslateService,
|
|
117
|
+
private scriptService: ScriptService,
|
|
116
118
|
public chatManager: ChatManager,
|
|
117
119
|
private tiledeskRequestsService: TiledeskRequestsService,
|
|
118
120
|
public tiledeskAuthService: TiledeskAuthService,
|
|
@@ -123,220 +125,222 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
123
125
|
public imageRepoService: ImageRepoService,
|
|
124
126
|
public typingService: TypingService,
|
|
125
127
|
public presenceService: PresenceService,
|
|
126
|
-
public uploadService: UploadService
|
|
128
|
+
public uploadService: UploadService
|
|
127
129
|
){}
|
|
128
130
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
ngOnInit(): void {
|
|
132
|
+
this.logger.info('[APP-CONF]---------------- ngOnInit: APP.COMPONENT ---------------- ')
|
|
133
|
+
this.initWidgetParamiters();
|
|
134
|
+
}
|
|
133
135
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
ngAfterViewInit(): void {
|
|
137
|
+
this.logger.info('[APP-CONF]---------------- ngAfterViewInit: APP.COMPONENT ---------------- ')
|
|
138
|
+
this.ngZone.run(() => {
|
|
139
|
+
const that = this;
|
|
140
|
+
const subChangedConversation = this.conversationsHandlerService.conversationChanged.subscribe((conversation) => {
|
|
141
|
+
// that.ngZone.run(() => {
|
|
142
|
+
if (conversation) {
|
|
143
|
+
this.onImageLoaded(conversation)
|
|
144
|
+
this.onConversationLoaded(conversation)
|
|
143
145
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
if(conversation.recipient === this.g.senderId && isUserBanned(conversation)){
|
|
147
|
+
that.disposeWidget();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if(conversation.is_new && conversation.sender !== this.g.senderId && !isInfo(conversation)){
|
|
152
|
+
that.manageTabNotification();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (that.g.isOpen === true) {
|
|
156
|
+
that.g.setParameter('displayEyeCatcherCard', 'none');
|
|
157
|
+
|
|
158
|
+
this.logger.debug('[APP-COMP] obsChangeConversation ::: ', conversation);
|
|
159
|
+
if (conversation.attributes && conversation.attributes['subtype'] === 'info') {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
} else {
|
|
164
|
+
// if(conversation.is_new && isJustRecived(this.g.startedAt.getTime(), conversation.timestamp)){
|
|
165
|
+
//widget closed
|
|
166
|
+
if(conversation.is_new && conversation.sender !== this.g.senderId && !isInfo(conversation)){
|
|
167
|
+
that.lastConversation = conversation;
|
|
168
|
+
that.g.isOpenNewMessage = true;
|
|
169
|
+
that.logger.debug('[APP-COMP] lastconversationnn', that.lastConversation)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
let badgeNewConverstionNumber = that.conversationsHandlerService.countIsNew()
|
|
174
|
+
that.g.setParameter('conversationsBadge', badgeNewConverstionNumber);
|
|
175
|
+
// }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
that.triggerOnConversationUpdated(conversation);
|
|
179
|
+
} else {
|
|
180
|
+
this.logger.debug('[APP-COMP] oBSconversationChanged null: errorrr')
|
|
146
181
|
return;
|
|
147
182
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
183
|
+
|
|
184
|
+
// });
|
|
185
|
+
});
|
|
186
|
+
this.subscriptions.push(subChangedConversation);
|
|
152
187
|
|
|
153
|
-
|
|
188
|
+
const subAddedConversation = this.conversationsHandlerService.conversationAdded.subscribe((conversation) => {
|
|
189
|
+
// that.ngZone.run(() => {
|
|
190
|
+
if (that.g.isOpen === true && conversation) {
|
|
154
191
|
that.g.setParameter('displayEyeCatcherCard', 'none');
|
|
155
|
-
|
|
156
|
-
|
|
192
|
+
that.triggerOnConversationUpdated(conversation);
|
|
193
|
+
that.logger.debug('[APP-COMP] obsAddedConversation ::: ', conversation);
|
|
157
194
|
if (conversation.attributes && conversation.attributes['subtype'] === 'info') {
|
|
158
195
|
return;
|
|
159
196
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if(
|
|
197
|
+
if (conversation.is_new) {
|
|
198
|
+
that.manageTabNotification()
|
|
199
|
+
// this.soundMessage();
|
|
200
|
+
}
|
|
201
|
+
if(this.g.isOpen === false){
|
|
165
202
|
that.lastConversation = conversation;
|
|
166
203
|
that.g.isOpenNewMessage = true;
|
|
167
|
-
that.logger.debug('[APP-COMP] lastconversationnn', that.lastConversation)
|
|
168
204
|
}
|
|
169
|
-
|
|
205
|
+
} else {
|
|
206
|
+
//widget closed
|
|
170
207
|
|
|
171
208
|
let badgeNewConverstionNumber = that.conversationsHandlerService.countIsNew()
|
|
172
209
|
that.g.setParameter('conversationsBadge', badgeNewConverstionNumber);
|
|
173
|
-
// }
|
|
174
210
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// });
|
|
183
|
-
});
|
|
184
|
-
this.subscriptions.push(subChangedConversation);
|
|
185
|
-
|
|
186
|
-
const subAddedConversation = this.conversationsHandlerService.conversationAdded.subscribe((conversation) => {
|
|
187
|
-
// that.ngZone.run(() => {
|
|
188
|
-
if (that.g.isOpen === true && conversation) {
|
|
189
|
-
that.g.setParameter('displayEyeCatcherCard', 'none');
|
|
190
|
-
that.triggerOnConversationUpdated(conversation);
|
|
191
|
-
that.logger.debug('[APP-COMP] obsAddedConversation ::: ', conversation);
|
|
192
|
-
if (conversation.attributes && conversation.attributes['subtype'] === 'info') {
|
|
193
|
-
return;
|
|
211
|
+
// that.manageTabNotification()
|
|
212
|
+
// });
|
|
213
|
+
if(conversation){
|
|
214
|
+
this.onImageLoaded(conversation)
|
|
215
|
+
this.onConversationLoaded(conversation)
|
|
194
216
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
217
|
+
|
|
218
|
+
});
|
|
219
|
+
this.subscriptions.push(subAddedConversation);
|
|
220
|
+
|
|
221
|
+
const subAddedArchivedConversations = this.archivedConversationsService.archivedConversationAdded.subscribe((conversation) => {
|
|
222
|
+
// that.ngZone.run(() => {
|
|
223
|
+
if (conversation) {
|
|
224
|
+
that.triggerOnConversationUpdated(conversation);
|
|
225
|
+
this.onImageLoaded(conversation)
|
|
226
|
+
this.onConversationLoaded(conversation)
|
|
198
227
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
228
|
+
// });
|
|
229
|
+
});
|
|
230
|
+
this.subscriptions.push(subAddedArchivedConversations);
|
|
231
|
+
|
|
232
|
+
const subRemovedArchivedConversations = this.archivedConversationsService.archivedConversationRemoved.subscribe((conversation) => {
|
|
233
|
+
// that.ngZone.run(() => {
|
|
234
|
+
if (conversation) {
|
|
235
|
+
this.isConversationArchived = false;
|
|
236
|
+
that.triggerOnConversationUpdated(conversation);
|
|
202
237
|
}
|
|
203
|
-
|
|
204
|
-
|
|
238
|
+
// });
|
|
239
|
+
});
|
|
240
|
+
this.subscriptions.push(subRemovedArchivedConversations);
|
|
205
241
|
|
|
206
|
-
let badgeNewConverstionNumber = that.conversationsHandlerService.countIsNew()
|
|
207
|
-
that.g.setParameter('conversationsBadge', badgeNewConverstionNumber);
|
|
208
|
-
}
|
|
209
|
-
// that.manageTabNotification()
|
|
210
|
-
// });
|
|
211
|
-
if(conversation){
|
|
212
|
-
this.onImageLoaded(conversation)
|
|
213
|
-
this.onConversationLoaded(conversation)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
242
|
});
|
|
217
|
-
this.
|
|
243
|
+
this.appStorageService.initialize(environment.storage_prefix, this.g.persistence, this.g.projectid)
|
|
244
|
+
this.tiledeskAuthService.initialize(this.appConfigService.getConfig().apiUrl)
|
|
245
|
+
this.tiledeskRequestsService.initialize(this.appConfigService.getConfig().apiUrl, this.g.projectid)
|
|
246
|
+
this.messagingAuthService.initialize();
|
|
247
|
+
this.chatManager.initialize();
|
|
248
|
+
this.uploadService.initialize();
|
|
249
|
+
}
|
|
218
250
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
251
|
+
private initWidgetParamiters(){
|
|
252
|
+
const that = this;
|
|
253
|
+
const obsSettingsService = this.globalSettingsService.obsSettingsService.subscribe((resp) => {
|
|
254
|
+
if(resp){
|
|
255
|
+
|
|
256
|
+
// /** INIT */
|
|
257
|
+
this.logger.setLoggerConfig(this.g.isLogEnabled, this.g.logLevel)
|
|
258
|
+
this.tabTitle = this.g.windowContext.window.document.title
|
|
259
|
+
this.appStorageService.initialize(environment.storage_prefix, this.g.persistence, this.g.projectid)
|
|
260
|
+
this.logger.debug('[APP-COMP] check if token is passed throw url: ', this.g.jwt);
|
|
261
|
+
/**CHECK IF JWT IS IN URL PARAMETERS */
|
|
262
|
+
if (this.g.jwt) {
|
|
263
|
+
// logging in with custom token from url
|
|
264
|
+
// add JWY token to localstorage and authenticate with it this.logger.debug('[APP-COMP] token from url. isShown:', this.g.isShown, 'autostart:', this.g.autoStart)
|
|
265
|
+
this.logger.debug('[APP-COMP] ---------------- logging in with custom token from url ---------------- ');
|
|
266
|
+
// this.g.autoStart = false;
|
|
267
|
+
const storedTiledeskToken = this.appStorageService.getItem('tiledeskToken')
|
|
268
|
+
storedTiledeskToken === this.g.jwt? null: this.appStorageService.setItem('tiledeskToken', this.g.jwt);
|
|
269
|
+
this.g.tiledeskToken = this.g.jwt;
|
|
270
|
+
// this.signInWithCustomToken(this.g.jwt) // moved to authenticate() in else(tiledeskToken)
|
|
271
|
+
}
|
|
229
272
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
273
|
+
/** INIT LABELS TRANSLATIONS */
|
|
274
|
+
this.translatorService.initI18n().then((result) => {
|
|
275
|
+
this.logger.debug('[APP-COMP] »»»» APP-COMPONENT.TS initI18n result', result);
|
|
276
|
+
const browserLang = this.translatorService.getLanguage();
|
|
277
|
+
// moment.locale(browserLang)
|
|
278
|
+
dayjs.locale(browserLang)
|
|
279
|
+
this.translatorService.translate(this.g);
|
|
280
|
+
}).then(() => {
|
|
281
|
+
/** INIT */
|
|
282
|
+
that.initAll();
|
|
283
|
+
/** TRIGGER ONBEFORE INIT */
|
|
284
|
+
that.triggerOnBeforeInit();
|
|
285
|
+
/** AUTH */
|
|
286
|
+
that.setAuthSubscription();
|
|
287
|
+
/** SCRIPT LOAD */
|
|
288
|
+
that.loadCustomScript(this.appConfigService.getConfig())
|
|
289
|
+
})
|
|
290
|
+
|
|
235
291
|
}
|
|
236
|
-
// });
|
|
237
292
|
});
|
|
238
|
-
this.subscriptions.push(
|
|
239
|
-
|
|
240
|
-
});
|
|
241
|
-
this.appStorageService.initialize(environment.storage_prefix, this.g.persistence, this.g.projectid)
|
|
242
|
-
this.tiledeskAuthService.initialize(this.appConfigService.getConfig().apiUrl)
|
|
243
|
-
this.tiledeskRequestsService.initialize(this.appConfigService.getConfig().apiUrl, this.g.projectid)
|
|
244
|
-
this.messagingAuthService.initialize();
|
|
245
|
-
this.chatManager.initialize();
|
|
246
|
-
this.uploadService.initialize();
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
private initWidgetParamiters(){
|
|
250
|
-
const that = this;
|
|
251
|
-
const obsSettingsService = this.globalSettingsService.obsSettingsService.subscribe((resp) => {
|
|
252
|
-
if(resp){
|
|
253
|
-
|
|
254
|
-
// /** INIT */
|
|
255
|
-
this.logger.setLoggerConfig(this.g.isLogEnabled, this.g.logLevel)
|
|
256
|
-
this.tabTitle = this.g.windowContext.window.document.title
|
|
257
|
-
this.appStorageService.initialize(environment.storage_prefix, this.g.persistence, this.g.projectid)
|
|
258
|
-
this.logger.debug('[APP-COMP] check if token is passed throw url: ', this.g.jwt);
|
|
259
|
-
/**CHECK IF JWT IS IN URL PARAMETERS */
|
|
260
|
-
if (this.g.jwt) {
|
|
261
|
-
// logging in with custom token from url
|
|
262
|
-
// add JWY token to localstorage and authenticate with it this.logger.debug('[APP-COMP] token from url. isShown:', this.g.isShown, 'autostart:', this.g.autoStart)
|
|
263
|
-
this.logger.debug('[APP-COMP] ---------------- logging in with custom token from url ---------------- ');
|
|
264
|
-
// this.g.autoStart = false;
|
|
265
|
-
const storedTiledeskToken = this.appStorageService.getItem('tiledeskToken')
|
|
266
|
-
storedTiledeskToken === this.g.jwt? null: this.appStorageService.setItem('tiledeskToken', this.g.jwt);
|
|
267
|
-
this.g.tiledeskToken = this.g.jwt;
|
|
268
|
-
// this.signInWithCustomToken(this.g.jwt) // moved to authenticate() in else(tiledeskToken)
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/** INIT LABELS TRANSLATIONS */
|
|
272
|
-
this.translatorService.initI18n().then((result) => {
|
|
273
|
-
this.logger.debug('[APP-COMP] »»»» APP-COMPONENT.TS initI18n result', result);
|
|
274
|
-
const browserLang = this.translatorService.getLanguage();
|
|
275
|
-
// moment.locale(browserLang)
|
|
276
|
-
dayjs.locale(browserLang)
|
|
277
|
-
this.translatorService.translate(this.g);
|
|
278
|
-
}).then(() => {
|
|
279
|
-
/** INIT */
|
|
280
|
-
that.initAll();
|
|
281
|
-
/** TRIGGER ONBEFORE INIT */
|
|
282
|
-
that.triggerOnBeforeInit();
|
|
283
|
-
/** AUTH */
|
|
284
|
-
that.setAuthSubscription();
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
this.subscriptions.push(obsSettingsService);
|
|
290
|
-
this.globalSettingsService.initWidgetParamiters(this.g, this.el);
|
|
293
|
+
this.subscriptions.push(obsSettingsService);
|
|
294
|
+
this.globalSettingsService.initWidgetParamiters(this.g, this.el);
|
|
291
295
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
296
|
+
// SET AUDIO
|
|
297
|
+
this.audio = new Audio();
|
|
298
|
+
this.audio.src = this.g.baseLocation + URL_SOUND_LIST_CONVERSATION;
|
|
299
|
+
this.audio.load();
|
|
300
|
+
}
|
|
297
301
|
|
|
298
|
-
|
|
299
|
-
|
|
302
|
+
private initAll() {
|
|
303
|
+
this.addComponentToWindow(this.ngZone);
|
|
300
304
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
305
|
+
//INIT TRIGGER-HANDLER
|
|
306
|
+
this.triggerHandler.setElement(this.el)
|
|
307
|
+
this.triggerHandler.setWindowContext(this.g.windowContext)
|
|
304
308
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
309
|
+
// /** TRANSLATION LOADER: */
|
|
310
|
+
// // this.translatorService.translate(this.g);
|
|
311
|
+
// this.translatorService.initI18n().then((result) => {
|
|
312
|
+
// this.g.wdLog(['»»»» APP-COMPONENT.TS initI18n result', result]);
|
|
313
|
+
// this.translatorService.translate(this.g);
|
|
314
|
+
// });
|
|
311
315
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
316
|
+
/** SET ATTRIBUTES */
|
|
317
|
+
const attributes = this.setAttributesFromStorageService();
|
|
318
|
+
if (attributes) {
|
|
319
|
+
this.g.attributes = attributes;
|
|
320
|
+
}
|
|
321
|
+
this.setStyleMap()
|
|
318
322
|
|
|
319
|
-
|
|
323
|
+
// ------------------------------- //
|
|
320
324
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
325
|
+
// ------------------------------- //
|
|
326
|
+
/**
|
|
327
|
+
* INIZIALIZE GLOBALS :
|
|
328
|
+
* create settings object used in trigger
|
|
329
|
+
* set isMobile
|
|
330
|
+
* set attributes
|
|
331
|
+
*/
|
|
332
|
+
this.g.initialize();
|
|
333
|
+
// ------------------------------- //
|
|
330
334
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
335
|
+
this.removeFirebasewebsocketFromLocalStorage();
|
|
336
|
+
// this.triggerLoadParamsEvent();
|
|
337
|
+
// this.addComponentToWindow(this.ngZone); // forse dovrebbe stare prima di tutti i triggers
|
|
334
338
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
339
|
+
this.initLauncherButton();
|
|
340
|
+
this.triggerLoadParamsEvent(); // first trigger
|
|
341
|
+
//this.setAvailableAgentsStatus();
|
|
338
342
|
|
|
339
|
-
|
|
343
|
+
}
|
|
340
344
|
|
|
341
345
|
// ========= begin:: SUBSCRIPTIONS ============//
|
|
342
346
|
private async setAuthSubscription(){
|
|
@@ -2064,6 +2068,13 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
|
2064
2068
|
this.el.nativeElement.style.setProperty('--button-in-msg-font-size', this.g.buttonFontSize)
|
|
2065
2069
|
}
|
|
2066
2070
|
|
|
2071
|
+
|
|
2072
|
+
private loadCustomScript(config){
|
|
2073
|
+
if(config.hasOwnProperty("globalRemoteJSSrc")){
|
|
2074
|
+
this.scriptService.buildScriptArray(config['globalRemoteJSSrc'])
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2067
2078
|
// ========= begin:: DESTROY ALL SUBSCRIPTIONS ============//
|
|
2068
2079
|
/** elimino tutte le sottoscrizioni */
|
|
2069
2080
|
ngOnDestroy() {
|
package/src/app/app.module.ts
CHANGED
|
@@ -62,10 +62,11 @@ import { TranslateModule } from '@ngx-translate/core';
|
|
|
62
62
|
import { PickerModule } from '@ctrl/ngx-emoji-mart';
|
|
63
63
|
import { LoggerModule, NGXLogger, NgxLoggerLevel } from "ngx-logger";
|
|
64
64
|
|
|
65
|
-
//DIRECTIVES
|
|
65
|
+
//DIRECTIVES-PIPES
|
|
66
66
|
import { HtmlEntitiesEncodePipe } from './pipe/html-entities-encode.pipe';
|
|
67
67
|
import { MarkedPipe } from './pipe/marked.pipe';
|
|
68
68
|
import { SafeHtmlPipe } from './pipe/safe-html.pipe';
|
|
69
|
+
import { TooltipDirective } from 'src/app/directives/tooltip.directive';
|
|
69
70
|
|
|
70
71
|
//LOGGER SERVICES
|
|
71
72
|
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
@@ -128,7 +129,7 @@ import { WaitingService } from './providers/waiting.service';
|
|
|
128
129
|
import { StarRatingWidgetService } from './providers/star-rating-widget.service';
|
|
129
130
|
import { LikeUnlikeComponent } from './component/message/like-unlike/like-unlike.component';
|
|
130
131
|
import { Rules } from './utils/rules';
|
|
131
|
-
import {
|
|
132
|
+
import { ScriptService } from 'src/chat21-core/providers/scripts/script.service';
|
|
132
133
|
|
|
133
134
|
|
|
134
135
|
const appInitializerFn = (appConfig: AppConfigService, logger: NGXLogger) => {
|
|
@@ -381,7 +382,8 @@ export function uploadFactory(http: HttpClient, appConfig: AppConfigService, app
|
|
|
381
382
|
TranslatorService,
|
|
382
383
|
CustomTranslateService,
|
|
383
384
|
Triggerhandler,
|
|
384
|
-
WaitingService
|
|
385
|
+
WaitingService,
|
|
386
|
+
ScriptService
|
|
385
387
|
],
|
|
386
388
|
bootstrap: [AppComponent]
|
|
387
389
|
})
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- LOGO-->
|
|
2
2
|
<div id="hiddenFooter" *ngIf="!hideTextAreaContent && poweredBy" class="fade-in-bottom"
|
|
3
3
|
[class.hideTextReply]="hideTextReply">
|
|
4
|
-
<div tabindex="-1" class="c21-powered-by" [innerHTML]="poweredBy"></div>
|
|
4
|
+
<div tabindex="-1" class="c21-powered-by" [innerHTML]="poweredBy" (click)="managePoweredBy($event)"></div>
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
7
|
<!-- TEXTAREA + ICONS: conv active-->
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts
CHANGED
|
@@ -596,4 +596,47 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
596
596
|
}
|
|
597
597
|
}
|
|
598
598
|
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
managePoweredBy(event: Event){
|
|
602
|
+
event.stopPropagation();
|
|
603
|
+
this.segmentLogoClick()
|
|
604
|
+
let target = (event.target as Element) || (event.srcElement as Element) || (event.currentTarget as Element)
|
|
605
|
+
if(target.parentElement.tagName === 'A' && target.parentElement.hasAttribute('href')){
|
|
606
|
+
window.open(target.parentElement.getAttribute('href'), '_blank')
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
private segmentLogoClick(){
|
|
612
|
+
let that = this
|
|
613
|
+
if(window['analytics']){
|
|
614
|
+
try {
|
|
615
|
+
window['analytics'].page("Widget Conversation Page, LogoClick", {});
|
|
616
|
+
} catch (err) {
|
|
617
|
+
this.logger.error('Event:Signed In [page] error', err);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
try {
|
|
621
|
+
window['analytics'].identify(that.senderId, {
|
|
622
|
+
name: that.userFullname,
|
|
623
|
+
email: that.userEmail,
|
|
624
|
+
logins: 5,
|
|
625
|
+
});
|
|
626
|
+
} catch (err) {
|
|
627
|
+
this.logger.error('Event:LogoClick [identify] error', err);
|
|
628
|
+
}
|
|
629
|
+
// Segments
|
|
630
|
+
try {
|
|
631
|
+
window['analytics'].track('LogoClick', {
|
|
632
|
+
"username": that.userFullname,
|
|
633
|
+
"userId": that.userEmail,
|
|
634
|
+
"attributes": that.attributes
|
|
635
|
+
});
|
|
636
|
+
} catch (err) {
|
|
637
|
+
this.logger.error('Event:LogoClick [track] error', err);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
599
642
|
}
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
<!-- FOOTER -->
|
|
145
145
|
<div class="c21-footer fade-in-bottom-footer">
|
|
146
146
|
<div id="c21-powered-by" (mouseover)="hover=true" (mouseleave)="hover=false">
|
|
147
|
-
<div tabindex="-1" class="c21-powered-by" [innerHTML]="g.poweredBy"></div>
|
|
147
|
+
<div tabindex="-1" class="c21-powered-by" [innerHTML]="g.poweredBy" (click)="managePoweredBy($event)"></div>
|
|
148
148
|
<!-- <div class="build_version">{{g.BUILD_VERSION}}</div> -->
|
|
149
149
|
</div>
|
|
150
150
|
<chat-menu-options *ngIf="!hideSettings"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TiledeskAuthService } from './../../../chat21-core/providers/tiledesk/tiledesk-auth.service';
|
|
1
2
|
import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
|
|
2
3
|
import { CustomTranslateService } from 'src/chat21-core/providers/custom-translate.service';
|
|
3
4
|
import { ConversationModel } from '../../../chat21-core/models/conversation';
|
|
@@ -47,6 +48,7 @@ export class HomeComponent implements OnInit, AfterViewInit {
|
|
|
47
48
|
|
|
48
49
|
constructor(
|
|
49
50
|
public g: Globals,
|
|
51
|
+
private tiledeskAuthService : TiledeskAuthService,
|
|
50
52
|
private customTranslateService: CustomTranslateService,
|
|
51
53
|
) {
|
|
52
54
|
|
|
@@ -85,6 +87,49 @@ export class HomeComponent implements OnInit, AfterViewInit {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
|
|
90
|
+
managePoweredBy(event: Event){
|
|
91
|
+
event.stopPropagation();
|
|
92
|
+
this.segmentLogoClick()
|
|
93
|
+
let target = (event.target as Element) || (event.srcElement as Element) || (event.currentTarget as Element)
|
|
94
|
+
if(target.parentElement.tagName === 'A' && target.parentElement.hasAttribute('href')){
|
|
95
|
+
window.open(target.parentElement.getAttribute('href'), '_blank')
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
private segmentLogoClick(){
|
|
101
|
+
let that = this
|
|
102
|
+
let user = this.tiledeskAuthService.getCurrentUser()
|
|
103
|
+
if(window['analytics']){
|
|
104
|
+
try {
|
|
105
|
+
window['analytics'].page("Widget Home Page, LogoClick", {});
|
|
106
|
+
} catch (err) {
|
|
107
|
+
this.logger.error('Event:Signed In [page] error', err);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
window['analytics'].identify(user.uid, {
|
|
112
|
+
name: user.firstname + ' ' + user.lastname,
|
|
113
|
+
email: user.email,
|
|
114
|
+
logins: 5,
|
|
115
|
+
});
|
|
116
|
+
} catch (err) {
|
|
117
|
+
this.logger.error('Event:LogoClick [identify] error', err);
|
|
118
|
+
}
|
|
119
|
+
// Segments
|
|
120
|
+
try {
|
|
121
|
+
window['analytics'].track('LogoClick', {
|
|
122
|
+
"username": user.firstname + ' ' + user.lastname,
|
|
123
|
+
"userId": user.uid,
|
|
124
|
+
"attributes": that.g.attributes
|
|
125
|
+
});
|
|
126
|
+
} catch (err) {
|
|
127
|
+
this.logger.error('Event:LogoClick [track] error', err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
88
133
|
|
|
89
134
|
|
|
90
135
|
|
|
@@ -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
|
}
|
|
@@ -369,6 +369,7 @@ export class GlobalSettingsService {
|
|
|
369
369
|
this.globals.isMobile? marginX= this.globals.mobileMarginX: marginX = this.globals.marginX
|
|
370
370
|
divTiledeskiframe.style.right = marginX;
|
|
371
371
|
}
|
|
372
|
+
|
|
372
373
|
if (this.globals.isMobile) {
|
|
373
374
|
divTiledeskiframe.style.bottom = this.globals.mobileMarginY
|
|
374
375
|
} else {
|
package/src/app/utils/globals.ts
CHANGED
|
@@ -587,6 +587,18 @@ export class Globals {
|
|
|
587
587
|
} else if(!isOpen && chat21conversationsEL){
|
|
588
588
|
chat21conversationsEL.classList.remove('isMobile')
|
|
589
589
|
}
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
//customize position for 'tiledeskdiv' for mobile
|
|
593
|
+
if(isOpen && this.isMobile && divTiledeskWidget){
|
|
594
|
+
divTiledeskWidget.style.right = '0px'
|
|
595
|
+
divTiledeskWidget.style.bottom = '0px'
|
|
596
|
+
} else if(!isOpen && this.isMobile && divTiledeskWidget){
|
|
597
|
+
divTiledeskWidget.style.bottom = this.marginY
|
|
598
|
+
this.align === 'left'? divTiledeskWidget.style.left = this.mobileMarginX : divTiledeskWidget.style.right = this.mobileMarginX;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
|
|
590
602
|
}
|
|
591
603
|
|
|
592
604
|
setWidgetPreviewContainerSize(width: number, height: number){
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ScriptService } from './script.service';
|
|
4
|
+
|
|
5
|
+
describe('ScriptService', () => {
|
|
6
|
+
beforeEach(() => TestBed.configureTestingModule({}));
|
|
7
|
+
|
|
8
|
+
it('should be created', () => {
|
|
9
|
+
const service: ScriptService = TestBed.get(ScriptService);
|
|
10
|
+
expect(service).toBeTruthy();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { HttpClient } from '@angular/common/http';
|
|
2
|
+
import { Injectable } from '@angular/core';
|
|
3
|
+
import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
|
|
4
|
+
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
5
|
+
|
|
6
|
+
@Injectable({
|
|
7
|
+
providedIn: 'root'
|
|
8
|
+
})
|
|
9
|
+
export class ScriptService {
|
|
10
|
+
|
|
11
|
+
private scriptList: Array<{name: string, loaded: boolean, src: string}> = []
|
|
12
|
+
private logger: LoggerService = LoggerInstance.getInstance();
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
public http: HttpClient,
|
|
16
|
+
) { }
|
|
17
|
+
|
|
18
|
+
buildScriptArray(globalRemoteJSSrc: string){
|
|
19
|
+
this.logger.log('[SCRIPT-SERVICE] buildScriptArray globalRemoteJSSrc ', globalRemoteJSSrc);
|
|
20
|
+
if(!this.isEmpty(globalRemoteJSSrc)){
|
|
21
|
+
var scriptArray = globalRemoteJSSrc.split(",")
|
|
22
|
+
|
|
23
|
+
let count = 0;
|
|
24
|
+
scriptArray.forEach(element => {
|
|
25
|
+
count = count + 1;
|
|
26
|
+
this.scriptList.push({name: element.split('/').pop(), loaded: false, src: element})
|
|
27
|
+
});
|
|
28
|
+
this.logger.log('[SCRIPT-SERVICE] buildScriptArray ', this.scriptList);
|
|
29
|
+
this.load()
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
load() {
|
|
35
|
+
this.logger.log('[SCRIPT-SERV] load ...scripts ', this.scriptList)
|
|
36
|
+
var promises: any[] = [];
|
|
37
|
+
this.scriptList.forEach((script) => promises.push(this.loadScript(script)));
|
|
38
|
+
return Promise.all(promises).catch((err) => {
|
|
39
|
+
// log that I have an error, return the entire array;
|
|
40
|
+
this.logger.error('A promise failed to resolve', err);
|
|
41
|
+
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
loadScript(currentScript){
|
|
47
|
+
this.logger.log('[SCRIPT-SERVICE] load script:', currentScript);
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
//resolve if already loaded
|
|
50
|
+
if (currentScript.loaded) {
|
|
51
|
+
resolve({ script: currentScript.name, loaded: true, status: 'Already Loaded' });
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
//load script
|
|
55
|
+
let script = document.createElement('script')
|
|
56
|
+
script.type = 'text/javascript';
|
|
57
|
+
script.src = currentScript.src;
|
|
58
|
+
script.onload = () => {
|
|
59
|
+
currentScript.loaded = true;
|
|
60
|
+
resolve({ script: name, loaded: true, status: 'Loaded' });
|
|
61
|
+
}
|
|
62
|
+
script.onerror = (error: any) => resolve({ script: currentScript.name, loaded: false, status: 'Loaded' });
|
|
63
|
+
document.getElementsByTagName('head')[0].appendChild(script);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
isEmpty(url: string) {
|
|
69
|
+
return (url === undefined || url == null || url.length <= 0) ? true : false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -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'
|