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