Built motion from commit b87691d.|0.0.53
[motion.git] / server / components / xchatty / xchatty.js
1 /**
2  *
3  * xChatty: xCally Shuttle WebChat Client
4  * Powered by Xenialab
5  *
6  * @author          Xenialab
7  * @link            http://www.xcally.com
8  * @since           xChatty v 2.0
9  *
10  */
11 var xChatty = {
12     config: {
13         websiteId: {{websiteId}},
14         signedUp: {{signedUp}},
15         windowFocused: {{windowFocused}},
16         isNewPage: {{isNewPage}},
17         processingSignUp: {{processingSignUp}},
18         processingEnquiry: {{processingEnquiry}},
19         processingSend: {{processingSend}},
20         visitor: {
21             fullname: '',
22             avatar: ''
23         },
24         timerReadMessages: {{timerReadMessages}},
25         timerCheckStatus: {{timerCheckStatus}},
26         timerSendMessages: '',
27         timerSignupResponse: '',
28         isOnline: {{isOnline}},
29         decayHistory: {{decayHistory}},
30         defaultTimeout: {{defaultTimeout}},
31         isInitialStatusCheck: {{isInitialStatusCheck}},
32         muteNotificationSoundOnce: {{muteNotificationSoundOnce}},
33         assetBase: '{{& assetBase}}',
34         rootPath: '{{& rootPath}}',
35         hasSessionSaf: {{hasSessionSaf}},
36         restoreOpenState: {{restoreOpenState}},
37         animateHover: {{animateHover}},
38         hideEmail: {{hideEmail}},
39         hideOffline: {{hideOffline}},
40         headerShape: '{{headerShape}}',
41         downloadTranscript: {{downloadTranscript}}
42     },
43     Lang: {
44         "HeaderCurrentlyChatting": "Live Chat",
45         "HeaderOnline": '{{HeaderOnline}}',
46         "HeaderOffline": "{{HeaderOffline}}",
47         "OperatorOfflineMessage": "It appears as if all operators are currently offline.",
48         "OfflineMessage": "{{{OfflineMessage}}}",
49         "OnlineMessage": '{{OnlineMessage}}',
50         "UsernamePlaceholder": '{{UsernamePlaceholder}}',
51         "EmailPlaceholder": '{{EmailPlaceholder}}',
52         "EnquiryMessagePlaceholder": "{{EnquiryMessagePlaceholder}}",
53         "EnquiryButtonText": "{{EnquiryButtonText}}",
54         "EnquirySubmitSuccess": "Your message was sucessfully submitted - we will contact you as soon as possible.",
55         "StartChatButtonText": '{{StartChatButtonText}}',
56         "OperatorComposing": "{fullname} is typing...",
57         "FirstMessageText": "",
58         "ExitChatButtonText": "Exit Chat",
59         "ExitChatQuestionText": "Are you sure?",
60         "ExitChatButtonConfirmText": "Yes",
61         "ExitChatButtonCancelText": "No",
62         "MessagePlaceholderText": "Your message...",
63         "MessageSendButtonText": "Send",
64         "ValidationEmailRequired": "Please enter your email address",
65         "ValidationEmailInvalid": "Please enter a valid email address",
66         "ValidationEmailMaxLength": "The email address may not exceed 85 characters",
67         "ValidationUsernameRequired": "Please enter your name",
68         "ValidationUsernameMaxLength": "The name may not exceed 45 characters",
69         "ValidationEnquiryRequired": "Please enter your enquiry",
70         "ValidationEnquiryMaxLength": "The enquiry may not exceed 1500 characters",
71         "ValidationMessageRequired": "Please enter your message",
72         "ValidationMessageMaxLength": "The message may not exceed 750 characters",
73         "DownloadTranscript": "Download Transcript"
74     },
75     init: function() {
76         jQuery(".xc_chat_container").css('margin-bottom', '-50px');
77         if (!xChatty.config.hideOffline)
78             jQuery(".xc_chat_container").show();
79         jQuery(".xc_chat_container").animate({
80             marginBottom: 0
81         }, {
82             duration: 500,
83             queue: true,
84             complete: function() {
85                 if (xChatty.config.restoreOpenState) {
86                     xChatty.config.isNewPage = true;
87                     jQuery(".xc_chat_head").trigger("click");
88                 }
89             }
90         });
91         xChatty.initAnimateHover();
92         jQuery(window).focus(function() {
93             xChatty.config.windowFocused = true;
94         });
95         jQuery(window).blur(function() {
96             xChatty.config.windowFocused = false;
97         });
98         jQuery(document).on("click", ".xc_chat_head", xChatty.headerClick);
99         jQuery(document).on("click", ".xc_btn_enquiry", xChatty.enquiryClick);
100         jQuery(document).on("submit", ".xc_form_enquiry", xChatty.enquirySubmit);
101         // jQuery(document).on("click", ".xc_btn_signup", xChatty.signUpClick);
102         jQuery(document).on("submit", ".xc_form_signup", xChatty.signUpSubmit);
103         jQuery(document).on("click", ".xc_btn_send", xChatty.sendClick);
104         jQuery(document).on("submit", ".xc_form_reply", xChatty.onSendSubmit);
105         jQuery(document).on("click", ".xc_btn_exit_chat", xChatty.btnExitChatClick);
106         jQuery(document).on("click", ".xc_btn_exit_chat_confirm", xChatty.btnExitChatConfirmClick);
107         jQuery(document).on("click", ".xc_btn_exit_chat_cancel", xChatty.btnExitChatCancelClick);
108         jQuery(document).on("click", ".xc_btn_notifications_close", xChatty.btnNotificationsCloseClick);
109         jQuery(document).on("keyup", ".xc_chat_container textarea, .xc_chat_container input", xChatty.messageKeyUp);
110         jQuery(document).on("keydown", ".xc_input_message", xChatty.messageKeyDown);
111         jQuery('[placeholder]').each(function() {
112             jQuery(this).css('color', '#ccc').val(jQuery(this).attr('placeholder'));
113         }).bind('focus', function() {
114             jQuery(this).css('color', 'inherit');
115             if (jQuery(this).val() === jQuery(this).attr('placeholder')) {
116                 jQuery(this).val('');
117             }
118         }).bind('blur', function() {
119             if (jQuery(this).val() === '') {
120                 jQuery(this).val(jQuery(this).attr('placeholder')).css('color', '#ccc');
121             }
122         });
123         xChatty.readMessages();
124     },
125     initAnimateHover: function() {
126         if (xChatty.config.animateHover !== true)
127             return;
128         jQuery(".xc_chat_container").animate({
129             opacity: 0.7
130         }, {
131             duration: 0,
132             queue: false
133         });
134         jQuery(".xc_chat_container").hover(function() {
135             jQuery(this).animate({
136                 opacity: 1
137             }, {
138                 duration: 200,
139                 queue: false
140             });
141         }, function() {
142             if (!jQuery(this).hasClass("xc_box_open"))
143                 jQuery(this).animate({
144                     opacity: 0.7
145                 }, {
146                     duration: 200,
147                     queue: false
148                 });
149         });
150         jQuery(".xc_chat_container").bind("chatOpen", function(e, isOpen) {
151             if (isOpen) {
152                 jQuery(this).animate({
153                     opacity: 1
154                 }, {
155                     duration: 200,
156                     queue: false
157                 });
158             } else {
159                 jQuery(this).animate({
160                     opacity: 0.7
161                 }, {
162                     duration: 200,
163                     queue: false
164                 });
165             }
166         });
167     },
168     enquiryClick: function(e) {
169         e.preventDefault();
170         jQuery(".xc_form_enquiry").submit();
171     },
172     btnExitChatClick: function(e) {
173         e.preventDefault();
174         jQuery(".xc_exit_chat_confirmation_wrapper").show();
175         jQuery(this).hide();
176     },
177     btnExitChatConfirmClick: function(e) {
178         e.preventDefault();
179         clearTimeout(xChatty.config.timerReadMessages);
180         clearTimeout(xChatty.config.timerCheckStatus);
181         var formData = jQuery(this).serializeArray();
182         formData.push({
183             name: 'data[sign_out]',
184             value: true
185         });
186         jQuery.ajax({
187             url: xChatty.config.rootPath + "signout",
188             data: formData,
189             dataType: "jsonp",
190             jsonpCallback: xChatty.getJsonpCallbackName(),
191             success: function(result) {
192                 if (result.success === true) {
193                     xChatty.resetDefaultState();
194                 } else {}
195             },
196             complete: function() {
197                 xChatty.checkStatus(true);
198             }
199         });
200     },
201     btnExitChatCancelClick: function(e) {
202         e.preventDefault();
203         jQuery(".xc_exit_chat_confirmation_wrapper").hide();
204         jQuery(".xc_btn_exit_chat").show();
205     },
206     resetDefaultState: function() {
207         xChatty.config.signedUp = false;
208         xChatty.config.visitor = {
209             fullname: "",
210             avatar: ""
211         };
212         jQuery(".xc_conversation_container").empty();
213         jQuery(".xc_conversation_container").html('<p class="xc_message_intro" data-id="-10">' + xChatty.Lang.FirstMessageText + '</p>');
214         jQuery(".xc_exit_chat_confirmation_wrapper").hide();
215         jQuery(".xc_btn_exit_chat").show();
216         jQuery(".xc_chat_head").trigger("click");
217     },
218     enquirySubmit: function(e) {
219         e.preventDefault();
220         if (xChatty.config.processingEnquiry)
221             return false;
222         var validationErrors = {};
223         if (jQuery.trim(jQuery(".xc_input_enquiry_fullname").val()) === '' || jQuery(".xc_input_enquiry_fullname").val() === jQuery(".xc_input_enquiry_fullname").attr("placeholder")) {
224             validationErrors["fullname"] = [xChatty.Lang.ValidationUsernameRequired];
225         }
226         if (jQuery.trim(jQuery(".xc_input_enquiry_email").val()) === '' || jQuery(".xc_input_enquiry_email").val() === jQuery(".xc_input_enquiry_email").attr("placeholder")) {
227             validationErrors["email"] = [xChatty.Lang.ValidationEmailRequired];
228         }
229         if (jQuery.trim(jQuery(".xc_input_enquiry_message").val()) === '' || jQuery(".xc_input_enquiry_message").val() === jQuery(".xc_input_enquiry_message").attr("placeholder")) {
230             validationErrors["message"] = [xChatty.Lang.ValidationEnquiryRequired];
231         }
232         if (validationErrors.hasOwnProperty("fullname") || validationErrors.hasOwnProperty("email") || validationErrors.hasOwnProperty("message")) {
233             xChatty.renderNotifications(validationErrors, true);
234             return;
235         }
236         xChatty.config.processingEnquiry = true;
237         var enquiryForm = jQuery(this);
238         enquiryForm.addClass("xc_enquiry_sending");
239         var formData = jQuery(this).serializeArray();
240         formData.push({
241             name: 'data[Enquiry][websiteId]',
242             value: xChatty.config.websiteId
243         });
244         formData.push({
245             name: 'data[Enquiry][current_page]',
246             value: encodeURIComponent(encodeURIComponent(document.URL))
247         });
248         xChatty.handleAjaxSubmitCall(formData, enquiryForm);
249         return false;
250     },
251     handleAjaxSubmitCall: function(formData, enquiryForm) {
252       jQuery.ajax({
253           url: xChatty.config.rootPath + "submit",
254           data: formData,
255           dataType: "jsonp",
256           jsonpCallback: xChatty.getJsonpCallbackName(),
257           success: function(result) {
258               if (result.success === true) {
259                   jQuery(".xc_notifications_wrapper").slideUp();
260                   xChatty.clearNotifications();
261                   jQuery(".xc_form_enquiry")[0].reset();
262                   var notifications = {
263                       success: [xChatty.Lang.EnquirySubmitSuccess]
264                   };
265                   xChatty.renderNotifications(notifications, false);
266               } else {
267                   xChatty.renderNotifications(result.errors, true);
268               }
269               xChatty.config.processingEnquiry = false;
270               enquiryForm.removeClass("xc_enquiry_sending");
271               jQuery(".xc_chat_container input, .xc_chat_container textarea").trigger("blur");
272           },
273           error: function(err) {
274             var error = {
275               'message': 'Service temporarily unavailable. We back as soon as possible!'
276             };
277             xChatty.renderErrors(error, true);
278             xChatty.config.timerSendMessages = setTimeout(function() {
279               xChatty.handleAjaxSubmitCall(formData, enquiryForm);
280             }, 5000);
281           }
282       });
283     },
284     onSendSubmit: function() {
285         var message = jQuery.trim(jQuery(".xc_input_message").val());
286         message = jQuery('<p>' + message + '</p>').text();
287         jQuery(".xc_input_message").val(message);
288         if (message === "" || jQuery(".xc_input_message").val() === jQuery(".xc_input_message").attr("placeholder"))
289             return false;
290         if (xChatty.config.processingSend)
291             return false;
292         var messageForm = jQuery(this);
293         messageForm.addClass("xc_message_sending");
294         xChatty.config.processingSend = true;
295         var formData = jQuery(".xc_form_reply").serializeArray();
296         formData.push({
297             name: 'data[Message][current_page]',
298             value: encodeURIComponent(encodeURIComponent(document.URL))
299         });
300         formData.push({
301             name: 'data[last_id]',
302             value: xChatty.getMaxId()
303         });
304         formData.push({
305             name: 'data[is_new_page]',
306             value: xChatty.config.isNewPage
307         });
308         xChatty.config.isNewPage = false;
309         jQuery(".xc_input_message").val("");
310
311         var tmpMessage = {};
312         tmpMessage.id = xChatty.getMaxId() + 999;
313         tmpMessage.fullname = xChatty.config.visitor.fullname;
314         tmpMessage.body = message;
315         tmpMessage.createdAt = new Date();
316         xChatty.addMessageToChat(tmpMessage, {
317             confirmed: false
318         });
319         xChatty.scrollBottom(false);
320         xChatty.handleAjaxSendCall(formData, tmpMessage, messageForm);
321         return false;
322     },
323     handleAjaxSendCall: function(formData, tmpMessage, messageForm) {
324       jQuery.ajax({
325           url: xChatty.config.rootPath + "send",
326           data: formData,
327           dataType: "jsonp",
328           jsonpCallback: xChatty.getJsonpCallbackName(),
329           success: function(result) {
330               if (result.success === true) {
331                   jQuery(".xc_notifications_wrapper").slideUp();
332                   jQuery("[data-id=" + tmpMessage.id + "]").remove();
333                   // xChatty.addMessageToChat(result.data);
334                   xChatty.addMessageToChat(result.messages[0]);
335                   for (var k = 0; k < result.messages.length; k++) {
336                       xChatty.addMessageToChat(result.messages[k]);
337                   }
338                   if (result.messages.length > 0)
339                       xChatty.scrollBottom(true);
340                   xChatty.config.processingSend = false;
341                   messageForm.removeClass("xc_message_sending");
342               } else {
343                   jQuery("[data-id=" + tmpMessage.id + "]").css('border', '1px dashed #f00');
344               }
345           },
346           error: function(err) {
347             var error = {
348               'message': 'Service temporarily unavailable. We back as soon as possible!'
349             };
350             xChatty.renderErrors(error, true);
351             xChatty.config.timerSendMessages = setTimeout(function() {
352               xChatty.handleAjaxSendCall(formData, tmpMessage, messageForm);
353             }, 5000);
354           }
355       });
356     },
357     headerClick: function(e) {
358         e.preventDefault();
359         // if (!xChatty.config.signedUp && (e.originalEvent !== undefined) && !jQuery(".xc_chat_toggle_container").is(":visible") && xChatty.config.hasSession !== true) {
360         //     jQuery('<form method="post" action="' + xChatty.config.rootPath + 'discussions/session_redir"><input type="hidden" name="data[referer]" value="' + window.location + '" /></form>').submit();
361         // }
362         jQuery(".xc_notification_badge_number").fadeOut();
363         jQuery(".xc_notification_badge_number").html('');
364         jQuery(".xc_chat_container").removeClass('xc_has_unread_messages');
365         if (!xChatty.config.signedUp) {
366             if (xChatty.config.isOnline) {
367                 jQuery(".xc_signup_wrapper").show();
368                 jQuery(".xc_conversation").hide();
369                 jQuery(".xc_enquiry_wrapper").hide();
370             } else {
371                 jQuery(".xc_enquiry_wrapper").show();
372                 jQuery(".xc_signup_wrapper").hide();
373                 jQuery(".xc_conversation").hide();
374             }
375         } else {
376             jQuery(".xc_enquiry_wrapper").hide();
377             jQuery(".xc_signup_wrapper").hide();
378             jQuery(".xc_conversation").show();
379         }
380         var wasClosed = jQuery(".xc_chat_toggle_container").is(":visible");
381         jQuery(".xc_chat_toggle_container").slideToggle("fast", function() {
382             xChatty.scrollBottom(true);
383             if (!wasClosed) {
384                 jQuery(".xc_chat_container").addClass("xc_box_open");
385                 jQuery(".xc_chat_container").trigger("chatOpen", true);
386             }
387         });
388         if (wasClosed) {
389             jQuery(".xc_chat_container").addClass("xc_chat_closing");
390             jQuery(".xc_chat_container").animate({
391                 marginBottom: -50
392             }, {
393                 duration: 200,
394                 queue: true,
395                 complete: function() {
396                     jQuery(".xc_chat_container").animate({
397                         marginBottom: 0
398                     }, {
399                         duration: 500,
400                         queue: true,
401                         complete: function() {}
402                     });
403                     jQuery(".xc_chat_container").removeClass("xc_box_open");
404                     jQuery(".xc_chat_container").removeClass("xc_chat_closing");
405                     jQuery(".xc_chat_container").trigger("chatOpen", false);
406                 }
407             });
408         } else {
409             jQuery(".xc_input_message").focus();
410         }
411         if (e.originalEvent !== undefined) {
412             xChatty.readMessages();
413         }
414         xChatty.checkStatus(true);
415     },
416     // signUpClick: function(e) {
417     //     e.preventDefault();
418     //     jQuery(".xc_form_signup").submit();
419     // },
420     signUpSubmit: function(e) {
421         e.preventDefault();
422         if (xChatty.config.processingSignUp)
423             return false;
424         var validationErrors = {};
425         var signupForm = jQuery(".xc_form_signup");
426         jQuery('.xc_form_signup input').each(function () {
427           var el = jQuery(this);
428           if ((jQuery.trim(el.val()) === '' || el.val() === el.attr('placeholder')) && el.attr('required') === 'required' ) {
429             validationErrors[el.attr('id')] = ['Please enter the field ' + el.attr('data-label')];
430           }
431         });
432         // if (jQuery.trim(jQuery(".xc_input_fullname").val()) === '' || jQuery(".xc_input_fullname").val() === jQuery(".xc_input_fullname").attr("placeholder")) {
433         //     validationErrors["fullname"] = [xChatty.Lang.ValidationUsernameRequired];
434         // }
435         // if (!xChatty.config.hideEmail && (jQuery.trim(jQuery(".xc_input_email").val()) === '' || jQuery(".xc_input_email").val() === jQuery(".xc_input_email").attr("placeholder"))) {
436         //     validationErrors["email"] = [xChatty.Lang.ValidationEmailRequired];
437         // }
438         // if (validationErrors.hasOwnProperty("fullname") || validationErrors.hasOwnProperty("email")) {
439         //     xChatty.renderNotifications(validationErrors, true);
440         //     return;
441         // }
442         if (Object.keys(validationErrors).length > 0) {
443           xChatty.renderNotifications(validationErrors,true);
444           return;
445         }
446         var now = new Date();
447         var dateStr = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate() + " " + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();
448         jQuery(".xc_input_visitor_time").val(dateStr);
449         var formData = jQuery(".xc_form_signup").serializeArray();
450         formData.push({
451           name: 'chatWebsiteId' ,
452           value: xChatty.config.websiteId
453         });
454         if (xChatty.config.hideEmail) {
455             formData.push({
456                 name: 'data[Discussion][email]',
457                 value: 'not.provided@example.com'
458             });
459         }
460         jQuery.ajax({
461             url: xChatty.config.rootPath + "signup",
462             data: formData,
463             dataType: "jsonp",
464             jsonpCallback: xChatty.getJsonpCallbackName(),
465             success: function(result) {
466                 if (result.success === true) {
467                     jQuery(".xc_notifications_wrapper").slideUp();
468                     xChatty.config.processingSignUp = true;
469                     xChatty.config.visitor.fullname = jQuery(".xc_input_fullname").val();
470                     xChatty.config.visitor.avatar = CryptoJS.MD5(jQuery.trim(jQuery(".xc_input_email").val()).toLowerCase());
471                     xChatty.clearNotifications();
472                     // xChatty.config.signedUp = true;
473                     xChatty.setHeaderText();
474                     xChatty.disableSignUpForm('xc_form_signup',true);
475                     xChatty.checkStatus();
476                     xChatty.handleNoAgentResponse();
477                     // xChatty.readMessages();
478                     // jQuery(".xc_signup_wrapper").hide();
479                     // jQuery(".xc_conversation").show();
480                     // xChatty.scrollBottom(false);
481                 } else {
482                     xChatty.renderNotifications(result.errors, true);
483                 }
484             },
485             error: function(err) {
486               var error = {
487                 'message': 'Service temporarily unavailable. We back as soon as possible!'
488               };
489               xChatty.renderErrors(error, true);
490             },
491             complete: function() {
492                 // xChatty.config.processingSignUp = false;
493             }
494         });
495     },
496     handleNoAgentResponse: function() {
497       xChatty.config.timerSignupResponse = setTimeout(function() {
498         if(xChatty.config.processingSignUp && !xChatty.config.signedUp) {
499           xChatty.config.processingSignUp = false;
500           clearTimeout(xChatty.config.timerCheckStatus);
501           var formData = jQuery(this).serializeArray();
502           formData.push({
503               name: 'data[unserved]',
504               value: true
505           });
506           jQuery.ajax({
507               url: xChatty.config.rootPath + "unserved",
508               data: formData,
509               dataType: "jsonp",
510               jsonpCallback: xChatty.getJsonpCallbackName(),
511               success: function(result) {
512                   if (result.success === true) {
513                     var error = {
514                       'message': 'In this moment all agents are busy. Try again!'
515                     };
516                     xChatty.renderErrors(error, true);
517                     xChatty.setHeaderText();
518                     xChatty.disableSignUpForm('xc_form_signup',false);
519                     // xChatty.config.visitor = {
520                     //     fullname: "",
521                     //     avatar: ""
522                     // };
523                   }
524               }
525           });
526         }
527       }, 80*1000); //Now is static, but we have to compute the total timeout for the chat website (sum of timeout of application)
528     },
529     setHeaderText: function() {
530         if (xChatty.config.signedUp === true)
531             jQuery(".xc_chat_head-title").html(xChatty.Lang.HeaderCurrentlyChatting);
532         else if (xChatty.config.signedUp === false && xChatty.config.processingSignUp === true)
533             jQuery(".xc_chat_head-title").html('Waiting for connection...');
534         else if (xChatty.config.isOnline === true)
535             jQuery(".xc_chat_head-title").html(xChatty.Lang.HeaderOnline);
536         else
537             jQuery(".xc_chat_head-title").html(xChatty.Lang.HeaderOffline);
538     },
539     getHTMLTemplate: function() {
540       jQuery.ajax({
541           url: xChatty.config.rootPath + xChatty.config.websiteId + '/html',
542           dataType: 'jsonp',
543           crossDomain: true,
544           success: function (data) {
545             if (jQuery(".xc_chat_container").length === 0) {
546               for (i in xChatty.Lang) {
547                 data = data.replace(new RegExp("{" + i + "}", "gm"), xChatty.Lang[i]);
548               }
549               jQuery('body').append(data);
550             }
551             if (jQuery("#xc_stylesheet").length === 0) {
552                 var xcCss = document.createElement('link');
553                 xcCss.setAttribute('rel', 'stylesheet');
554                 xcCss.type = 'text/css';
555                 xcCss.id = 'xc_stylesheet';
556                 xcCss.href = xChatty.config.rootPath + xChatty.config.websiteId + "/styles";
557                 document.body.appendChild(xcCss);
558             }
559             if(xChatty.config.downloadTranscript) {
560               jQuery(".xc_download_transcript_container").show();
561             } else {
562               jQuery(".xc_download_transcript_container").hide();
563             }
564             xChatty.checkStatus();
565           }
566         });
567     },
568     checkStatus: function(async) {
569         // var chatHtml = '<div class="xc_chat_container" style="display: none;"><div class="xc_chat_head '+xChatty.config.headerShape+'"><i class="xc_header_icon"><span class="xc_notification_badge"><span class="xc_notification_badge_number"></span></span></i><span class="xc_chat_head-title">{HeaderText}</span></div><div class="xc_chat_toggle_container"><div class="xc_sub-head-spacer"></div><div class="xc_notifications_wrapper"><!--<i class="xc_btn_notifications_close">&times;</i>--><ul class="xc_errorlist"></ul></div><div class="xc_enquiry_wrapper"><form class="xc_form_enquiry" accept-charset="UTF-8"><p>{OfflineMessage}</p><input maxlength="45" type="text" name="data[Enquiry][fullname]" placeholder="{UsernamePlaceholder}" class="xc_input_enquiry_fullname" /><input maxlength="85" type="text" name="data[Enquiry][email]" placeholder="{EmailPlaceholder}" class="xc_input_enquiry_email" /><textarea maxlength="1500" placeholder="{EnquiryMessagePlaceholder}" name="data[Enquiry][message]" class="xc_input_enquiry_message"></textarea><a href="#" class="xc_btn_enquiry xc_btn_style">{EnquiryButtonText}</a></form></div><div class="xc_signup_wrapper"><form class="xc_form_signup" accept-charset="UTF-8"><p>{OnlineMessage}</p><input maxlength="45" type="text" name="data[Discussion][fullname]" placeholder="{UsernamePlaceholder}" class="xc_input_fullname" /><input maxlength="85" type="text" name="data[Discussion][email]" placeholder="{EmailPlaceholder}" class="xc_input_email" /><input type="hidden" class="xc_input_visitor_time" name="data[Discussion][visitor_time]" /><a href="#" class="xc_btn_signup xc_btn_style">{StartChatButtonText}</a></form></div><div class="xc_conversation"><div class="xc_conversation_container"><p class="xc_message_intro" data-id="-10">{FirstMessageText}</p></div><div class="xc_composing_container"></div><form class="xc_form_reply" accept-charset="UTF-8"><div class="xc_exit_chat_container"><div class="xc_download_transcript_container" style="display:none;"><a href="'+xChatty.config.rootPath + 'transcript" class="xc_download_transcript">{DownloadTranscript}</a></div><a href="#" class="xc_btn_exit_chat">{ExitChatButtonText}</a><div class="xc_exit_chat_confirmation_wrapper" style="display: none;"><span>{ExitChatQuestionText} </span><a href="#" class="xc_btn_exit_chat_confirm">{ExitChatButtonConfirmText}</a><span> | </span><a href="#" class="xc_btn_exit_chat_cancel">{ExitChatButtonCancelText}</a></div></div><textarea maxlength="750" placeholder="{MessagePlaceholderText}" name="data[Message][message]" class="xc_input_message"></textarea><a href="#" class="xc_btn_send xc_btn_style">{MessageSendButtonText}</a></form></div><div class="xc_footer"><div class="xc_powered"><a>Powered by Xenialab | Trademark xCALLY</a></div></div></div></div>';
570         // if (jQuery(".xc_chat_container").length === 0) {
571         //     for (i in xChatty.Lang) {
572         //         chatHtml = chatHtml.replace(new RegExp("{" + i + "}", "gm"), xChatty.Lang[i]);
573         //     }
574         //     jQuery('body').append(chatHtml);
575         //     if (xChatty.config.hideEmail) {
576         //         jQuery(".xc_chat_container .xc_input_email").hide();
577         //     }
578         // }
579         // if (jQuery("#xc_stylesheet").length === 0) {
580         //     var xcCss = document.createElement('link');
581         //     xcCss.setAttribute('rel', 'stylesheet');
582         //     xcCss.type = 'text/css';
583         //     xcCss.id = 'xc_stylesheet';
584         //     xcCss.href = xChatty.config.rootPath + "/" + xChatty.config.websiteId + "/styles";
585         //     document.body.appendChild(xcCss);
586         // }
587         // if(xChatty.config.downloadTranscript) {
588         //   jQuery(".xc_download_transcript_container").show();
589         // } else {
590         //   jQuery(".xc_download_transcript_container").hide();
591         // }
592         clearTimeout(xChatty.config.timerCheckStatus);
593         var formData = [];
594         if (xChatty.config.isInitialStatusCheck)
595             formData.push({
596                 name: 'data[referer]',
597                 value: encodeURIComponent(encodeURIComponent(document.referrer))
598             });
599         else
600             formData.push({
601                 name: 'data[open_state]',
602                 value: (jQuery(".xc_chat_toggle_container").is(":visible") && !jQuery(".xc_chat_container").hasClass("xc_chat_closing"))
603             });
604         jQuery.ajax({
605             url: xChatty.config.rootPath + "status",
606             dataType: "jsonp",
607             data: formData,
608             async: async,
609             jsonpCallback: xChatty.getJsonpCallbackName(),
610             success: function(result) {
611                 jQuery(".xc_notifications_wrapper").slideUp();
612                 var wasSignedUp = xChatty.config.signedUp;
613                 if (result.success) {
614                     xChatty.config.visitor.fullname = result.fullname;
615                     xChatty.config.visitor.avatar = result.avatar;
616                     xChatty.config.signedUp = result.signed_up;
617                     xChatty.config.isOnline = result.online;
618                     xChatty.config.hasSessionSaf = result.has_session_saf;
619                 }
620                 if (result.success && result.signed_up === false && xChatty.config.signedUp) {
621                     xChatty.resetDefaultState();
622                 }
623                 if (xChatty.config.isOnline) {
624                     jQuery(".xc_chat_container").addClass("xc_state_online").removeClass("xc_state_offline").fadeIn();
625                 } else {
626                     jQuery(".xc_chat_container").removeClass("xc_state_online").addClass("xc_state_offline");
627                 }
628                 if (!xChatty.config.signedUp) {
629                     if (xChatty.config.isOnline) {
630                         jQuery(".xc_signup_wrapper").show();
631                         jQuery(".xc_conversation").hide();
632                         jQuery(".xc_enquiry_wrapper").hide();
633                     } else {
634                         jQuery(".xc_enquiry_wrapper").show();
635                         jQuery(".xc_signup_wrapper").hide();
636                         jQuery(".xc_conversation").hide();
637                     }
638                 } else {
639                     if (xChatty.config.isOnline) {
640                         xChatty.clearNotifications();
641                     } else {
642                         var notifications = {
643                             offline: [xChatty.Lang.OperatorOfflineMessage]
644                         };
645                         xChatty.renderNotifications(notifications, true);
646                     }
647                 }
648                 var wasInitialStatusCheck = xChatty.config.isInitialStatusCheck;
649                 if (xChatty.config.isInitialStatusCheck === true) {
650                     xChatty.config.isInitialStatusCheck = false;
651                     xChatty.config.muteNotificationSoundOnce = true;
652                     xChatty.setHeaderText();
653                     xChatty.init();
654                     if (result.open_state === true) {
655                         xChatty.config.restoreOpenState = true;
656                     }
657                 }
658                 if (result.success && result.signed_up === true && wasSignedUp === false && wasInitialStatusCheck === false) {
659                     jQuery(".xc_enquiry_wrapper").hide();
660                     jQuery(".xc_signup_wrapper").hide();
661                     jQuery(".xc_conversation").show();
662                     xChatty.readMessages();
663                 }
664
665                 if(!wasSignedUp && result.signed_up === true && xChatty.config.processingSignUp) {
666                   xChatty.config.processingSignUp = false;
667                   xChatty.disableSignUpForm('xc_form_signup',false);
668                   xChatty.setHeaderText();
669                 }
670
671                 // if(wasSignedUp && result.signed_up === true) {
672                 //   xChatty.readMessages(false);
673                 //   // var duration = xChatty.calculateTimeOutDuration();
674                 //   // xChatty.config.timerReadMessages = setTimeout(function() {
675                 //   //   xChatty.readMessages(false);
676                 //   // }, duration);
677                 // }
678
679             },
680             error: function(err) {
681               var error = {
682                 'message': 'Service temporarily unavailable. We back as soon as possible!'
683               };
684               xChatty.renderErrors(error, true);
685             },
686             complete: function() {
687                 xChatty.setHeaderText();
688                 var duration = xChatty.calculateStatusTimeOutDuration();
689                 xChatty.config.timerCheckStatus = setTimeout(function() {
690                     xChatty.checkStatus(true);
691                 }, duration);
692             }
693         });
694     },
695     getJsonpCallbackName: function() {
696         var callback = 'xChatty_';
697         var cStr = parseInt(new Date().getTime() / 1000).toString().substring(5) + (Math.random() + ' ').substring(5, 10);
698         var mult = parseInt(cStr.charAt(Math.floor(Math.random() * cStr.length)));
699         mult = (mult === 0 || mult === 1) ? mult + 2 : mult;
700         var cStr = mult.toString() + cStr.toString() + (cStr * mult).toString();
701         callback += cStr.toString().split("").reverse().join("");
702         return callback;
703     },
704     timerNotifications: null,
705     renderNotifications: function(errorMessages, isError) {
706         if (isError) {
707             jQuery(".xc_notifications_wrapper").removeClass("xc_notification_success");
708             jQuery(".xc_notifications_wrapper").addClass("xc_notification_error");
709         } else {
710             jQuery(".xc_notifications_wrapper").addClass("xc_notification_success");
711             jQuery(".xc_notifications_wrapper").removeClass("xc_notification_error");
712         }
713         jQuery(".xc_notifications_wrapper ul.xc_errorlist").html("");
714         for (k in errorMessages) {
715             for (var l = 0; l < errorMessages[k].length; l++)
716                 jQuery(".xc_notifications_wrapper ul.xc_errorlist").append(jQuery("<li>" + errorMessages[k][l] + "</li>"));
717         }
718         jQuery(".xc_notifications_wrapper").slideDown();
719         clearTimeout(xChatty.timerNotifications);
720         xChatty.timerNotifications = setTimeout(function() {
721             jQuery(".xc_notifications_wrapper").slideUp();
722         }, 10000);
723     },
724     renderErrors: function(error, isError) {
725         if (isError) {
726             jQuery(".xc_notifications_wrapper").removeClass("xc_notification_success");
727             jQuery(".xc_notifications_wrapper").addClass("xc_notification_error");
728         } else {
729             jQuery(".xc_notifications_wrapper").addClass("xc_notification_success");
730             jQuery(".xc_notifications_wrapper").removeClass("xc_notification_error");
731         }
732         jQuery(".xc_notifications_wrapper ul.xc_errorlist").html("");
733         jQuery(".xc_notifications_wrapper ul.xc_errorlist").append(jQuery("<li>" + error.message + "</li>"));
734         jQuery(".xc_notifications_wrapper").slideDown();
735         // clearTimeout(xChatty.timerNotifications);
736         // xChatty.timerNotifications = setTimeout(function() {
737         //     jQuery(".xc_notifications_wrapper").slideUp();
738         // }, 10000);
739     },
740     clearNotifications: function() {
741         jQuery(".xc_notifications_wrapper").hide();
742         jQuery(".xc_notifications_wrapper ul.xc_errorlist").html("");
743     },
744     btnNotificationsCloseClick: function(e) {
745         e.preventDefault();
746         jQuery(".xc_notifications_wrapper").slideUp();
747     },
748     messageKeyUp: function(e) {
749         if (e.shiftKey)
750             return;
751         if (e.keyCode === 13 && !jQuery(this).hasClass("xc_input_enquiry_message")) {
752             jQuery(this).parents('form').submit();
753         }
754     },
755     messageKeyDownWait: false,
756     messageKeyDown: function(e) {
757         if (xChatty.messageKeyDownWait === true) {
758             return;
759         } else {
760             xChatty.messageKeyDownWait = true;
761             setTimeout(function() {
762                 xChatty.messageKeyDownWait = false;
763             }, 1000);
764         }
765         // jQuery.ajax({
766         //     url: xChatty.config.rootPath + "discussions/composing",
767         //     dataType: "jsonp",
768         //     jsonpCallback: xChatty.getJsonpCallbackName(),
769         //     success: function(result) {},
770         //     complete: function() {}
771         // });
772     },
773     sendClick: function(e) {
774         e.preventDefault();
775         jQuery('form.xc_form_reply').submit();
776     },
777     addMessageToChat: function(message, options) {
778         var isConfirmed = "";
779         var fullname = "";
780         if ((typeof options !== 'undefined' && options.confirmed === false) && xChatty.config.visitor.fullname === message.fullname)
781             isConfirmed = " xc_submission_pending";
782         else if (typeof options === 'undefined' && xChatty.config.visitor.fullname === message.fullname)
783             isConfirmed = " xc_submission_confirmed";
784         if (jQuery(".xc_conversation_container [data-id=" + message.id + "]").length === 0) {
785           if (message.User) {
786             fullname = message.User.fullname;
787           }
788           if (message.ChatVisitor) {
789             fullname = message.ChatVisitor.fullname;
790           }
791
792             jQuery(".xc_conversation_container .xc_message_intro").remove();
793             var mTime = ('0' + new Date(message.createdAt).getHours()).slice(-2) + ":" + ('0' + new Date(message.createdAt).getMinutes()).slice(-2);
794             var newMessage = jQuery("<div style=\"clear: both\" class=\"xc_chatrow" + "\" data-id=\"" + message.id + "\"><div class=\"xc_time" + isConfirmed + "\">" + mTime + "</div><p><i style=\"background-image: url(http://www.gravatar.com/avatar/" + message.email + "?s=40&d=identicon);\" class=\"xc_avatar\"></i><span class=\"xc_fullname\">" + fullname + "</span> " + xChatty.prepareMessageText(message.body) + "</p></div>");
795             jQuery(".xc_conversation_container").append(newMessage);
796             jQuery('.xc_conversation_container').children().sort(function(a, b) {
797                 var aF = parseInt(jQuery(a).attr("data-id"));
798                 var bF = parseInt(jQuery(b).attr("data-id"));
799                 if (aF > bF)
800                     return 1;
801                 else if (aF < bF)
802                     return -1;
803                 else
804                     return 0;
805             }).appendTo('.xc_conversation_container');
806         }
807     },
808     prepareMessageText: function(text) {
809         var smilies = [
810           {
811               s: [' :-D ', ' :D '],
812               r: "biggrin"
813           },
814           {
815               s: [' :-S ', ' :S '],
816               r: "confused"
817           },
818           // {
819           //     s: [],
820           //     r: "cool"
821           // },
822           {
823               s: [' ;-( ', ' ;( '],
824               r: "cry"
825           },
826           {
827               s: [' OO '],
828               r: "eek"
829           },
830           // {
831           //     s: [],
832           //     r: "evil"
833           // },
834           {
835               s: [' <3 '],
836               r: "like"
837           },
838           {
839               s: [' ^^ '],
840               r: "lol"
841           },
842           // {
843           //     s: [],
844           //     r: "mad"
845           // },
846           // {
847           //     s: [],
848           //     r: "mrgreen"
849           // },
850           {
851               s: [' :-| ', ' :| '],
852               r: "neutral"
853           },
854           // {
855           //     s: [],
856           //     r: "question"
857           // },
858           {
859               s: [' :-P ', ' :P '],
860               r: "razz"
861           },
862           // {
863           //     s: [],
864           //     r: "redface"
865           // },
866           // {
867           //     s: [],
868           //     r: "rolleyes"
869           // },
870           {
871               s: [' :-( ', ' :( '],
872               r: "sad"
873           },
874           {
875               s: [' :-) ', ' :) '],
876               r: "smile"
877           },
878           {
879               s: [' :-O ', ' :O '],
880               r: "surprised"
881           },
882           // {
883           //     s: [],
884           //     r: "thumbdown"
885           // },
886           // {
887           //     s: [],
888           //     r: "thumbup"
889           // },
890           // {
891           //     s: [],
892           //     r: "twisted"
893           // },
894           {
895               s: [' ;-) ', ' ;) '],
896               r: "wink"
897           }
898         ];
899         text = " " + text + " ";
900         for (var i = 0; i < smilies.length; i++) {
901             for (var j = 0; j < smilies[i].s.length; j++) {
902                 var smilie = ' <i style="background-image: url(' + ('{XC_REP}' + '?resource=smilies/' + smilies[i].r + '.png') + ');" class="xc_smilie" >' + jQuery.trim(smilies[i].s[j].toString()) + '</i> ';
903                 var regex = new RegExp(xChatty.escapeRegExp(smilies[i].s[j]), 'g');
904                 text = text.replace(regex, smilie);
905             }
906         }
907         var wAddress = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
908         var eAddress = /\w+@[a-zA-Z_]+?(?:\.[a-zA-Z]{2,6})+/gim;
909         text = text.replace(wAddress, '<a href="$&">$&</a>').replace(eAddress, '<a href="mailto:$&">$&</a>');
910         var tmp = jQuery("<div>" + text + "<div>");
911         tmp.find("a").each(function() {
912             if (jQuery(this).attr("href").indexOf(document.domain) === -1) {
913                 jQuery(this).attr("target", "_blank").addClass("xc_link_external");
914             } else {
915                 jQuery(this).addClass("xc_link_internal");
916             }
917         });
918         var regex = new RegExp(xChatty.escapeRegExp("{XC_REP}"), 'g');
919         text = jQuery(tmp).html().replace(regex, xChatty.config.assetBase);
920         return jQuery.trim(text).replace(/\n/g, '<br />');
921     },
922     escapeRegExp: function(str) {
923         return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
924     },
925     loadMore: function() {
926         xChatty.readMessages(true);
927     },
928     readMessages: function(loadMore) {
929         // if (!loadMore)
930         //     clearTimeout(xChatty.config.timerReadMessages);
931         if (!xChatty.config.signedUp) {
932             return;
933         }
934         if (xChatty.config.isNewPage) {}
935         var requestData = [];
936         if (loadMore === true) {
937             requestData.push({
938                 name: 'data[first_id]',
939                 value: xChatty.getMinId()
940             });
941             requestData.push({
942                 name: 'data[load_more]',
943                 value: true
944             });
945         } else {
946             requestData.push({
947                 name: 'data[last_id]',
948                 value: xChatty.getMaxId()
949             });
950             requestData.push({
951                 name: 'data[is_new_page]',
952                 value: xChatty.config.isNewPage
953             });
954         }
955         jQuery.ajax({
956             data: requestData,
957             url: xChatty.config.rootPath + "read",
958             dataType: "jsonp",
959             jsonpCallback: xChatty.getJsonpCallbackName(),
960             success: function(result) {
961                 if (result.success === true) {
962                     jQuery(".xc_notifications_wrapper").slideUp();
963                     var scrollToElem = jQuery("[data-id=" + xChatty.getMinId() + "]");
964                     for (var i = 0; i < result.messages.length; i++) {
965                         xChatty.addMessageToChat(result.messages[i]);
966                     }
967                     if (loadMore)
968                         jQuery(".xc_btn_load_more").remove();
969                     // if (result.messages.length >= 20 && jQuery(".xc_btn_load_more").length === 0) {
970                     //     jQuery(".xc_conversation_container").prepend(jQuery("<a href=\"#\" data-id=\"-10\" class=\"xc_btn_load_more xc_btn_style\">Load More</a>"));
971                     //     jQuery(".xc_btn_load_more").on("click", xChatty.loadMore);
972                     // }
973                     if (result.composing === true && result.messages.length === 0) {
974                         jQuery(".xc_composing_container").html(xChatty.Lang.OperatorComposing.replace("{fullname}", result.composing_fullname)).slideDown();
975                     } else {
976                         jQuery(".xc_composing_container").slideUp();
977                     }
978                     if (result.messages.length > 0) {
979                         jQuery(".xc_composing_container").slideUp();
980                     }
981                     if (!loadMore && result.messages.length > 0) {
982                         xChatty.playNotificationSound();
983                         xChatty.scrollBottom(true);
984                         if (!xChatty.config.isNewPage && !jQuery(".xc_conversation_container").is(":visible")) {
985                             jQuery(".xc_chat_container").animate({
986                                 opacity: 1
987                             }, {
988                                 duration: 200,
989                                 queue: false
990                             });
991                             jQuery(".xc_chat_container").animate({
992                                 'margin-bottom': -7
993                             }, 100, function() {
994                                 jQuery(this).animate({
995                                     'margin-bottom': 0
996                                 }, 100, function() {
997                                     jQuery(this).animate({
998                                         'margin-bottom': -5
999                                     }, 100, function() {
1000                                         jQuery(this).animate({
1001                                             'margin-bottom': 0
1002                                         }, 200, function() {});
1003                                     });
1004                                 });
1005                             });
1006                             jQuery(".xc_notification_badge_number").fadeIn();
1007                             var newVal = (isNaN(parseInt(jQuery(".xc_notification_badge_number").html())) ? 0 : parseInt(jQuery(".xc_notification_badge_number").html())) + result.messages.length;
1008                             jQuery(".xc_notification_badge_number").html(newVal);
1009                             jQuery(".xc_chat_container").addClass('xc_has_unread_messages');
1010                         }
1011                     } else if (loadMore) {
1012                         xChatty.scrollToElement(scrollToElem);
1013                     }
1014                     if (result.messages.length === 0)
1015                         xChatty.config.decayHistory++;
1016                     else
1017                         xChatty.config.decayHistory = 0;
1018                     // var duration = xChatty.calculateTimeOutDuration();
1019                     // if (!loadMore) {
1020                     //     xChatty.config.timerReadMessages = setTimeout(function() {
1021                     //         xChatty.readMessages(false);
1022                     //     }, duration);
1023                     // }
1024                 } else if (result.success === false) {
1025                     xChatty.checkStatus(true);
1026                 } else {}
1027                 xChatty.config.isNewPage = false;
1028             },
1029             error: function(err) {
1030               var error = {
1031                 'message': 'Service temporarily unavailable. We back as soon as possible!'
1032               };
1033               xChatty.renderErrors(error, true);
1034             },
1035             complete: function() {
1036               var duration = xChatty.calculateTimeOutDuration();
1037               if (!loadMore) {
1038                   xChatty.config.timerReadMessages = setTimeout(function() {
1039                       xChatty.readMessages(false);
1040                   }, duration);
1041               }
1042             }
1043         });
1044     },
1045     playNotificationSound: function() {
1046         if (xChatty.config.isNewPage || (xChatty.config.windowFocused && jQuery(".xc_conversation_container").is(":visible")) || xChatty.config.muteNotificationSoundOnce) {
1047             xChatty.config.muteNotificationSoundOnce = false;
1048             return;
1049         }
1050         jQuery("#xc_auto_tag").remove();
1051         var soundWav = xChatty.config.assetBase + "?resource=notification/xc_blubb.wav";
1052         var soundMp3 = xChatty.config.assetBase + "?resource=notification/xc_blubb.mp3";
1053         var soundOgg = xChatty.config.assetBase + "?resource=notification/xc_blubb.ogg";
1054         jQuery('<audio id="xc_auto_tag" autoplay="autoplay">').append(jQuery('<source>').attr('src', soundWav)).append(jQuery('<source>').attr('src', soundMp3)).append(jQuery('<source>').attr('src', soundOgg)).appendTo('body');
1055     },
1056     calculateTimeOutDuration: function() {
1057         if (!jQuery(".xc_conversation_container").is(":visible"))
1058             return 10000;
1059         var calcTimeOut = (parseFloat(xChatty.config.decayHistory / 10) * 1000);
1060         if (calcTimeOut > 10000)
1061             return 10000;
1062         if (calcTimeOut > xChatty.config.defaultTimeout) {
1063             return calcTimeOut;
1064         }
1065         return xChatty.config.defaultTimeout;
1066     },
1067     calculateStatusTimeOutDuration: function() {
1068         if (jQuery(".xc_signup_wrapper").is(":visible") && xChatty.config.processingSignUp)
1069           return xChatty.config.defaultTimeout;
1070         return 15000;
1071     },
1072     getMaxId: function() {
1073         if (jQuery(".xc_chatrow").length === 0)
1074             return 0;
1075         var numbers = jQuery(".xc_chatrow").map(function() {
1076             return parseFloat(this.getAttribute('data-id')) || -Infinity;
1077         }).toArray();
1078         return Math.max.apply(Math, numbers);
1079     },
1080     getMinId: function() {
1081         if (jQuery(".xc_chatrow").length === 0)
1082             return 0;
1083         var numbers = jQuery(".xc_chatrow").map(function() {
1084             return parseFloat(this.getAttribute('data-id')) || -Infinity;
1085         }).toArray();
1086         return Math.min.apply(Math, numbers);
1087     },
1088     scrollBottom: function(animate) {
1089         if (!animate)
1090             jQuery(".xc_conversation_container").scrollTop(jQuery(".xc_conversation_container")[0].scrollHeight);
1091         else
1092             jQuery(".xc_conversation_container").animate({
1093                 scrollTop: jQuery(".xc_conversation_container")[0].scrollHeight
1094             }, 800);
1095     },
1096     scrollToElement: function(elem) {
1097         var offset = jQuery(elem).offset().top + (jQuery(elem).height() * 2) - jQuery(".xc_conversation_container").height();
1098         jQuery(".xc_conversation_container").animate({
1099             scrollTop: offset
1100         }, 800);
1101     },
1102     disableSignUpForm: function(form, enable) {
1103       jQuery("." + form + " :input").attr("disabled", enable);
1104       if(enable) {
1105         jQuery(document).on("click", "." + form + " .xc_btn_signup", function(e) { e.preventDefault();});
1106       } else {
1107         // jQuery(document).on("click", "." + form + " .xc_btn_signup", xChatty.signUpClick);
1108       }
1109     },
1110     browserTest: function(test) {
1111         var isOpera = !!(window.opera && window.opera.version);
1112         var isFirefox = xChatty.testStyle('MozBoxSizing');
1113         var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
1114         var isChrome = !isSafari && xChatty.testStyle('WebkitTransform');
1115         var isIE = false || xChatty.testStyle('msTransform');
1116         var browserValue = {
1117             'Opera': isOpera,
1118             'Firefox': isFirefox,
1119             'Safari': isSafari,
1120             'Chrome': isChrome,
1121             'IE': isIE
1122         };
1123         return browserValue[test];
1124     },
1125     testStyle: function(property) {
1126         return property in document.documentElement.style;
1127     },
1128     checkIfMobileDevice: function() {
1129         var n = (navigator.userAgent || navigator.vendor || window.opera);
1130         return /android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge|maemo|midp|mmp|netfront|opera m(ob|in)i|palm(os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows(ce|phone)|xda|xiino/i.test(n) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(n.substr(0, 4));
1131     }
1132 };
1133
1134 function xcLoadJS(xcCallback) {
1135     var script = document.createElement("script")
1136     script.type = "text/javascript";
1137     if (script.readyState) {
1138         script.onreadystatechange = function() {
1139             if (script.readyState == "loaded" || script.readyState == "complete") {
1140                 script.onreadystatechange = null;
1141                 xcCallback();
1142             }
1143         };
1144     } else {
1145         script.onload = function() {
1146             xcCallback();
1147         };
1148     }
1149     script.src = "http://code.jquery.com/jquery-2.1.4.min.js";
1150     var ph = document.getElementsByTagName('script')[0];
1151     ph.parentNode.insertBefore(script, ph);
1152 }
1153
1154 if (true) {
1155     if (typeof jQuery == 'undefined') {
1156         xcLoadJS(function() {
1157             (function($) {
1158                 jQuery(document).ready(function() {
1159                     xChatty.getHTMLTemplate();
1160                 });
1161             })(jQuery);
1162         });
1163     } else {
1164         (function($) {
1165             jQuery(document).ready(function() {
1166                 xChatty.getHTMLTemplate();
1167             });
1168         })(jQuery);
1169     }
1170 }
1171
1172 /**
1173  * The code below this is not covered by the CodeCanyon Regular License.
1174  * Feel free to re-use the code below as per your requirements whilst following
1175  * the respective licensing terms.
1176  */
1177 /*
1178 CryptoJS v3.1.2
1179 code.google.com/p/crypto-js
1180 (c) 2009-2013 by Jeff Mott. All rights reserved.
1181 code.google.com/p/crypto-js/wiki/License
1182 */
1183 var CryptoJS = CryptoJS || function(s, p) {
1184     var m = {},
1185         l = m.lib = {},
1186         n = function() {},
1187         r = l.Base = {
1188             extend: function(b) {
1189                 n.prototype = this;
1190                 var h = new n;
1191                 b && h.mixIn(b);
1192                 h.hasOwnProperty("init") || (h.init = function() {
1193                     h.$super.init.apply(this, arguments)
1194                 });
1195                 h.init.prototype = h;
1196                 h.$super = this;
1197                 return h
1198             },
1199             create: function() {
1200                 var b = this.extend();
1201                 b.init.apply(b, arguments);
1202                 return b
1203             },
1204             init: function() {},
1205             mixIn: function(b) {
1206                 for (var h in b) b.hasOwnProperty(h) && (this[h] = b[h]);
1207                 b.hasOwnProperty("toString") && (this.toString = b.toString)
1208             },
1209             clone: function() {
1210                 return this.init.prototype.extend(this)
1211             }
1212         },
1213         q = l.WordArray = r.extend({
1214             init: function(b, h) {
1215                 b = this.words = b || [];
1216                 this.sigBytes = h != p ? h : 4 * b.length
1217             },
1218             toString: function(b) {
1219                 return (b || t).stringify(this)
1220             },
1221             concat: function(b) {
1222                 var h = this.words,
1223                     a = b.words,
1224                     j = this.sigBytes;
1225                 b = b.sigBytes;
1226                 this.clamp();
1227                 if (j % 4)
1228                     for (var g = 0; g < b; g++) h[j + g >>> 2] |= (a[g >>> 2] >>> 24 - 8 * (g % 4) & 255) << 24 - 8 * ((j + g) % 4);
1229                 else if (65535 < a.length)
1230                     for (g = 0; g < b; g += 4) h[j + g >>> 2] = a[g >>> 2];
1231                 else h.push.apply(h, a);
1232                 this.sigBytes += b;
1233                 return this
1234             },
1235             clamp: function() {
1236                 var b = this.words,
1237                     h = this.sigBytes;
1238                 b[h >>> 2] &= 4294967295 << 32 - 8 * (h % 4);
1239                 b.length = s.ceil(h / 4)
1240             },
1241             clone: function() {
1242                 var b = r.clone.call(this);
1243                 b.words = this.words.slice(0);
1244                 return b
1245             },
1246             random: function(b) {
1247                 for (var h = [], a = 0; a < b; a += 4) h.push(4294967296 * s.random() | 0);
1248                 return new q.init(h, b)
1249             }
1250         }),
1251         v = m.enc = {},
1252         t = v.Hex = {
1253             stringify: function(b) {
1254                 var a = b.words;
1255                 b = b.sigBytes;
1256                 for (var g = [], j = 0; j < b; j++) {
1257                     var k = a[j >>> 2] >>> 24 - 8 * (j % 4) & 255;
1258                     g.push((k >>> 4).toString(16));
1259                     g.push((k & 15).toString(16))
1260                 }
1261                 return g.join("")
1262             },
1263             parse: function(b) {
1264                 for (var a = b.length, g = [], j = 0; j < a; j += 2) g[j >>> 3] |= parseInt(b.substr(j, 2), 16) << 24 - 4 * (j % 8);
1265                 return new q.init(g, a / 2)
1266             }
1267         },
1268         a = v.Latin1 = {
1269             stringify: function(b) {
1270                 var a = b.words;
1271                 b = b.sigBytes;
1272                 for (var g = [], j = 0; j < b; j++) g.push(String.fromCharCode(a[j >>> 2] >>> 24 - 8 * (j % 4) & 255));
1273                 return g.join("")
1274             },
1275             parse: function(b) {
1276                 for (var a = b.length, g = [], j = 0; j < a; j++) g[j >>> 2] |= (b.charCodeAt(j) & 255) << 24 - 8 * (j % 4);
1277                 return new q.init(g, a)
1278             }
1279         },
1280         u = v.Utf8 = {
1281             stringify: function(b) {
1282                 try {
1283                     return decodeURIComponent(escape(a.stringify(b)))
1284                 } catch (g) {
1285                     throw Error("Malformed UTF-8 data");
1286                 }
1287             },
1288             parse: function(b) {
1289                 return a.parse(unescape(encodeURIComponent(b)))
1290             }
1291         },
1292         g = l.BufferedBlockAlgorithm = r.extend({
1293             reset: function() {
1294                 this._data = new q.init;
1295                 this._nDataBytes = 0
1296             },
1297             _append: function(b) {
1298                 "string" == typeof b && (b = u.parse(b));
1299                 this._data.concat(b);
1300                 this._nDataBytes += b.sigBytes
1301             },
1302             _process: function(b) {
1303                 var a = this._data,
1304                     g = a.words,
1305                     j = a.sigBytes,
1306                     k = this.blockSize,
1307                     m = j / (4 * k),
1308                     m = b ? s.ceil(m) : s.max((m | 0) - this._minBufferSize, 0);
1309                 b = m * k;
1310                 j = s.min(4 * b, j);
1311                 if (b) {
1312                     for (var l = 0; l < b; l += k) this._doProcessBlock(g, l);
1313                     l = g.splice(0, b);
1314                     a.sigBytes -= j
1315                 }
1316                 return new q.init(l, j)
1317             },
1318             clone: function() {
1319                 var b = r.clone.call(this);
1320                 b._data = this._data.clone();
1321                 return b
1322             },
1323             _minBufferSize: 0
1324         });
1325     l.Hasher = g.extend({
1326         cfg: r.extend(),
1327         init: function(b) {
1328             this.cfg = this.cfg.extend(b);
1329             this.reset()
1330         },
1331         reset: function() {
1332             g.reset.call(this);
1333             this._doReset()
1334         },
1335         update: function(b) {
1336             this._append(b);
1337             this._process();
1338             return this
1339         },
1340         finalize: function(b) {
1341             b && this._append(b);
1342             return this._doFinalize()
1343         },
1344         blockSize: 16,
1345         _createHelper: function(b) {
1346             return function(a, g) {
1347                 return (new b.init(g)).finalize(a)
1348             }
1349         },
1350         _createHmacHelper: function(b) {
1351             return function(a, g) {
1352                 return (new k.HMAC.init(b, g)).finalize(a)
1353             }
1354         }
1355     });
1356     var k = m.algo = {};
1357     return m
1358 }(Math);
1359 (function(s) {
1360     function p(a, k, b, h, l, j, m) {
1361         a = a + (k & b | ~k & h) + l + m;
1362         return (a << j | a >>> 32 - j) + k
1363     }
1364
1365     function m(a, k, b, h, l, j, m) {
1366         a = a + (k & h | b & ~h) + l + m;
1367         return (a << j | a >>> 32 - j) + k
1368     }
1369
1370     function l(a, k, b, h, l, j, m) {
1371         a = a + (k ^ b ^ h) + l + m;
1372         return (a << j | a >>> 32 - j) + k
1373     }
1374
1375     function n(a, k, b, h, l, j, m) {
1376         a = a + (b ^ (k | ~h)) + l + m;
1377         return (a << j | a >>> 32 - j) + k
1378     }
1379     for (var r = CryptoJS, q = r.lib, v = q.WordArray, t = q.Hasher, q = r.algo, a = [], u = 0; 64 > u; u++) a[u] = 4294967296 * s.abs(s.sin(u + 1)) | 0;
1380     q = q.MD5 = t.extend({
1381         _doReset: function() {
1382             this._hash = new v.init([1422584193, 4023233417, 2562383102, 271423878])
1383         },
1384         _doProcessBlock: function(g, k) {
1385             for (var b = 0; 16 > b; b++) {
1386                 var h = k + b,
1387                     w = g[h];
1388                 g[h] = (w << 8 | w >>> 24) & 16711935 | (w << 24 | w >>> 8) & 4278255360
1389             }
1390             var b = this._hash.words,
1391                 h = g[k + 0],
1392                 w = g[k + 1],
1393                 j = g[k + 2],
1394                 q = g[k + 3],
1395                 r = g[k + 4],
1396                 s = g[k + 5],
1397                 t = g[k + 6],
1398                 u = g[k + 7],
1399                 v = g[k + 8],
1400                 x = g[k + 9],
1401                 y = g[k + 10],
1402                 z = g[k + 11],
1403                 A = g[k + 12],
1404                 B = g[k + 13],
1405                 C = g[k + 14],
1406                 D = g[k + 15],
1407                 c = b[0],
1408                 d = b[1],
1409                 e = b[2],
1410                 f = b[3],
1411                 c = p(c, d, e, f, h, 7, a[0]),
1412                 f = p(f, c, d, e, w, 12, a[1]),
1413                 e = p(e, f, c, d, j, 17, a[2]),
1414                 d = p(d, e, f, c, q, 22, a[3]),
1415                 c = p(c, d, e, f, r, 7, a[4]),
1416                 f = p(f, c, d, e, s, 12, a[5]),
1417                 e = p(e, f, c, d, t, 17, a[6]),
1418                 d = p(d, e, f, c, u, 22, a[7]),
1419                 c = p(c, d, e, f, v, 7, a[8]),
1420                 f = p(f, c, d, e, x, 12, a[9]),
1421                 e = p(e, f, c, d, y, 17, a[10]),
1422                 d = p(d, e, f, c, z, 22, a[11]),
1423                 c = p(c, d, e, f, A, 7, a[12]),
1424                 f = p(f, c, d, e, B, 12, a[13]),
1425                 e = p(e, f, c, d, C, 17, a[14]),
1426                 d = p(d, e, f, c, D, 22, a[15]),
1427                 c = m(c, d, e, f, w, 5, a[16]),
1428                 f = m(f, c, d, e, t, 9, a[17]),
1429                 e = m(e, f, c, d, z, 14, a[18]),
1430                 d = m(d, e, f, c, h, 20, a[19]),
1431                 c = m(c, d, e, f, s, 5, a[20]),
1432                 f = m(f, c, d, e, y, 9, a[21]),
1433                 e = m(e, f, c, d, D, 14, a[22]),
1434                 d = m(d, e, f, c, r, 20, a[23]),
1435                 c = m(c, d, e, f, x, 5, a[24]),
1436                 f = m(f, c, d, e, C, 9, a[25]),
1437                 e = m(e, f, c, d, q, 14, a[26]),
1438                 d = m(d, e, f, c, v, 20, a[27]),
1439                 c = m(c, d, e, f, B, 5, a[28]),
1440                 f = m(f, c, d, e, j, 9, a[29]),
1441                 e = m(e, f, c, d, u, 14, a[30]),
1442                 d = m(d, e, f, c, A, 20, a[31]),
1443                 c = l(c, d, e, f, s, 4, a[32]),
1444                 f = l(f, c, d, e, v, 11, a[33]),
1445                 e = l(e, f, c, d, z, 16, a[34]),
1446                 d = l(d, e, f, c, C, 23, a[35]),
1447                 c = l(c, d, e, f, w, 4, a[36]),
1448                 f = l(f, c, d, e, r, 11, a[37]),
1449                 e = l(e, f, c, d, u, 16, a[38]),
1450                 d = l(d, e, f, c, y, 23, a[39]),
1451                 c = l(c, d, e, f, B, 4, a[40]),
1452                 f = l(f, c, d, e, h, 11, a[41]),
1453                 e = l(e, f, c, d, q, 16, a[42]),
1454                 d = l(d, e, f, c, t, 23, a[43]),
1455                 c = l(c, d, e, f, x, 4, a[44]),
1456                 f = l(f, c, d, e, A, 11, a[45]),
1457                 e = l(e, f, c, d, D, 16, a[46]),
1458                 d = l(d, e, f, c, j, 23, a[47]),
1459                 c = n(c, d, e, f, h, 6, a[48]),
1460                 f = n(f, c, d, e, u, 10, a[49]),
1461                 e = n(e, f, c, d, C, 15, a[50]),
1462                 d = n(d, e, f, c, s, 21, a[51]),
1463                 c = n(c, d, e, f, A, 6, a[52]),
1464                 f = n(f, c, d, e, q, 10, a[53]),
1465                 e = n(e, f, c, d, y, 15, a[54]),
1466                 d = n(d, e, f, c, w, 21, a[55]),
1467                 c = n(c, d, e, f, v, 6, a[56]),
1468                 f = n(f, c, d, e, D, 10, a[57]),
1469                 e = n(e, f, c, d, t, 15, a[58]),
1470                 d = n(d, e, f, c, B, 21, a[59]),
1471                 c = n(c, d, e, f, r, 6, a[60]),
1472                 f = n(f, c, d, e, z, 10, a[61]),
1473                 e = n(e, f, c, d, j, 15, a[62]),
1474                 d = n(d, e, f, c, x, 21, a[63]);
1475             b[0] = b[0] + c | 0;
1476             b[1] = b[1] + d | 0;
1477             b[2] = b[2] + e | 0;
1478             b[3] = b[3] + f | 0
1479         },
1480         _doFinalize: function() {
1481             var a = this._data,
1482                 k = a.words,
1483                 b = 8 * this._nDataBytes,
1484                 h = 8 * a.sigBytes;
1485             k[h >>> 5] |= 128 << 24 - h % 32;
1486             var l = s.floor(b / 4294967296);
1487             k[(h + 64 >>> 9 << 4) + 15] = (l << 8 | l >>> 24) & 16711935 | (l << 24 | l >>> 8) & 4278255360;
1488             k[(h + 64 >>> 9 << 4) + 14] = (b << 8 | b >>> 24) & 16711935 | (b << 24 | b >>> 8) & 4278255360;
1489             a.sigBytes = 4 * (k.length + 1);
1490             this._process();
1491             a = this._hash;
1492             k = a.words;
1493             for (b = 0; 4 > b; b++) h = k[b], k[b] = (h << 8 | h >>> 24) & 16711935 | (h << 24 | h >>> 8) & 4278255360;
1494             return a
1495         },
1496         clone: function() {
1497             var a = t.clone.call(this);
1498             a._hash = this._hash.clone();
1499             return a
1500         }
1501     });
1502     r.MD5 = t._createHelper(q);
1503     r.HmacMD5 = t._createHmacHelper(q)
1504 })(Math);