PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.8
VikBooking Hotel Booking Engine & PMS v1.8.8
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / site / resources / chat / session / guest.js

guest.js in VikBooking Hotel Booking Engine & PMS 1.8.8, at site/resources/chat/session/guest.js

309 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function($, w) {
2 'use strict';
3
4 /*****************
5 * SHARE SESSION *
6 *****************/
7
8 /**
9 * Share session disabled status handler.
10 */
11 $(w).on('chat.session.share.disabled', (event) => {
12 const [root, parentEvent, button, chat] = event.args;
13
14 // disable the button in case we have no messages
15 event.shouldDisable = chat.data.environment.messages.length ? false : true;
16 });
17
18 /**
19 * Session session button action handler.
20 */
21 $(w).on('chat.session.share.action', async (event) => {
22 const [root, parentEvent, button, chat] = event.args;
23
24 // remove the any textarea previously created
25 $('textarea#chat-session-copy-area').remove();
26
27 const copyArea = $('<textarea id="chat-session-copy-area"></textarea>')
28 .val(button.url)
29 .css('width', 0)
30 .css('height', 0)
31 .css('opacity', 0)
32 .css('float', 'right');
33
34 $('body').append(copyArea);
35
36 // copy URL within the clipboard
37 VBOCore.copyToClipboard(copyArea[0]).then((success) => {
38 VBOToast.dispatch(new VBOToastMessage({
39 body: 'URL copied to clipboard!',
40 status: VBOToast.SUCCESS_STATUS,
41 delay: 'auto',
42 action: () => {
43 VBOToast.dispose(true);
44 },
45 }));
46
47 copyArea.remove();
48 }).catch((err) => {
49 // make textarea visible on screen again
50 copyArea.css('width', '100%');
51 copyArea.css('height', '50px');
52 copyArea.css('opacity', 1);
53 copyArea.css('float', 'none');
54 copyArea.css('resize', 'none');
55 copyArea.css('margin', '10px 0 0 0');
56 copyArea.prop('readonly', true);
57
58 // auto-dispose the toast after copying the contents
59 copyArea.on('copy', () => {
60 setTimeout(() => VBOToast.dispose(true), 1000);
61 });
62
63 // prevent native event used to dispose the toast on click
64 copyArea.on('click', (event) => {
65 // reselect the whole text
66 copyArea.select();
67
68 // prevent the toast from closing
69 event.preventDefault();
70 event.stopPropagation();
71 return false;
72 });
73
74 const body = $('<div>Unable to copy URL to clipboard! Please proceed manually.</div>')
75 .append(copyArea);
76
77 VBOToast.dispatch(new VBOToastMessage({
78 body: body,
79 status: VBOToast.ERROR_STATUS,
80 delay: 0, // do not auto-dispose
81 callback: () => {
82 // auto select textarea and focus it
83 copyArea.select().focus();
84 },
85 }));
86 });
87 });
88
89 /*********************
90 * START NEW SESSION *
91 *********************/
92
93 const restartSession = (chat) => {
94 return new Promise((resolve, reject) => {
95 // make the request
96 VBOChatAjax.do(
97 chat.data.environment.url,
98 {
99 task: 'chat.end_session',
100 restart: 1,
101 },
102 (resp) => {
103 resolve(resp.id);
104 },
105 (error) => {
106 reject(error);
107 }
108 );
109 });
110 }
111
112 const refreshChat = (chat, contextId) => {
113 return new Promise((resolve, reject) => {
114 VBOChatAjax.do(
115 chat.data.environment.url,
116 {
117 task: 'chat.render_chat',
118 context: 'session',
119 id_context: contextId,
120 },
121 (resp) => {
122 resolve(resp.html);
123 },
124 (error) => {
125 reject(error);
126 }
127 );
128 });
129 }
130
131 /**
132 * Restart session disabled status handler.
133 */
134 $(w).on('chat.session.restart.disabled', (event) => {
135 const [root, parentEvent, button, chat] = event.args;
136
137 event.shouldDisable = true;
138
139 // iterate all the messages
140 for (let i = 0; i < chat.data.environment.messages.length; i++) {
141 let message = chat.data.environment.messages[i];
142
143 // in case we have a message sent by another user, enable the button
144 if (!chat.isSender(message)) {
145 event.shouldDisable = false;
146 }
147 }
148 });
149
150 /**
151 * Restart session button action handler.
152 */
153 $(w).on('chat.session.restart.action', async (event) => {
154 const [root, parentEvent, button, chat] = event.args;
155
156 if (!confirm(Joomla.JText._('VBO_WANT_PROCEED'))) {
157 // ignored by the user
158 return;
159 }
160
161 // identify the target chat element
162 const chatTargetEl = $(chat.data.element.conversation).closest('.chat-session-target');
163
164 try {
165 // close current session and start a new one
166 const sessionId = await restartSession(chat);
167 // refresh chat
168 const newChatHTML = await refreshChat(chat, sessionId);
169
170 // destroy chat after renewing the session
171 chat.destroy();
172
173 // replace HTML
174 chatTargetEl.html(newChatHTML);
175 } catch (error) {
176 console.error(error);
177
178 chat.alert(error.responseText || error.statusText || 'Connection lost!');
179 }
180 });
181
182 /***************
183 * CHAT EVENTS *
184 ***************/
185
186 /**
187 * Fires after preparing the conversation.
188 * Changes the native alert behavior applied by the chat.
189 *
190 * For guest only.
191 */
192 window.addEventListener('chat.prepare', (event) => {
193 const {messages, chat} = event.detail;
194
195 if (chat.data.environment.context.alias !== 'session') {
196 // ignore if we are not visiting the chat for a different context
197 return;
198 }
199
200 // prefer a toast message rather than a system alert
201 chat.alert = (error) => {
202 // display the error through toast
203 VBOToast.dispatch(new VBOToastMessage({
204 body: error,
205 status: VBOToast.ERROR_STATUS,
206 delay: 'auto',
207 }));
208 }
209 });
210
211 /**
212 * Fires before the chat delivers the message.
213 * Displays a "Thinking..." bubble in case the AI is enabled.
214 *
215 * For guest only.
216 */
217 window.addEventListener('chat.send.before', (event) => {
218 const {message, chat} = event.detail;
219
220 if (chat.data.environment.context.alias !== 'session') {
221 // ignore if we are not visiting the chat for a different context
222 return;
223 }
224
225 if (chat.data.environment.users.hasOwnProperty(-2) == false) {
226 // do not go ahead in case the AI is not involved
227 return;
228 }
229
230 if (!chat.data.environment.context.metadata.use_ai) {
231 // do not go ahead in case the AI has been manually blocked
232 return;
233 }
234
235 if ($('#msg-ai-typing').length) {
236 // do not add another placeholder
237 return;
238 }
239
240 // build dummy object
241 const dummy = {
242 id: 'msg-ai-typing',
243 message: Joomla.JText._('VBO_CHAT_AI_THINKING').replace(/\.+$/, '') + '<span class="ai-thinking-dots"><span></span><span></span><span></span></span>',
244 id_sender: -2,
245 sender_name: 'AI',
246 createdon: DateHelper.toStringUTC(new Date()),
247 };
248
249 setTimeout(() => {
250 // draw message within the chat
251 chat.drawMessage(dummy);
252 // force scroll to bottom
253 setTimeout(() => chat.scrollToBottom(), 32);
254 }, 512);
255 });
256
257 /**
258 * Fires in case the chat fails to deliver a message.
259 * Removes the "Thinking..." bubble previously displayed.
260 *
261 * For guest only.
262 */
263 window.addEventListener('chat.send.failed', (event) => {
264 const {message, chat, error} = event.detail;
265
266 if (chat.data.environment.context.alias !== 'session') {
267 // ignore if we are not visiting the chat for a different context
268 return;
269 }
270
271 if (error.status == 403) {
272 // in case of forbidden error, prevent replies by removing the message from the chat
273 chat.removeMessage(message.id, true);
274
275 // display the error through toast
276 VBOToast.dispatch(new VBOToastMessage({
277 body: error.responseText || error.statusText || 'Forbidden!',
278 status: VBOToast.ERROR_STATUS,
279 }));
280 }
281
282 setTimeout(() => {
283 // remove placeholder on failure
284 $('#msg-ai-typing').remove();
285 }, 512);
286 });
287
288 /**
289 * Fires before syncing the conversation.
290 * Removes the "Thinking..." bubble previously displayed.
291 *
292 * For guest only.
293 */
294 window.addEventListener('chat.sync.before', (event) => {
295 const {messages, chat} = event.detail;
296
297 if (chat.data.environment.context.alias !== 'session') {
298 // ignore if we are not visiting the chat for a different context
299 return;
300 }
301
302 // remove thinking bubble only if the response contains at least a message wrote by AI
303 if (messages.some(message => message.id_sender == -2)) {
304 // remove the "thinking" bubble before syncing the messages
305 $('#msg-ai-typing').remove();
306 }
307 });
308
309 })(jQuery, window);