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