@chat21/chat21-web-widget 5.1.0-rc.4 → 5.1.0-rc10
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 +19 -3
- package/Dockerfile +3 -3
- package/deploy_beta.sh +12 -1
- package/deploy_prod.sh +13 -4
- package/package.json +1 -1
- package/src/app/component/conversation-detail/conversation/conversation.component.html +1 -2
- package/src/app/component/conversation-detail/conversation/conversation.component.ts +3 -1
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +22 -6
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +45 -3
- package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +60 -8
- package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html +2 -2
- package/src/app/component/conversation-detail/conversation-header/conversation-header.component.ts +0 -1
- package/src/app/component/message/audio/audio.component.ts +30 -16
- package/src/app/providers/global-settings.service.ts +1 -14
- package/src/app/sass/_variables.scss +6 -1
- package/src/app/utils/globals.ts +1 -4
- package/src/app/utils/utils.ts +0 -9
- package/src/assets/i18n/en.json +3 -1
- package/src/assets/twp/chatbot-panel.html +8 -1
- package/src/assets/twp/index-dev.html +8 -18
- package/src/assets/twp/index.html +13 -3
- package/src/chat21-core/utils/utils-message.ts +20 -0
- package/src/chat21-core/utils/utils.ts +83 -0
- package/src/models/project.ts +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,13 +6,29 @@
|
|
|
6
6
|
### **Copyrigth**:
|
|
7
7
|
*Tiledesk SRL*
|
|
8
8
|
|
|
9
|
-
# 5.1.0-
|
|
9
|
+
# 5.1.0-rc10
|
|
10
|
+
- **bug-fixed**: minor fix allowed urls
|
|
11
|
+
|
|
12
|
+
# 5.1.0-rc9
|
|
13
|
+
- **bug-fixed**: minor fix allowed urls
|
|
14
|
+
|
|
15
|
+
# 5.1.0-rc8
|
|
16
|
+
- **added**: ability to filter on urls attached to message textarea
|
|
17
|
+
|
|
18
|
+
# 5.1.0-rc7
|
|
19
|
+
- **added**: ability to allows emoji after message is sent
|
|
20
|
+
|
|
21
|
+
# 5.1.0-rc6
|
|
22
|
+
- **removed**: hideRestartConversationOptionsMenu
|
|
23
|
+
|
|
24
|
+
# 5.1.0-rc5
|
|
25
|
+
# 5.1.0-rc4
|
|
10
26
|
- **bug-fixed**: Dockerfile for angular 18
|
|
11
27
|
|
|
12
|
-
# 5.1.0-
|
|
28
|
+
# 5.1.0-rc3
|
|
13
29
|
- **added**: angular 18
|
|
14
30
|
|
|
15
|
-
# 5.1.0-
|
|
31
|
+
# 5.1.0-rc2
|
|
16
32
|
- **added**: angular 17
|
|
17
33
|
|
|
18
34
|
# 5.0.96
|
package/Dockerfile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
### STAGE 1: Build ###
|
|
2
2
|
|
|
3
3
|
# We label our stage as ‘builder’
|
|
4
|
-
FROM node:
|
|
4
|
+
FROM node:20.12.2-alpine3.19 as builder
|
|
5
5
|
|
|
6
6
|
COPY package.json package-lock.json ./
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ COPY . .
|
|
|
15
15
|
|
|
16
16
|
## Build the angular app in production mode and store the artifacts in dist folder
|
|
17
17
|
|
|
18
|
-
RUN
|
|
18
|
+
RUN npx ng build --configuration="prod" --output-path=dist --base-href=./ --output-hashing=none
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
### STAGE 2: Setup ###
|
|
@@ -29,7 +29,7 @@ COPY nginx.conf /etc/nginx/nginx.conf
|
|
|
29
29
|
RUN rm -rf /usr/share/nginx/html/*
|
|
30
30
|
|
|
31
31
|
## From ‘builder’ stage copy over the artifacts in dist folder to default nginx public folder
|
|
32
|
-
COPY --from=builder /ng-app/dist /usr/share/nginx/html
|
|
32
|
+
COPY --from=builder /ng-app/dist/browser /usr/share/nginx/html
|
|
33
33
|
|
|
34
34
|
RUN echo "Chat21 Web Widget Started!!"
|
|
35
35
|
|
package/deploy_beta.sh
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
# npm version prerelease --preid=beta
|
|
2
2
|
version=`node -e 'console.log(require("./package.json").version)'`
|
|
3
3
|
echo "version $version"
|
|
4
|
+
echo "____________WIDGET-V5______________"
|
|
5
|
+
echo "CREATING TAG ON GIT FOR version: $version"
|
|
6
|
+
|
|
7
|
+
# Get curent branch name
|
|
8
|
+
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
|
9
|
+
remote_name=$(git config --get branch.$current_branch.remote)
|
|
10
|
+
|
|
11
|
+
## Push commit to git
|
|
12
|
+
git add .
|
|
13
|
+
git commit -m "version added: ### $version"
|
|
14
|
+
git push "$remote_name" "$current_branch"
|
|
4
15
|
|
|
5
16
|
if [ "$version" != "" ]; then
|
|
6
17
|
git tag -a "$version" -m "`git log -1 --format=%s`"
|
|
7
18
|
echo "Created a new tag, $version"
|
|
8
|
-
git push
|
|
19
|
+
git push --tags
|
|
9
20
|
npm publish
|
|
10
21
|
fi
|
package/deploy_prod.sh
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
# npm version
|
|
1
|
+
# npm version prerelease --preid=beta
|
|
2
2
|
version=`node -e 'console.log(require("./package.json").version)'`
|
|
3
|
-
|
|
3
|
+
echo "version $version"
|
|
4
|
+
echo "____________WIDGET-V5______________"
|
|
4
5
|
echo "CREATING TAG ON GIT FOR version: $version"
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
# Get curent branch name
|
|
8
|
+
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
|
9
|
+
remote_name=$(git config --get branch.$current_branch.remote)
|
|
10
|
+
|
|
11
|
+
## Push commit to git
|
|
12
|
+
git add .
|
|
13
|
+
git commit -m "version added: ### $version"
|
|
14
|
+
git push "$remote_name" "$current_branch"
|
|
6
15
|
|
|
7
16
|
if [ "$version" != "" ]; then
|
|
8
17
|
git tag -a "$version" -m "`git log -1 --format=%s`"
|
|
9
18
|
echo "Created a new tag, $version"
|
|
10
|
-
git push
|
|
19
|
+
git push --tags
|
|
11
20
|
npm publish
|
|
12
21
|
fi
|
package/package.json
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
[hideHeaderCloseButton]="g?.hideHeaderCloseButton"
|
|
16
16
|
[hideHeaderBackButton]="g?.singleConversation"
|
|
17
17
|
[hideCloseConversationOptionMenu]="(isConversationArchived || g?.hideCloseConversationOptionMenu)"
|
|
18
|
-
[hideRestartConversationOptionsMenu]="(isConversationArchived || (!g?.singleConversation && !hideTextAreaContent) || g?.hideRestartConversationOptionsMenu)"
|
|
19
18
|
[hideHeaderConversationOptionsMenu]="g?.hideHeaderConversationOptionsMenu"
|
|
20
19
|
[hideSignOutOptionMenu]="(!g?.singleConversation || !g?.showLogoutOption)"
|
|
21
20
|
[hideChatDetailOptionMenu]="(!g?.isDevMode)"
|
|
@@ -113,7 +112,7 @@
|
|
|
113
112
|
[attributes]="g?.attributes"
|
|
114
113
|
[senderId]="senderId"
|
|
115
114
|
[tenant]="g?.tenant"
|
|
116
|
-
[
|
|
115
|
+
[project]="g?.project"
|
|
117
116
|
[channelType]="g?.channelType"
|
|
118
117
|
[userFullname]="g?.userFullname"
|
|
119
118
|
[userEmail]="g?.userEmail"
|
|
@@ -231,7 +231,9 @@ export class ConversationComponent implements OnInit, AfterViewInit, OnChanges {
|
|
|
231
231
|
'LABEL_PLACEHOLDER',
|
|
232
232
|
'GUEST_LABEL',
|
|
233
233
|
'LABEL_START_NW_CONV',
|
|
234
|
-
'CONTINUE'
|
|
234
|
+
'CONTINUE',
|
|
235
|
+
'EMOJI_NOT_ELLOWED',
|
|
236
|
+
'DOMAIN_NOT_ALLOWED'
|
|
235
237
|
];
|
|
236
238
|
|
|
237
239
|
const keysContent = [
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
[class.hideTextReply]="hideTextReply">
|
|
4
|
-
|
|
1
|
+
<div class="footerContainerAlert">
|
|
2
|
+
<!-- LOGO-->
|
|
3
|
+
<div id="hiddenFooter" *ngIf="!hideTextAreaContent && poweredBy" class="fade-in-bottom" [class.hideTextReply]="hideTextReply">
|
|
4
|
+
<div tabindex="-1" class="c21-powered-by" [innerHTML]="poweredBy" (click)="managePoweredBy($event)"></div>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<!-- ALERT EMOJI & URLS -->
|
|
8
|
+
<div id="textAlert" *ngIf="!hideTextAreaContent && showAlertEmoji" class="fade-in-bottom" [class.hideTextReply]="hideTextReply">
|
|
9
|
+
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" version="1.1" viewBox="0 0 110 135">
|
|
10
|
+
<path d="M55,25.8c-23,0-41.7,18.7-41.7,41.7s18.7,41.7,41.7,41.7,41.7-18.7,41.7-41.7-18.7-41.7-41.7-41.7ZM55,91.5c-3.4,0-6.2-2.8-6.2-6.2s2.8-6.2,6.2-6.2,6.2,2.8,6.2,6.2-2.8,6.2-6.2,6.2ZM60.3,70.1c-.2,2.8-2.5,4.9-5.3,4.9s-5.1-2.2-5.3-4.9l-1.6-22.3c-.3-4,2.9-7.4,6.9-7.4s7.2,3.4,6.9,7.4l-1.6,22.3Z"/>
|
|
11
|
+
</svg>
|
|
12
|
+
<div tabindex="-1" class="alertText">{{translationMap.get('EMOJI_NOT_ELLOWED')}}</div>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div id="textAlert" *ngIf="!hideTextAreaContent && showAlertUrl" class="fade-in-bottom" [class.hideTextReply]="hideTextReply">
|
|
16
|
+
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" version="1.1" viewBox="0 0 110 135">
|
|
17
|
+
<path d="M55,25.8c-23,0-41.7,18.7-41.7,41.7s18.7,41.7,41.7,41.7,41.7-18.7,41.7-41.7-18.7-41.7-41.7-41.7ZM55,91.5c-3.4,0-6.2-2.8-6.2-6.2s2.8-6.2,6.2-6.2,6.2,2.8,6.2,6.2-2.8,6.2-6.2,6.2ZM60.3,70.1c-.2,2.8-2.5,4.9-5.3,4.9s-5.1-2.2-5.3-4.9l-1.6-22.3c-.3-4,2.9-7.4,6.9-7.4s7.2,3.4,6.9,7.4l-1.6,22.3Z"/>
|
|
18
|
+
</svg>
|
|
19
|
+
<div tabindex="-1" class="alertText">{{translationMap.get('DOMAIN_NOT_ALLOWED')}}</div>
|
|
20
|
+
</div>
|
|
5
21
|
</div>
|
|
6
22
|
|
|
7
23
|
<!-- TEXTAREA + ICONS: conv active-->
|
|
@@ -44,7 +60,7 @@
|
|
|
44
60
|
|
|
45
61
|
|
|
46
62
|
|
|
47
|
-
<div *ngIf="!isStopRec" class="visible-text-area"
|
|
63
|
+
<div *ngIf="!isStopRec" class="visible-text-area" [class.hasError]="showAlertEmoji || showAlertUrl" [class.disabled] = "( isConversationArchived || hideTextReply)? true : null">
|
|
48
64
|
<!-- isFilePendingToUpload || -->
|
|
49
65
|
<textarea
|
|
50
66
|
[attr.disabled] = "(hideTextReply)? true : null"
|
|
@@ -67,7 +83,7 @@
|
|
|
67
83
|
</div>
|
|
68
84
|
|
|
69
85
|
<!-- ICON SEND -->
|
|
70
|
-
<div *ngIf="(textInputTextArea !== '' && !isStopRec) || !showAudioRecorderFooterButton" tabindex="-1" class="chat21-textarea-button" [class.active]="textInputTextArea && !hideTextReply" id="chat21-button-send" (click)="onSendPressed($event)">
|
|
86
|
+
<div *ngIf="(textInputTextArea !== '' && !isStopRec) || !showAudioRecorderFooterButton" tabindex="-1" class="chat21-textarea-button" [class.disabled]="showAlertEmoji || showAlertUrl" [class.active]="textInputTextArea && !hideTextReply" id="chat21-button-send" (click)="onSendPressed($event)">
|
|
71
87
|
<span class="v-align-center">
|
|
72
88
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="24" width="24" viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
|
73
89
|
<path d="M1.8,18.9V1.7L22,10.3L1.8,18.9z M3.9,15.6l12.6-5.4L3.9,4.9v3.7l6.4,1.6l-6.4,1.6V15.6z M3.9,15.6V4.9v7V15.6z"/>
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss
CHANGED
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
&.disabled {
|
|
40
40
|
background-color: rgb(232, 233, 237);
|
|
41
41
|
}
|
|
42
|
+
&.hasError{
|
|
43
|
+
box-shadow: 0 0 0 1px var(--chat-footer-border-color-error) inset;
|
|
44
|
+
}
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
.chat21-textarea-button {
|
|
@@ -52,6 +55,12 @@
|
|
|
52
55
|
opacity: 1;
|
|
53
56
|
cursor: pointer;
|
|
54
57
|
}
|
|
58
|
+
&.disabled{
|
|
59
|
+
opacity: 0.3 !important;
|
|
60
|
+
pointer-events: none !important;
|
|
61
|
+
cursor: not-allowed !important;
|
|
62
|
+
|
|
63
|
+
}
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
.chat21-textarea-button span svg:hover {
|
|
@@ -273,16 +282,18 @@ textarea:active{
|
|
|
273
282
|
|
|
274
283
|
}
|
|
275
284
|
|
|
285
|
+
.footerContainerAlert{
|
|
286
|
+
position: relative;
|
|
287
|
+
}
|
|
276
288
|
|
|
277
289
|
#hiddenFooter{
|
|
278
|
-
|
|
290
|
+
position: absolute;
|
|
279
291
|
bottom: 100%;
|
|
280
292
|
width: 100%;
|
|
281
293
|
height: var(--chat-footer-logo-height);
|
|
282
294
|
display: flex;
|
|
283
295
|
align-items: center;
|
|
284
296
|
justify-content: center;
|
|
285
|
-
// position: absolute;
|
|
286
297
|
// box-shadow: inset 0px -22px 16px -15px rgba(0,0,0,0.1);
|
|
287
298
|
&.hideTextReply{
|
|
288
299
|
height: var(--chat-footer-height);
|
|
@@ -344,6 +355,37 @@ textarea:active{
|
|
|
344
355
|
}
|
|
345
356
|
}
|
|
346
357
|
|
|
358
|
+
#textAlert{
|
|
359
|
+
bottom: 100%;
|
|
360
|
+
width: 100%;
|
|
361
|
+
height: var(--chat-footer-logo-height);
|
|
362
|
+
display: flex;
|
|
363
|
+
align-items: center;
|
|
364
|
+
justify-content: center;
|
|
365
|
+
background-color: var(--content-background-color);
|
|
366
|
+
position: absolute;
|
|
367
|
+
svg{
|
|
368
|
+
fill: var(--chat-footer-border-color-error);
|
|
369
|
+
}
|
|
370
|
+
// box-shadow: inset 0px -22px 16px -15px rgba(0,0,0,0.1);
|
|
371
|
+
div.alertText{
|
|
372
|
+
color: var(--dark-gray);
|
|
373
|
+
font-size: 1.2em;
|
|
374
|
+
font-weight: 500;
|
|
375
|
+
line-height: 22px;
|
|
376
|
+
font-family: Mulish, sans-serif;
|
|
377
|
+
letter-spacing: 0.24px;
|
|
378
|
+
-webkit-font-smoothing: antialiased;
|
|
379
|
+
padding: 4px 12px;
|
|
380
|
+
color: var(--chat-footer-border-color-error);
|
|
381
|
+
}
|
|
382
|
+
&.hideTextReply{
|
|
383
|
+
height: var(--chat-footer-height);
|
|
384
|
+
position: unset;
|
|
385
|
+
box-shadow: none;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
347
389
|
.fade-in-bottom {
|
|
348
390
|
-webkit-animation: fade-in-bottom 0.5s cubic-bezier(0.600, -0.280, 0.735, 0.045) 0.0s;
|
|
349
391
|
animation: fade-in-bottom 0.5s cubic-bezier(0.600, -0.280, 0.735, 0.045) 0.0s;
|
|
@@ -367,4 +409,4 @@ textarea:active{
|
|
|
367
409
|
// left: 10px;
|
|
368
410
|
border: none;
|
|
369
411
|
margin: -2px -2px 0px;
|
|
370
|
-
}
|
|
412
|
+
}
|
package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts
CHANGED
|
@@ -10,8 +10,9 @@ import { UploadService } from 'src/chat21-core/providers/abstract/upload.service
|
|
|
10
10
|
import { ChatManager } from 'src/chat21-core/providers/chat-manager';
|
|
11
11
|
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
12
12
|
import { TYPE_MSG_FILE, TYPE_MSG_IMAGE, TYPE_MSG_TEXT } from 'src/chat21-core/utils/constants';
|
|
13
|
-
import { convertColorToRGBA } from 'src/chat21-core/utils/utils';
|
|
14
|
-
import { isImage } from 'src/chat21-core/utils/utils-message';
|
|
13
|
+
import { convertColorToRGBA, isAllowedUrlInText, isEmoji } from 'src/chat21-core/utils/utils';
|
|
14
|
+
import { findAndRemoveEmoji, isImage } from 'src/chat21-core/utils/utils-message';
|
|
15
|
+
import { ProjectModel } from 'src/models/project';
|
|
15
16
|
|
|
16
17
|
@Component({
|
|
17
18
|
selector: 'chat-conversation-footer',
|
|
@@ -24,7 +25,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
24
25
|
@Input() attributes: string;
|
|
25
26
|
@Input() senderId: string;
|
|
26
27
|
@Input() tenant: string;
|
|
27
|
-
@Input()
|
|
28
|
+
@Input() project: ProjectModel;
|
|
28
29
|
@Input() channelType: string;
|
|
29
30
|
@Input() userFullname: string;
|
|
30
31
|
@Input() userEmail: string;
|
|
@@ -81,10 +82,12 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
81
82
|
include: [ 'recent', 'people', 'nature', 'activity', 'flags']
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
showAlertEmoji: boolean = false
|
|
86
|
+
showAlertUrl: boolean = false;
|
|
87
|
+
|
|
84
88
|
convertColorToRGBA = convertColorToRGBA;
|
|
85
89
|
private logger: LoggerService = LoggerInstance.getInstance()
|
|
86
|
-
constructor(
|
|
87
|
-
private chatManager: ChatManager,
|
|
90
|
+
constructor(private chatManager: ChatManager,
|
|
88
91
|
private typingService: TypingService,
|
|
89
92
|
private uploadService: UploadService) { }
|
|
90
93
|
|
|
@@ -253,7 +256,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
253
256
|
// return snapshot.ref.getDownloadURL(); // Will return a promise with the download link
|
|
254
257
|
// }).then(downloadURL => {
|
|
255
258
|
// that.logger.log('[CONV-FOOTER] AppComponent::uploadSingle:: downloadURL', downloadURL]);
|
|
256
|
-
// that.g.wdLog([`Successfully uploaded file and got download link - ${downloadURL}`]);
|
|
257
259
|
|
|
258
260
|
// metadata.src = downloadURL;
|
|
259
261
|
// let type_message = TYPE_MSG_TEXT;
|
|
@@ -321,6 +323,13 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
321
323
|
(metadata) ? metadata = metadata : metadata = '';
|
|
322
324
|
this.onEmojiiPickerShow.emit(false)
|
|
323
325
|
this.logger.log('[CONV-FOOTER] SEND MESSAGE: ', msg, type, metadata, additional_attributes);
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
let checkUrlDomain = this.checkForUrlDomain(this.textInputTextArea)
|
|
329
|
+
if(!checkUrlDomain){
|
|
330
|
+
return
|
|
331
|
+
}
|
|
332
|
+
|
|
324
333
|
if (msg && msg.trim() !== '' || type === TYPE_MSG_IMAGE || type === TYPE_MSG_FILE ) {
|
|
325
334
|
|
|
326
335
|
// msg = htmlEntities(msg);
|
|
@@ -345,7 +354,7 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
345
354
|
// fine-sponziello
|
|
346
355
|
// this.conversationHandlerService = this.chatManager.getConversationHandlerByConversationId(this.conversationWith)
|
|
347
356
|
const senderId = this.senderId;
|
|
348
|
-
const projectid = this.
|
|
357
|
+
const projectid = this.project.id;
|
|
349
358
|
const channelType = this.channelType;
|
|
350
359
|
const userFullname = this.userFullname;
|
|
351
360
|
const userEmail = this.userEmail;
|
|
@@ -514,11 +523,49 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
514
523
|
//}, false);
|
|
515
524
|
}
|
|
516
525
|
|
|
526
|
+
|
|
527
|
+
checkForEmojii(text){
|
|
528
|
+
//remove emojii only if "emojii" exist and is set to false
|
|
529
|
+
if(this.project && this.project.settings?.allow_send_emoji === false){
|
|
530
|
+
this.showAlertEmoji = isEmoji(text);
|
|
531
|
+
if(this.showAlertEmoji){
|
|
532
|
+
return false
|
|
533
|
+
}
|
|
534
|
+
this.showAlertEmoji = false;
|
|
535
|
+
return true
|
|
536
|
+
}
|
|
537
|
+
this.showAlertEmoji = false;
|
|
538
|
+
return true
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
checkForUrlDomain(text){
|
|
542
|
+
if(this.project && this.project.settings?.allowed_urls === true){
|
|
543
|
+
this.showAlertUrl = !isAllowedUrlInText(text, this.project.settings?.allowed_urls_list);
|
|
544
|
+
if(this.showAlertUrl){
|
|
545
|
+
return false
|
|
546
|
+
}
|
|
547
|
+
this.showAlertUrl = false
|
|
548
|
+
return true
|
|
549
|
+
}
|
|
550
|
+
this.showAlertUrl = false
|
|
551
|
+
return true
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
}
|
|
555
|
+
|
|
517
556
|
|
|
518
557
|
|
|
519
558
|
onTextAreaChange(){
|
|
520
559
|
this.resizeInputField()
|
|
521
560
|
this.setWritingMessages(this.textInputTextArea)
|
|
561
|
+
|
|
562
|
+
//reset alert to defalt values before checking again
|
|
563
|
+
this.showAlertEmoji= false;
|
|
564
|
+
this.showAlertUrl = false;
|
|
565
|
+
let check = this.checkForEmojii(this.textInputTextArea)
|
|
566
|
+
if(!check){
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
522
569
|
}
|
|
523
570
|
|
|
524
571
|
onSendPressed(event) {
|
|
@@ -587,6 +634,12 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
587
634
|
|
|
588
635
|
addEmoji(event){
|
|
589
636
|
this.onEmojiiPickerShow.emit(false); //de-activate emojii picker on select
|
|
637
|
+
|
|
638
|
+
let check = this.checkForEmojii(this.textInputTextArea)
|
|
639
|
+
if(!check){
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
|
|
590
643
|
this.textInputTextArea = this.textInputTextArea.trimStart() + event.emoji.native + " "
|
|
591
644
|
this.setFocusOnId('chat21-main-message-context')
|
|
592
645
|
}
|
|
@@ -632,7 +685,6 @@ export class ConversationFooterComponent implements OnInit, OnChanges {
|
|
|
632
685
|
* @param str
|
|
633
686
|
*/
|
|
634
687
|
setWritingMessages(str) {
|
|
635
|
-
//this.messagingService.setWritingMessages(str, this.g.channelType);
|
|
636
688
|
this.typingService.setTyping(this.conversationWith, str, this.senderId, this.userFullname )
|
|
637
689
|
}
|
|
638
690
|
|
package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html
CHANGED
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
<!-- ICON RESTART CONVERSATION -->
|
|
115
|
-
<div class="c21-header-button c21-right" *ngIf="!hideRestartConversationOptionsMenu" (click)="restartChat()">
|
|
115
|
+
<!-- <div class="c21-header-button c21-right" *ngIf="!hideRestartConversationOptionsMenu" (click)="restartChat()">
|
|
116
116
|
<svg role="img" id="refresh" aria-labelledby="altIconTitle" class="icon-menu" xmlns="http://www.w3.org/2000/svg"
|
|
117
117
|
width="20px" height="20px" viewBox="0 0 20 20">
|
|
118
118
|
<path d="M9.6,18.2c0.6,0,1-0.7,1-1.5s-0.5-1.5-1-1.5H6c-0.6,0-1-0.7-1-1.5V7.8h1c0.4,0,0.8-0.4,1-0.9c0.2-0.6,0.1-1.2-0.2-1.6 l-2.1-3c-0.4-0.6-1.1-0.6-1.5,0l-2.1,3C0.9,5.7,0.8,6.3,1,6.9s0.5,0.9,1,0.9h1v5.9c0,2.5,1.4,4.4,3.1,4.4H9.6z"/>
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
<title id="altIconTitle">{{ translationMap?.get('RESTART') }}</title>
|
|
121
121
|
</svg>
|
|
122
122
|
<span class="label-menu-item">{{ translationMap?.get('RESTART') }}</span>
|
|
123
|
-
</div>
|
|
123
|
+
</div> -->
|
|
124
124
|
|
|
125
125
|
<!-- ICON MAXIMIZE -->
|
|
126
126
|
<!-- <div class="c21-header-button c21-right" *ngIf="heightStatus==='min'" (click)="maximizeMinimize('max')">
|
package/src/app/component/conversation-detail/conversation-header/conversation-header.component.ts
CHANGED
|
@@ -23,7 +23,6 @@ export class ConversationHeaderComponent implements OnInit, OnChanges {
|
|
|
23
23
|
@Input() typingLocation: string;
|
|
24
24
|
@Input() isTrascriptDownloadEnabled: boolean;
|
|
25
25
|
@Input() hideCloseConversationOptionMenu: boolean;
|
|
26
|
-
@Input() hideRestartConversationOptionsMenu: boolean;
|
|
27
26
|
@Input() hideHeaderCloseButton: boolean;
|
|
28
27
|
@Input() hideHeaderBackButton: boolean;
|
|
29
28
|
@Input() hideHeaderConversationOptionsMenu: boolean;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Component, ElementRef, AfterViewInit, Input, ViewChild } from '@angular/core';
|
|
2
2
|
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
|
3
|
+
import { LoggerService } from 'src/chat21-core/providers/abstract/logger.service';
|
|
4
|
+
import { LoggerInstance } from 'src/chat21-core/providers/logger/loggerInstance';
|
|
3
5
|
import { convertColorToRGBA } from 'src/chat21-core/utils/utils';
|
|
4
6
|
|
|
5
7
|
@Component({
|
|
@@ -26,13 +28,13 @@ export class AudioComponent implements AfterViewInit {
|
|
|
26
28
|
currentTime: number = 0;
|
|
27
29
|
isPlaying: boolean = false;
|
|
28
30
|
|
|
31
|
+
private logger: LoggerService = LoggerInstance.getInstance();
|
|
29
32
|
constructor(
|
|
30
33
|
private sanitizer: DomSanitizer,
|
|
31
34
|
private elementRef: ElementRef
|
|
32
35
|
) {}
|
|
33
36
|
|
|
34
37
|
ngAfterViewInit() {
|
|
35
|
-
console.log('stylesssss', this.stylesMap)
|
|
36
38
|
if (this.audioBlob) {
|
|
37
39
|
this.rawAudioUrl = URL.createObjectURL(this.audioBlob);
|
|
38
40
|
this.audioUrl = this.sanitizer.bypassSecurityTrustUrl(this.rawAudioUrl);
|
|
@@ -136,21 +138,33 @@ export class AudioComponent implements AfterViewInit {
|
|
|
136
138
|
return `${minutes}:${sec < 10 ? '0' + sec : sec}`;
|
|
137
139
|
}
|
|
138
140
|
|
|
139
|
-
getAudioDuration() {
|
|
140
|
-
const audio = new Audio();
|
|
141
|
-
audio.src = this.rawAudioUrl!;
|
|
142
|
-
audio.addEventListener('loadedmetadata', () => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
});
|
|
141
|
+
async getAudioDuration() {
|
|
142
|
+
// const audio = new Audio();
|
|
143
|
+
// audio.src = this.rawAudioUrl!;
|
|
144
|
+
// audio.addEventListener('loadedmetadata', () => {
|
|
145
|
+
// if (audio.duration === Infinity) {
|
|
146
|
+
// audio.currentTime = Number.MAX_SAFE_INTEGER;
|
|
147
|
+
// audio.ontimeupdate = () => {
|
|
148
|
+
// audio.ontimeupdate = null;
|
|
149
|
+
// audio.currentTime = 0;
|
|
150
|
+
// this.audioDuration = audio.duration;
|
|
151
|
+
// };
|
|
152
|
+
// } else {
|
|
153
|
+
// this.audioDuration = audio.duration;
|
|
154
|
+
// }
|
|
155
|
+
// });
|
|
156
|
+
|
|
157
|
+
const response = await fetch(this.rawAudioUrl!);
|
|
158
|
+
this.logger.debug('getAudioDuration: response ---> ', response)
|
|
159
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
160
|
+
this.logger.debug('getAudioDuration: arrayBuffer ---> ', arrayBuffer)
|
|
161
|
+
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
|
|
162
|
+
this.logger.debug('getAudioDuration: audioContext ---> ', audioContext)
|
|
163
|
+
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
|
|
164
|
+
this.logger.debug('getAudioDuration: audioBuffer ---> ', audioBuffer)
|
|
165
|
+
this.audioDuration = audioBuffer.duration;
|
|
166
|
+
this.logger.debug('getAudioDuration: audioDuration ---> ', this.audioDuration)
|
|
167
|
+
|
|
154
168
|
}
|
|
155
169
|
|
|
156
170
|
extractFirstColor(gradient: string): string | null {
|
|
@@ -93,6 +93,7 @@ export class GlobalSettingsService {
|
|
|
93
93
|
project['trialDaysLeft'],
|
|
94
94
|
project['trialExpired'],
|
|
95
95
|
project['updatedAt'],
|
|
96
|
+
project['settings'],
|
|
96
97
|
project['versions']
|
|
97
98
|
);
|
|
98
99
|
}
|
|
@@ -865,11 +866,6 @@ export class GlobalSettingsService {
|
|
|
865
866
|
if (TEMP !== undefined) {
|
|
866
867
|
globals.hideCloseConversationOptionMenu = (TEMP === true) ? true : false;;
|
|
867
868
|
}
|
|
868
|
-
TEMP = tiledeskSettings['hideRestartConversationOptionsMenu'];
|
|
869
|
-
// this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > hideHeaderConversationOptionsMenu:: ', TEMP]);
|
|
870
|
-
if (TEMP !== undefined) {
|
|
871
|
-
globals.hideRestartConversationOptionsMenu = (TEMP === true) ? true : false;;
|
|
872
|
-
}
|
|
873
869
|
TEMP = tiledeskSettings['hideHeaderConversationOptionsMenu'];
|
|
874
870
|
// this.logger.debug('[GLOBAL-SET] setVariablesFromSettings > hideHeaderConversationOptionsMenu:: ', TEMP]);
|
|
875
871
|
if (TEMP !== undefined) {
|
|
@@ -1240,10 +1236,6 @@ export class GlobalSettingsService {
|
|
|
1240
1236
|
if (TEMP !== null) {
|
|
1241
1237
|
this.globals.hideCloseConversationOptionMenu = TEMP;
|
|
1242
1238
|
}
|
|
1243
|
-
TEMP = el.nativeElement.getAttribute('hideRestartConversationOptionsMenu');
|
|
1244
|
-
if (TEMP !== null) {
|
|
1245
|
-
this.globals.hideRestartConversationOptionsMenu = TEMP;
|
|
1246
|
-
}
|
|
1247
1239
|
TEMP = el.nativeElement.getAttribute('hideSettings');
|
|
1248
1240
|
if (TEMP !== null) {
|
|
1249
1241
|
this.globals.hideSettings = TEMP;
|
|
@@ -1637,11 +1629,6 @@ export class GlobalSettingsService {
|
|
|
1637
1629
|
globals.hideCloseConversationOptionMenu = stringToBoolean(TEMP);
|
|
1638
1630
|
}
|
|
1639
1631
|
|
|
1640
|
-
TEMP = getParameterByName(windowContext, 'tiledesk_hideRestartConversationOptionsMenu');
|
|
1641
|
-
if (TEMP) {
|
|
1642
|
-
globals.hideRestartConversationOptionsMenu = stringToBoolean(TEMP);
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1645
1632
|
TEMP = getParameterByName(windowContext, 'tiledesk_hideSettings');
|
|
1646
1633
|
if (TEMP) {
|
|
1647
1634
|
globals.hideSettings = stringToBoolean(TEMP);
|
|
@@ -31,8 +31,13 @@
|
|
|
31
31
|
--chat-footer-border-radius: 16px;
|
|
32
32
|
--chat-footer-background-color: #f6f7fb;
|
|
33
33
|
--chat-footer-color: #1a1a1a;
|
|
34
|
+
--chat-footer-border-color-error: #aa0404;
|
|
34
35
|
|
|
35
|
-
--icon-fill-color: #5f6368
|
|
36
|
+
--icon-fill-color: #5f6368;
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
--content-background-color: #fff;
|
|
40
|
+
--content-text-color: var(--black);
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
$trasp-black:rgba(0,0,0,0.8);
|
package/src/app/utils/globals.ts
CHANGED
|
@@ -163,7 +163,6 @@ export class Globals {
|
|
|
163
163
|
openExternalLinkButton: boolean;
|
|
164
164
|
hideHeaderConversationOptionsMenu: boolean;
|
|
165
165
|
hideCloseConversationOptionMenu: boolean;
|
|
166
|
-
hideRestartConversationOptionsMenu: boolean;
|
|
167
166
|
hideSettings: boolean;
|
|
168
167
|
filterByRequester: boolean;
|
|
169
168
|
persistence;
|
|
@@ -337,8 +336,6 @@ export class Globals {
|
|
|
337
336
|
/** enable to close a conversation from upper-right header menu */
|
|
338
337
|
this.hideCloseConversationOptionMenu = false;
|
|
339
338
|
/** enable to hide/show options menu in conversation detail header */
|
|
340
|
-
this.hideRestartConversationOptionsMenu = false;
|
|
341
|
-
/** enable to hide/show options menu in conversation detail header */
|
|
342
339
|
this.hideSettings = false;
|
|
343
340
|
/** enable to hide/show options menu in home component */
|
|
344
341
|
this.filterByRequester = false;
|
|
@@ -528,7 +525,7 @@ export class Globals {
|
|
|
528
525
|
'fullscreenMode': this.fullscreenMode,
|
|
529
526
|
'filterByRequester': this.filterByRequester,
|
|
530
527
|
'hideHeaderConversationOptionsMenu': this.hideHeaderConversationOptionsMenu, 'hideHeaderCloseButton': this.hideHeaderCloseButton,
|
|
531
|
-
'hideCloseConversationOptionMenu': this.hideCloseConversationOptionMenu,
|
|
528
|
+
'hideCloseConversationOptionMenu': this.hideCloseConversationOptionMenu,
|
|
532
529
|
'hideSettings': this.hideSettings,
|
|
533
530
|
'isLogEnabled': this.isLogEnabled,
|
|
534
531
|
'isOpen': this.isOpen, 'isShown': this.isShown,
|
package/src/app/utils/utils.ts
CHANGED
|
@@ -200,15 +200,6 @@ export function avatarPlaceholder(name: string) {
|
|
|
200
200
|
return initials;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
export function isEmoji(str: string) {
|
|
204
|
-
// tslint:disable-next-line:max-line-length
|
|
205
|
-
const ranges = ['(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])'];
|
|
206
|
-
if (str.match(ranges.join('|'))) {
|
|
207
|
-
return true;
|
|
208
|
-
} else {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
203
|
|
|
213
204
|
export function setColorFromString(str: string) {
|
|
214
205
|
const arrayBckColor = ['#fba76f', '#80d066', '#73cdd0', '#ecd074', '#6fb1e4', '#f98bae'];
|
package/src/assets/i18n/en.json
CHANGED
|
@@ -91,5 +91,7 @@
|
|
|
91
91
|
|
|
92
92
|
"LABEL_PREVIEW": "Preview",
|
|
93
93
|
"SWITCH_TO": "Or switch to:",
|
|
94
|
-
"CONNECTION_NETWORK_ERROR": "Our apologies. There was some trouble connecting to network"
|
|
94
|
+
"CONNECTION_NETWORK_ERROR": "Our apologies. There was some trouble connecting to network",
|
|
95
|
+
"EMOJI_NOT_ELLOWED":"Emoji not allowed",
|
|
96
|
+
"DOMAIN_NOT_ALLOWED":"URL contains a non-allowed domain"
|
|
95
97
|
}
|
|
@@ -613,7 +613,7 @@
|
|
|
613
613
|
var brandJson = JSON.parse(xhr.response)
|
|
614
614
|
if(brandJson){
|
|
615
615
|
/** TITLE AND FAVICON **/
|
|
616
|
-
brandJson['WIDGET'].META_TITLE? document.
|
|
616
|
+
brandJson['WIDGET'].META_TITLE? document.title = brandJson['WIDGET'].META_TITLE : null;
|
|
617
617
|
brandJson['WIDGET'].FAVICON_URL? document.querySelector("link[rel~='icon']").setAttribute('href', brandJson['WIDGET'].FAVICON_URL) : null;
|
|
618
618
|
/** FOOTER-LOGO **/
|
|
619
619
|
brandJson['COMMON'].COMPANY_LOGO? document.getElementById('footer-logo').src = brandJson['COMMON'].COMPANY_LOGO : null;
|
|
@@ -624,6 +624,13 @@
|
|
|
624
624
|
brandJson['COMMON'].BRAND_PRIMARY_COLOR? document.body.style.setProperty('--base-company-logo', brandJson['COMMON'].BRAND_PRIMARY_COLOR): null;
|
|
625
625
|
/** IFRAME TITLE**/
|
|
626
626
|
brandJson['COMMON'].COMPANY_NAME? document.getElementById('tiledeskiframe').title = brandJson['COMMON'].COMPANY_NAME + ' Widget' : null;
|
|
627
|
+
/** META sharing ELEMENTS */
|
|
628
|
+
if(brandJson['WIDGET'].META_SHARE_INFO && Object.keys(brandJson['WIDGET'].META_SHARE_INFO).length > 0){
|
|
629
|
+
Object.keys(brandJson['WIDGET'].META_SHARE_INFO).forEach(key => {
|
|
630
|
+
var meta = document.querySelector("meta[property^='og:"+key.toLowerCase()+"']");
|
|
631
|
+
meta.setAttribute('content', brandJson['WIDGET'].META_SHARE_INFO[key])
|
|
632
|
+
})
|
|
633
|
+
}
|
|
627
634
|
}
|
|
628
635
|
}
|
|
629
636
|
|
|
@@ -719,7 +719,7 @@
|
|
|
719
719
|
var brandJson = JSON.parse(xhr.response)
|
|
720
720
|
if(brandJson){
|
|
721
721
|
/** TITLE AND FAVICON **/
|
|
722
|
-
brandJson['WIDGET'].META_TITLE? document.
|
|
722
|
+
brandJson['WIDGET'].META_TITLE? document.title = brandJson['WIDGET'].META_TITLE : null;
|
|
723
723
|
brandJson['WIDGET'].FAVICON_URL? document.querySelector("link[rel~='icon']").setAttribute('href', brandJson['WIDGET'].FAVICON_URL) : null;
|
|
724
724
|
/** FOOTER-LOGO **/
|
|
725
725
|
brandJson['COMMON'].COMPANY_LOGO? document.getElementById('footer-logo').src = brandJson['COMMON'].COMPANY_LOGO : null;
|
|
@@ -737,6 +737,13 @@
|
|
|
737
737
|
}
|
|
738
738
|
/** IFRAME TITLE**/
|
|
739
739
|
brandJson['COMMON'].COMPANY_LOGO? document.getElementById('tiledeskiframe').title = brandJson['COMMON'].COMPANY_NAME + ' Widget' : null;
|
|
740
|
+
/** META sharing ELEMENTS */
|
|
741
|
+
if(brandJson['WIDGET'].META_SHARE_INFO && Object.keys(brandJson['WIDGET'].META_SHARE_INFO).length > 0){
|
|
742
|
+
Object.keys(brandJson['WIDGET'].META_SHARE_INFO).forEach(key => {
|
|
743
|
+
var meta = document.querySelector("meta[property^='og:"+key.toLowerCase()+"']");
|
|
744
|
+
meta.setAttribute('content', brandJson['WIDGET'].META_SHARE_INFO[key])
|
|
745
|
+
})
|
|
746
|
+
}
|
|
740
747
|
}
|
|
741
748
|
}
|
|
742
749
|
}
|
|
@@ -1263,13 +1270,6 @@
|
|
|
1263
1270
|
window.Tiledesk('restart')
|
|
1264
1271
|
}
|
|
1265
1272
|
|
|
1266
|
-
function onClickHideRestartConversationOptionsMenu(){
|
|
1267
|
-
let status = document.querySelector('input[name="hideRestartConversationOptionsMenu"]:checked').value
|
|
1268
|
-
window.tiledeskSettings['hideRestartConversationOptionsMenu'] = stringToBoolean(status)
|
|
1269
|
-
console.log('onClickHideRestartConversationOptionsMenu:', window.tiledeskSettings)
|
|
1270
|
-
window.Tiledesk('restart')
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
1273
|
function onClickAllowTranscriptDownload(){
|
|
1274
1274
|
let status = document.querySelector('input[name="allowTranscriptDownload"]:checked').value
|
|
1275
1275
|
window.tiledeskSettings['allowTranscriptDownload'] = stringToBoolean(status)
|
|
@@ -2277,16 +2277,6 @@
|
|
|
2277
2277
|
<button class="btn btn-light" onclick="onClickHideCloseConversationOptionMenu()">Test this setting <i class="fa fa-magic" aria-hidden="true"></i></button>
|
|
2278
2278
|
</div>
|
|
2279
2279
|
</div>
|
|
2280
|
-
<div class="row">
|
|
2281
|
-
<div class="col-md-5 formElement"><span><em><strong>hideRestartConversationOptionsMenu</strong></em></span></div>
|
|
2282
|
-
<div class="col-md-5">
|
|
2283
|
-
<input class="form-check-input" type="radio" name="hideRestartConversationOptionsMenu" value="true"><label>True</label>
|
|
2284
|
-
<input class="form-check-input" type="radio" name="hideRestartConversationOptionsMenu" value="false" checked><label >False</label>
|
|
2285
|
-
</div>
|
|
2286
|
-
<div class="col-md-2">
|
|
2287
|
-
<button class="btn btn-light" onclick="onClickHideRestartConversationOptionsMenu()">Test this setting <i class="fa fa-magic" aria-hidden="true"></i></button>
|
|
2288
|
-
</div>
|
|
2289
|
-
</div>
|
|
2290
2280
|
<div class="row">
|
|
2291
2281
|
<div class="col-md-5 formElement"><span><em><strong>allowTranscriptDownload</strong></em></span></div>
|
|
2292
2282
|
<div class="col-md-5">
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8">
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
8
8
|
|
|
9
|
-
<title>Widget test page
|
|
9
|
+
<title>Widget test page</title>
|
|
10
10
|
<style>
|
|
11
11
|
|
|
12
12
|
@-moz-keyframes blink {0%{opacity:1;} 50%{opacity:0;} 100%{opacity:1;}} /* Firefox */
|
|
@@ -295,7 +295,10 @@
|
|
|
295
295
|
window.Tiledesk('onBeforeInit', function(event_data) {
|
|
296
296
|
console.log("onBeforeInit Tiledesk FN", event_data);
|
|
297
297
|
|
|
298
|
-
|
|
298
|
+
if(event_data.detail.appConfigs.brandSrc){
|
|
299
|
+
getBrandResources(event_data.detail.appConfigs.brandSrc)
|
|
300
|
+
}
|
|
301
|
+
// var brandSrc = event_data.detail.appConfigs.brandSrc? : null;
|
|
299
302
|
|
|
300
303
|
setTimeout(() => {
|
|
301
304
|
if(event_data && event_data.detail && event_data.detail.appConfigs){
|
|
@@ -408,7 +411,7 @@
|
|
|
408
411
|
var brandJson = JSON.parse(xhr.response)
|
|
409
412
|
if(brandJson){
|
|
410
413
|
/** TITLE AND FAVICON **/
|
|
411
|
-
brandJson['WIDGET'].META_TITLE? document.
|
|
414
|
+
brandJson['WIDGET'].META_TITLE? document.title = brandJson['WIDGET'].META_TITLE : null;
|
|
412
415
|
brandJson['WIDGET'].FAVICON_URL? document.querySelector("link[rel~='icon']").setAttribute('href', brandJson['WIDGET'].FAVICON_URL) : null;
|
|
413
416
|
/** FOOTER-LOGO **/
|
|
414
417
|
brandJson['COMMON'].COMPANY_LOGO? document.getElementById('footer-logo').src = brandJson['COMMON'].COMPANY_LOGO : null;
|
|
@@ -421,6 +424,13 @@
|
|
|
421
424
|
brandJson['COMMON'].DOCS? null: document.getElementById('share').style.display = 'none'
|
|
422
425
|
/** IFRAME TITLE**/
|
|
423
426
|
brandJson['COMMON'].COMPANY_LOGO? document.getElementById('tiledeskiframe').title = brandJson['COMMON'].COMPANY_NAME + ' Widget' : null;
|
|
427
|
+
/** META sharing ELEMENTS */
|
|
428
|
+
if(brandJson['WIDGET'].META_SHARE_INFO && Object.keys(brandJson['WIDGET'].META_SHARE_INFO).length > 0){
|
|
429
|
+
Object.keys(brandJson['WIDGET'].META_SHARE_INFO).forEach(key => {
|
|
430
|
+
var meta = document.querySelector("meta[property^='og:"+key.toLowerCase()+"']");
|
|
431
|
+
meta.setAttribute('content', brandJson['WIDGET'].META_SHARE_INFO[key])
|
|
432
|
+
})
|
|
433
|
+
}
|
|
424
434
|
}
|
|
425
435
|
|
|
426
436
|
}
|
|
@@ -194,9 +194,13 @@ export function isEmojii(message: any){
|
|
|
194
194
|
// https://localcoder.org/javascript-detect-if-a-string-contains-only-unicode-emojis
|
|
195
195
|
try {
|
|
196
196
|
if(!message) return false;
|
|
197
|
+
// Removes all characters that are NOT emojis (unicode > \u1eeff)
|
|
197
198
|
const onlyEmojis = message.replace(new RegExp('[\u0000-\u1eeff]', 'g'), '')
|
|
199
|
+
// Removes spaces, line breaks, and carriage returns from the string
|
|
198
200
|
const visibleChars = message.replace(new RegExp('[\n\r\s]+|( )+', 'g'), '')
|
|
201
|
+
// Removes Chinese characters from the string
|
|
199
202
|
const chineseChars = message.replace(new RegExp('[\u4e00-\u9fa5]', 'g'), '')
|
|
203
|
+
|
|
200
204
|
if(onlyEmojis === '' || visibleChars == '' || chineseChars=='') return false
|
|
201
205
|
return (onlyEmojis.length === visibleChars.length && onlyEmojis.length <= 2)
|
|
202
206
|
} catch(e) {
|
|
@@ -204,6 +208,22 @@ export function isEmojii(message: any){
|
|
|
204
208
|
}
|
|
205
209
|
}
|
|
206
210
|
|
|
211
|
+
export function findAndRemoveEmoji(text): string{
|
|
212
|
+
|
|
213
|
+
if (!text) return text;
|
|
214
|
+
|
|
215
|
+
// Regex to find most unicode emojis
|
|
216
|
+
// Source: https://thekevinscott.com/emojis-in-javascript/
|
|
217
|
+
const emojiRegex = /([\u2700-\u27BF]|[\uE000-\uF8FF]|[\uD83C-\uDBFF][\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83D[\uDE00-\uDE4F])/g;
|
|
218
|
+
|
|
219
|
+
// Removes all found emojis
|
|
220
|
+
text = text.replace(emojiRegex, '');
|
|
221
|
+
|
|
222
|
+
// Removes any multiple spaces left by the removal of emojis
|
|
223
|
+
text = text.replace(/\s{2,}/g, ' ').trim();
|
|
224
|
+
return text
|
|
225
|
+
}
|
|
226
|
+
|
|
207
227
|
export function isJustRecived(startedAt, time) {
|
|
208
228
|
if (time > startedAt) {
|
|
209
229
|
return true;
|
|
@@ -579,4 +579,87 @@ function componentFromStr(numStr, percent) {
|
|
|
579
579
|
|
|
580
580
|
|
|
581
581
|
|
|
582
|
+
// export function isAllowedUrlInText(text: string, allowedUrls: string[]): boolean {
|
|
583
|
+
// // Regex per trovare URL o domini nudi nel testo
|
|
584
|
+
// const urlRegex = /https?:\/\/[^\s]+|www\.[^\s]+|(?:\b[\w-]+\.)+[a-z]{2,}(\/[^\s]*)?/gi;
|
|
585
|
+
// const foundUrls = text.match(urlRegex);
|
|
586
|
+
|
|
587
|
+
// if (!foundUrls) {
|
|
588
|
+
// return true; // Nessun URL => testo ammesso
|
|
589
|
+
// }
|
|
590
|
+
|
|
591
|
+
// // Normalizza dominio: rimuove schema, www., slash finali
|
|
592
|
+
// const normalize = (url: string) =>
|
|
593
|
+
// url
|
|
594
|
+
// .replace(/^https?:\/\//i, '')
|
|
595
|
+
// .replace(/^www\./i, '')
|
|
596
|
+
// .replace(/\/$/, '')
|
|
597
|
+
// .toLowerCase();
|
|
598
|
+
|
|
599
|
+
// // Normalizza tutti gli allowed pattern per confronto
|
|
600
|
+
// const normalizedAllowedPatterns = allowedUrls.map(pattern =>
|
|
601
|
+
// pattern
|
|
602
|
+
// .replace(/^https?:\/\//i, '')
|
|
603
|
+
// .replace(/^www\./i, '')
|
|
604
|
+
// .replace(/\/$/, '')
|
|
605
|
+
// .toLowerCase()
|
|
606
|
+
// .replace(/\./g, '\\.')
|
|
607
|
+
// .replace(/\//g, '\\/')
|
|
608
|
+
// .replace(/\*/g, '.*')
|
|
609
|
+
// );
|
|
610
|
+
|
|
611
|
+
// return foundUrls.every(rawUrl => {
|
|
612
|
+
// const url = normalize(rawUrl);
|
|
613
|
+
// return normalizedAllowedPatterns.some(pattern => {
|
|
614
|
+
// const regex = new RegExp(`^${pattern}$`, 'i');
|
|
615
|
+
// return regex.test(url);
|
|
616
|
+
// });
|
|
617
|
+
// });
|
|
618
|
+
// }
|
|
619
|
+
|
|
620
|
+
export function isAllowedUrlInText(text: string, allowedUrls: string[]) {
|
|
621
|
+
const urlsInMessage = extractUrls(text);
|
|
622
|
+
console.log('urlsInMessage ++++ :', urlsInMessage);
|
|
623
|
+
|
|
624
|
+
const allowedPatterns = allowedUrls.map((url) => {
|
|
625
|
+
try {
|
|
626
|
+
// Prova a estrarre il dominio da una URL completa
|
|
627
|
+
const hostname = new URL(url).hostname.toLowerCase();
|
|
628
|
+
return hostname;
|
|
629
|
+
} catch {
|
|
630
|
+
// Lascia il dominio nudo (es: "*.tiledesk.com" o "tiledesk.com")
|
|
631
|
+
return url.toLowerCase();
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
const matchesAllowed = (domain: string) => {
|
|
636
|
+
return allowedPatterns.some((pattern) => {
|
|
637
|
+
if (pattern.startsWith('*.')) {
|
|
638
|
+
const base = pattern.replace(/^\*\./, '');
|
|
639
|
+
return domain === base || domain.endsWith('.' + base);
|
|
640
|
+
} else {
|
|
641
|
+
return domain === pattern;
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
const nonWhitelistedDomains = urlsInMessage.filter((url) => {
|
|
647
|
+
try {
|
|
648
|
+
const domain = new URL(url).hostname.toLowerCase();
|
|
649
|
+
return !matchesAllowed(domain);
|
|
650
|
+
} catch (e) {
|
|
651
|
+
return true; // Considera URL non valido come non ammesso
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
return nonWhitelistedDomains.length === 0;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function extractUrls(text: string): string[] {
|
|
659
|
+
const urlRegex = /https?:\/\/[^\s]+/g;
|
|
660
|
+
return text.match(urlRegex) || [];
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
582
665
|
|
package/src/models/project.ts
CHANGED
|
@@ -24,7 +24,8 @@ export class ProjectModel {
|
|
|
24
24
|
public color?: string,
|
|
25
25
|
public welcomeTitle?: string,
|
|
26
26
|
public welcomeMsg?: string,
|
|
27
|
-
public attributes?: IRules
|
|
27
|
+
public attributes?: IRules,
|
|
28
|
+
public settings?:{ [key: string]: any },
|
|
28
29
|
) { }
|
|
29
30
|
|
|
30
31
|
initialize (
|
|
@@ -43,6 +44,7 @@ export class ProjectModel {
|
|
|
43
44
|
trialDaysLeft?: number,
|
|
44
45
|
trialExpired?: boolean,
|
|
45
46
|
updatedAt?: string,
|
|
47
|
+
settings?: { [key: string]: any },
|
|
46
48
|
versions?: string,
|
|
47
49
|
) {
|
|
48
50
|
this.id = id;
|
|
@@ -60,6 +62,7 @@ export class ProjectModel {
|
|
|
60
62
|
this.trialDaysLeft = trialDaysLeft;
|
|
61
63
|
this.trialExpired = trialExpired;
|
|
62
64
|
this.updatedAt = updatedAt;
|
|
65
|
+
this.settings = settings;
|
|
63
66
|
this.versions = versions;
|
|
64
67
|
}
|
|
65
68
|
|