PageSourceSearch

https://www.pdg.pl/konto/templates/hexa/assets/js/whmcs.js

js pdg.pl collected 2026-10-02 02:57:58 UTC 75,621 bytes, 2,122 lines download raw bytes

1/**
2 * WHMCS core JS library reference
3 *
4 * @copyright Copyright (c) WHMCS Limited 2005-2017
5 * @license http://www.whmcs.com/license/ WHMCS Eula
6 */
7
8(function (window, factory) {
9    if (typeof window.WHMCS !== 'object') {
10        window.WHMCS = factory;
11    }
12}(
13    window,
14    {
15        hasModule: function (name) {
16            return (typeof WHMCS[name] !== 'undefined'
17                && Object.getOwnPropertyNames(WHMCS[name]).length > 0);
18        },
19        loadModule: function (name, module) {
20            if (this.hasModule(name)) {
21                return;
22            }
23
24            WHMCS[name] = {};
25            if (typeof module === 'function') {
26                (module).apply(WHMCS[name]);
27            } else {
28                for (var key in module) {
29                    if (module.hasOwnProperty(key)) {
30                        WHMCS[name][key] = {};
31                        (module[key]).apply(WHMCS[name][key]);
32                    }
33                }
34            }
35        }
36    }
37));
38jQuery(document).ready(function() {
39    jQuery(document).on('click', '.disable-on-click', function () {
40        jQuery(this).addClass('disabled');
41
42        if (jQuery(this).hasClass('spinner-on-click')) {
43            var icon = $(this).find('i.fas,i.far,i.fal,i.fab');
44
45            jQuery(icon)
46                .removeAttr('class')
47                .addClass('fas fa-spinner fa-spin');
48        }
49    });
50});
51/**
52 * WHMCS authentication module
53 *
54 * @copyright Copyright (c) WHMCS Limited 2005-2017
55 * @license http://www.whmcs.com/license/ WHMCS Eula
56 */
57
58(function(module) {
59    if (!WHMCS.hasModule('authn')) {
60        WHMCS.loadModule('authn', module);
61    }
62})({
63provider: function () {
64    var callbackFired = false;
65
66    /**
67     * @return {jQuery}
68     */
69    this.feedbackContainer = function () {
70        return jQuery(".providerLinkingFeedback");
71    };
72
73    /**
74     * @returns {jQuery}
75     */
76    this.btnContainer = function () {
77        return jQuery(".providerPreLinking");
78    };
79
80    this.feedbackMessage = function (context) {
81        if (typeof context === 'undefined') {
82            context = 'complete_sign_in';
83        }
84        var msgContainer = jQuery('p.providerLinkingMsg-preLink-' + context);
85        if (msgContainer.length) {
86            return msgContainer.first().html();
87        }
88
89        return '';
90    };
91
92    this.showProgressMessage = function(callback) {
93        this.feedbackContainer().fadeIn('fast', function () {
94            if (typeof callback === 'function' && !callbackFired) {
95                callbackFired = true;
96                callback();
97            }
98        });
99    };
100
101    this.preLinkInit = function (callback) {
102        var icon = '<i class="fas fa-fw fa-spinner fa-spin"></i> ';
103
104        this.feedbackContainer()
105            .removeClass('alert-danger alert-success')
106            .addClass('alert alert-info')
107            .html(icon + this.feedbackMessage())
108            .hide();
109
110        var btnContainer = this.btnContainer();
111        if (btnContainer.length) {
112            if (btnContainer.data('hideOnPrelink')) {
113                var self = this;
114                btnContainer.fadeOut('false', function ()
115                {
116                    self.showProgressMessage(callback)
117                });
118            } else if (btnContainer.data('disableOnPrelink')) {
119                btnContainer.find('.btn').addClass('disabled');
120                this.showProgressMessage(callback);
121            } else {
122                this.showProgressMessage(callback);
123            }
124        } else {
125            this.showProgressMessage(callback);
126        }
127    };
128
129    this.displayError = function (provider, errorCondition, providerErrorText){
130        jQuery('#providerLinkingMessages .provider-name').html(provider);
131
132        var feedbackMsg = this.feedbackMessage('connect_error');
133        if (errorCondition) {
134            var errorMsg = this.feedbackMessage(errorCondition);
135            if (errorMsg) {
136                feedbackMsg = errorMsg
137            }
138        }
139
140        if (providerErrorText && jQuery('.btn-logged-in-admin').length > 0) {
141            feedbackMsg += ' Error: ' + providerErrorText;
142        }
143
144        this.feedbackContainer().removeClass('alert-info alert-success')
145            .addClass('alert alert-danger')
146            .html(feedbackMsg).slideDown();
147    };
148
149    this.displaySuccess = function (data, context, provider) {
150        var icon = provider.icon;
151        var htmlTarget = context.htmlTarget;
152        var targetLogin = context.targetLogin;
153        var targetRegister = context.targetRegister;
154        var displayName = provider.name;
155        var feedbackMsg = '';
156
157        switch (data.result) {
158            case "logged_in":
159            case "2fa_needed":
160                feedbackMsg = this.feedbackMessage('2fa_needed');
161                this.feedbackContainer().removeClass('alert-danger alert-warning alert-success')
162                    .addClass('alert alert-info')
163                    .html(feedbackMsg);
164                window.location = data.redirect_url ? data.redirect_url : context.redirectUrl;
165                break;
166
167            case "linking_complete":
168                var accountInfo = '';
169                if (data.remote_account.email) {
170                    accountInfo = data.remote_account.email;
171                } else {
172                    accountInfo = data.remote_account.firstname + " " + data.remote_account.lastname;
173                }
174
175                accountInfo = accountInfo.trim();
176
177                feedbackMsg = this.feedbackMessage('linking_complete').trim().replace(':displayName', displayName);
178                if (accountInfo) {
179                    feedbackMsg = feedbackMsg.replace(/\.$/, ' (' + accountInfo + ').');
180                }
181
182                this.feedbackContainer().removeClass('alert-danger alert-warning alert-info')
183                    .addClass('alert alert-success')
184                    .html(icon + feedbackMsg);
185                break;
186
187            case "login_to_link":
188                if (htmlTarget === targetLogin) {
189                    feedbackMsg = this.feedbackMessage('login_to_link-signin-required');
190                    this.feedbackContainer().removeClass('alert-danger alert-success alert-info')
191                        .addClass('alert alert-warning')
192                        .html(icon + feedbackMsg);
193                } else {
194                    var emailField = jQuery("input[name=email]");
195                    var firstNameField = jQuery("input[name=firstname]");
196                    var lastNameField = jQuery("input[name=lastname]");
197
198                    if (emailField.val() === "") {
199                        emailField.val(data.remote_account.email);
200                    }
201
202                    if (firstNameField.val() === "") {
203                        firstNameField.val(data.remote_account.firstname);
204                    }
205
206                    if (lastNameField.val() === "") {
207                        lastNameField.val(data.remote_account.lastname);
208                    }
209
210                    if (htmlTarget === targetRegister) {
211                        if (typeof WHMCS.client.registration === 'object') {
212                            WHMCS.client.registration.prefillPassword();
213                        }
214                        feedbackMsg = this.feedbackMessage('login_to_link-registration-required');
215                        this.feedbackContainer().fadeOut('slow', function () {
216                            jQuery(this).removeClass('alert-danger alert-success alert-info')
217                                .addClass('alert alert-warning')
218                                .html(icon + feedbackMsg).fadeIn('fast');
219                        });
220
221                    } else {
222                        // this is checkout
223                        if (typeof WHMCS.client.registration === 'object') {
224                            WHMCS.client.registration.prefillPassword();
225                        }
226
227                        var self = this;
228                        this.feedbackContainer().each(function (i, el) {
229                            var container = jQuery(el);
230                            var linkContext = container.siblings('div .providerPreLinking').data('linkContext');
231
232                            container.fadeOut('slow', function () {
233                                if (linkContext === 'checkout-new') {
234                                    feedbackMsg = self.feedbackMessage('checkout-new');
235                                } else {
236                                    feedbackMsg = self.feedbackMessage('login_to_link-signin-required');
237                                }
238                                container.removeClass('alert-danger alert-success alert-info')
239                                    .addClass('alert alert-warning')
240                                    .html(icon + feedbackMsg).fadeIn('fast');
241                            });
242                        });
243                    }
244                }
245
246                break;
247
248            case "other_user_exists":
249                feedbackMsg = this.feedbackMessage('other_user_exists');
250                this.feedbackContainer().removeClass('alert-info alert-success')
251                    .addClass('alert alert-danger')
252                    .html(icon + feedbackMsg).slideDown();
253                break;
254
255            case "already_linked":
256                feedbackMsg = this.feedbackMessage('already_linked');
257                this.feedbackContainer().removeClass('alert-info alert-success')
258                    .addClass('alert alert-danger')
259                    .html(icon + feedbackMsg).slideDown();
260                break;
261
262            default:
263                feedbackMsg = this.feedbackMessage('default');
264                this.feedbackContainer().removeClass('alert-info alert-success')
265                    .addClass('alert alert-danger')
266                    .html(icon + feedbackMsg).slideDown();
267                break;
268        }
269    };
270
271    this.signIn = function (config, context, provider, providerDone, providerError) {
272        jQuery.ajax(config).done(function(data) {
273            providerDone();
274            WHMCS.authn.provider.displaySuccess(data, context, provider);
275            var table = jQuery('#tableLinkedAccounts');
276            if (table.length) {
277                WHMCS.ui.dataTable.getTableById('tableLinkedAccounts').ajax.reload();
278            }
279        }).error(function() {
280            providerError();
281            WHMCS.authn.provider.displayError();
282        });
283    };
284
285    return this;
286}});
287
288/**
289 * WHMCS client module
290 *
291 * @copyright Copyright (c) WHMCS Limited 2005-2017
292 * @license http://www.whmcs.com/license/ WHMCS Eula
293 */
294(function(module) {
295    if (!WHMCS.hasModule('client')) {
296        WHMCS.loadModule('client', module);
297    }
298})({
299registration: function () {
300    this.prefillPassword = function (params) {
301        params = params || {};
302        if (typeof params.hideContainer === 'undefined') {
303            var id = (jQuery('#inputSecurityQId').attr('id')) ? '#containerPassword' : '#containerNewUserSecurity';
304            params.hideContainer = jQuery(id);
305            params.hideInputs = true;
306        } else if (typeof params.hideContainer === 'string' && params.hideContainer.length) {
307            params.hideContainer = jQuery(params.hideContainer);
308        }
309
310        if (typeof params.form === 'undefined') {
311            params.form = {
312                password: [
313                    {id: 'inputNewPassword1'},
314                    {id: 'inputNewPassword2'}
315                ]
316            };
317        }
318
319        var prefillFunc = function () {
320            var $randomPasswd = WHMCS.utils.simpleRNG();
321            for (var i = 0, len = params.form.password.length; i < len; i++) {
322                jQuery('#' + params.form.password[i].id)
323                    .val($randomPasswd).trigger('keyup');
324            }
325        };
326
327        if (params.hideInputs) {
328            params.hideContainer.slideUp('fast', prefillFunc);
329        } else {
330            prefillFunc();
331        }
332    };
333
334    return this;
335}});
336
337/**
338 * WHMCS HTTP module
339 *
340 * @copyright Copyright (c) WHMCS Limited 2005-2018
341 * @license http://www.whmcs.com/license/ WHMCS Eula
342 */
343(function(module) {
344    if (!WHMCS.hasModule('http')) {
345        WHMCS.loadModule('http', module);
346    }
347})({
348jqClient: function () {
349    _getSettings = function (url, data, success, dataType)
350    {
351        if (typeof url === 'object') {
352            /*
353                Settings may be the only argument
354             */
355            return url;
356        }
357
358        if (typeof data === 'function') {
359            /*
360                If 'data' is omitted, 'success' will come in its place
361             */
362            success = data;
363            data = null;
364        }
365
366        return {
367            url: url,
368            data: data,
369            success: success,
370            dataType: dataType
371        };
372    };
373
374    /**
375     * @param url
376     * @param data
377     * @param success
378     * @param dataType
379     * @returns {*}
380     */
381    this.get = function (url, data, success, dataType)
382    {
383        return WHMCS.http.client.request(
384            jQuery.extend(
385                _getSettings(url, data, success, dataType),
386                {
387                    type: 'GET'
388                }
389            )
390        );
391    };
392
393    /**
394     * @param url
395     * @param data
396     * @param success
397     * @param dataType
398     * @returns {*}
399     */
400    this.post = function (url, data, success, dataType)
401    {
402        return WHMCS.http.client.request(
403            jQuery.extend(
404                _getSettings(url, data, success, dataType),
405                {
406                    type: 'POST'
407                }
408            )
409        );
410    };
411
412    return this;
413},
414
415client: function () {
416    var methods = ['get', 'post', 'put', 'delete'];
417    var client = this;
418
419    _beforeRequest = function (settings)
420    {
421        /*
422            Enforcing dataType was found to break many invocations expecting HTML back.
423            If/when those are refactored, this may be uncommented to enforce a safer
424            data transit.
425         */
426        /*if (typeof settings.dataType === 'undefined') {
427            settings.dataType = 'json';
428        }*/
429
430        if (typeof settings.type === 'undefined') {
431            // default request type is GET
432            settings.type = 'GET';
433        }
434
435        /*
436            Add other preprocessing here if required
437         */
438
439        return settings;
440    };
441
442    this.request = function (settings)
443    {
444        settings = _beforeRequest(settings || {});
445        return jQuery.ajax(settings);
446    };
447
448    /*
449        Create shortcut methods for methods[] array above
450     */
451    jQuery.each(methods, function(index, method) {
452        client[method] = (function(method, client) {
453            return function (settings)
454            {
455                settings = settings || {};
456
457                settings.type = method.toUpperCase();
458
459                return client.request(settings);
460            }
461        })(method, client);
462    });
463
464    return this;
465}
466
467});
468
469/**
470 * WHMCS UI module
471 *
472 * @copyright Copyright (c) WHMCS Limited 2005-2017
473 * @license http://www.whmcs.com/license/ WHMCS Eula
474 */
475(function(module) {
476    if (!WHMCS.hasModule('ui')) {
477        WHMCS.loadModule('ui', module);
478    }
479})({
480/**
481 * Confirmation PopUp
482 */
483confirmation: function () {
484
485    /**
486     * @type {Array} Registered confirmation root selectors
487     */
488    var toggles = [];
489
490    /**
491     * Register/Re-Register all confirmation elements with jQuery
492     * By default all elements of data toggle "confirmation" will be registered
493     *
494     * @param {(string|undefined)} rootSelector
495     * @return {Array} array of registered toggles
496     */
497    this.register = function (rootSelector) {
498        if (typeof rootSelector === 'undefined') {
499            rootSelector = '[data-toggle=confirmation]';
500        }
501        if (toggles.indexOf(rootSelector) < 0) {
502            toggles.push(rootSelector);
503        }
504
505        jQuery(rootSelector).confirmation({
506            rootSelector: rootSelector
507        });
508
509        return toggles;
510    };
511
512    return this;
513},
514
515/**
516 * Data Driven Table
517 */
518dataTable: function () {
519
520    /**
521     * @type {{}}
522     */
523    this.tables = {};
524
525    /**
526     * Register all tables on page with the class "data-driven"
527     */
528    this.register = function () {
529        var self = this;
530        jQuery('table.data-driven').each(function (i, table) {
531            self.getTableById(table.id, undefined);
532        });
533    };
534
535    /**
536     * Get a table by id; create table object on fly as necessary
537     *
538     * @param {string} id
539     * @param {({}|undefined)} options
540     * @returns {DataTable}
541     */
542    this.getTableById = function (id, options) {
543        var self = this;
544        var el = jQuery('#' + id);
545        if (typeof self.tables[id] === 'undefined') {
546            if (typeof options === 'undefined') {
547                options = {
548                    dom: '<"listtable"ift>pl',
549                    paging: false,
550                    lengthChange: false,
551                    searching: false,
552                    ordering: true,
553                    info: false,
554                    autoWidth: true,
555                    language: {
556                        emptyTable: (el.data('lang-empty-table')) ? el.data('lang-empty-table') : "No records found"
557                    }
558                };
559            }
560            var ajaxUrl = el.data('ajax-url');
561            if (typeof ajaxUrl !== 'undefined') {
562                options.ajax = {
563                    url: ajaxUrl
564                };
565            }
566            var dom = el.data('dom');
567            if (typeof dom !== 'undefined') {
568                options.dom = dom;
569            }
570            var searching = el.data('searching');
571            if (typeof searching !== 'undefined') {
572                options.searching = searching;
573            }
574            var responsive = el.data('responsive');
575            if (typeof responsive !== 'undefined') {
576                options.responsive = responsive;
577            }
578            var ordering = el.data('ordering');
579            if (typeof ordering !== 'undefined') {
580                options["ordering"] = ordering;
581            }
582            var order = el.data('order');
583            if (typeof order !== 'undefined' && order) {
584                options["order"] = order;
585            }
586            var colCss = el.data('columns');
587            if (typeof colCss !== 'undefined' && colCss) {
588                options["columns"] = colCss;
589            }
590            var autoWidth = el.data('auto-width');
591            if (typeof autoWidth !== 'undefined') {
592                options["autoWidth"] = autoWidth;
593            }
594            var paging = el.data('paging');
595            if (typeof paging !== 'undefined') {
596                options["paging"] = paging;
597            }
598            var lengthChange = el.data('length-change');
599            if (typeof lengthChange !== 'undefined') {
600                options["lengthChange"] = lengthChange;
601            }
602            var pageLength = el.data('page-length');
603            if (typeof pageLength !== 'undefined') {
604                options["pageLength"] = pageLength;
605            }
606
607            self.tables[id] = self.initTable(el, options);
608        } else if (typeof options !== 'undefined') {
609            var oldTable = self.tables[id];
610            var initOpts = oldTable.init();
611            var newOpts = jQuery.extend( initOpts, options);
612            oldTable.destroy();
613            self.tables[id] = self.initTable(el, newOpts);
614        }
615
616        return self.tables[id];
617    };
618
619    this.initTable = function (el, options) {
620        var table = el.DataTable(options);
621        var self = this;
622        if (el.data('on-draw')) {
623            table.on('draw.dt', function (e, settings) {
624                var namedCallback = el.data('on-draw');
625                if (typeof window[namedCallback] === 'function') {
626                    window[namedCallback](e, settings);
627                }
628            });
629        } else if (el.data('on-draw-rebind-confirmation')) {
630            table.on('draw.dt', function (e) {
631                self.rebindConfirmation(e);
632            });
633        }
634
635        return table;
636    };
637
638    this.rebindConfirmation = function (e) {
639        var self = this;
640        var tableId = e.target.id;
641        var toggles = WHMCS.ui.confirmation.register();
642        for(var i = 0, len = toggles.length; i < len; i++ ) {
643            jQuery(toggles[i]).on(
644                'confirmed.bs.confirmation',
645                function (e)
646                {
647                    e.preventDefault();
648                    WHMCS.http.jqClient.post(
649                        jQuery(e.target).data('target-url'),
650                        {
651                            'token': csrfToken
652                        }
653                    ).done(function (data)
654                    {
655                        if (data.status === 'success' || data.status === 'okay') {
656                            self.getTableById(tableId, undefined).ajax.reload();
657                        }
658                    });
659
660                }
661            );
662        }
663    };
664
665    return this;
666},
667
668/**
669* ToolTip and Clipboard behaviors
670*/
671toolTip: function () {
672  this.registerClipboard = function () {
673      var self = this;
674      jQuery('[data-toggle="tooltip"]').tooltip();
675      var clipboard = new Clipboard('.copy-to-clipboard');
676      clipboard.on('success', function(e) {
677          var btn = jQuery(e.trigger);
678          self.setTip(btn, 'Copied!');
679          self.hideTip(btn);
680      });
681      clipboard.on('error', function(e) {
682          self.setTip(e.trigger, 'Press Ctrl+C to copy');
683          self.hideTip(e.trigger);
684      });
685      jQuery('.copy-to-clipboard').tooltip({
686          trigger: 'click',
687          placement: 'bottom'
688      });
689  };
690
691  this.setTip = function (btn, message) {
692      var tip = btn.data('bs.tooltip');
693      if (tip.hoverState !== 'in') {
694          tip.hoverState = 'in';
695      }
696      btn.attr('data-original-title', message);
697      tip.show();
698
699      return tip;
700  };
701
702  this.hideTip = function (btn) {
703      return setTimeout(function() {
704          btn.data('bs.tooltip').hide()
705      }, 2000);
706  }
707}
708});
709
710/**
711* Form module
712*
713* @copyright Copyright (c) WHMCS Limited 2005-2017
714* @license http://www.whmcs.com/license/ WHMCS Eula
715*/
716(function(module) {
717  if (!WHMCS.hasModule('form')) {
718      WHMCS.loadModule('form', module);
719  }
720})(
721  function () {
722      this.checkAllBound = false;
723
724      this.register = function () {
725          if (!this.checkAllBound) {
726              this.bindCheckAll();
727              this.checkAllBound = true;
728          }
729      };
730
731  this.bindCheckAll = function ()
732  {
733      var huntSelector = '.btn-check-all';
734      jQuery(huntSelector).click(function (e) {
735          var btn = jQuery(e.target);
736          var targetInputs = jQuery(
737              '#' + btn.data('checkbox-container') + ' input[type="checkbox"]'
738          );
739          if (btn.data('btn-check-toggle')) {
740              // one control that changes
741              var textDeselect = 'Deselect All';
742              var textSelect = 'Select All';
743              if (btn.data('label-text-deselect')) {
744                  textDeselect = btn.data('label-text-deselect');
745              }
746              if (btn.data('label-text-select')) {
747                  textSelect = btn.data('label-text-select');
748              }
749
750              if (btn.hasClass('toggle-active')) {
751                  targetInputs.prop('checked',false);
752                  btn.text(textSelect);
753                  btn.removeClass('toggle-active');
754              } else {
755                  targetInputs.prop('checked',true);
756                  btn.text(textDeselect);
757                  btn.addClass('toggle-active');
758              }
759          } else {
760              // two controls that are static
761              if (btn.data('btn-toggle-on')) {
762                  targetInputs.prop('checked',true);
763              } else {
764                  targetInputs.prop('checked',false);
765              }
766          }
767      });
768  };
769
770  return this;
771});
772
773/**
774 * reCaptcha module
775 *
776 * @copyright Copyright (c) WHMCS Limited 2005-2018
777 * @license http://www.whmcs.com/license/ WHMCS Eula
778 */
779(function(module) {
780    if (!WHMCS.hasModule('recaptcha')) {
781        WHMCS.loadModule('recaptcha', module);
782    }
783})(
784    function () {
785
786        this.register = function () {
787            var postLoad = [];
788            var recaptchaForms = jQuery(".btn-recaptcha").parents('form');
789            recaptchaForms.each(function (i, el){
790                if (typeof recaptchaSiteKey === 'undefined') {
791                    console.log('Recaptcha site key not defined');
792                    return;
793                }
794                var frm = jQuery(el);
795                var btnRecaptcha = frm.find(".btn-recaptcha");
796                var isInvisible = btnRecaptcha.hasClass('btn-recaptcha-invisible');
797
798                // if no recaptcha element, make one
799                var recaptchaContent = frm.find("#divDynamicRecaptcha .g-recaptcha");
800                if (!recaptchaContent.length) {
801                    frm.append('<div id="divDynamicRecaptcha" class="g-recaptcha"></div>');
802                    recaptchaContent = frm.find("#divDynamicRecaptcha");
803                }
804                // propagate invisible recaptcha if necessary
805                if (isInvisible) {
806                    if (recaptchaContent.data('size') !== 'invisible') {
807                        recaptchaContent.attr('data-size', 'invisible');
808                    }
809                } else {
810                    recaptchaContent.hide()
811                }
812
813                // ensure site key is available to grecaptcha
814                recaptchaContent.attr('data-sitekey', recaptchaSiteKey);
815
816
817                // alter form to work around JS behavior on .submit() when there
818                // there is an input with the name 'submit'
819                var btnSubmit = frm.find("input[name='submit']");
820                if (btnSubmit.length) {
821                    var action = frm.prop('action');
822                    frm.prop('action', action + '&submit=1');
823                    btnSubmit.remove();
824                }
825
826                // make callback for grecaptcha to invoke after
827                // injecting token & make it known via data-callback
828                var funcName = 'recaptchaCallback' + i;
829                window[funcName] = function () {
830                    if (isInvisible) {
831                        frm.submit();
832                    } else {
833                        btnRecaptcha.prop("disabled", false);
834                        recaptchaContent.slideUp('fast', function () {
835                            recaptchaContent.hide();
836                            btnRecaptcha.slideDown();
837                        });
838
839                    }
840                };
841                recaptchaContent.attr('data-callback', funcName);
842
843                // alter submit button to integrate invisible recaptcha
844                // otherwise setup a callback to twiddle UI after grecaptcha
845                // has inject DOM
846                if (isInvisible) {
847                    btnRecaptcha.on('click', function (event) {
848                        event.preventDefault();
849                        grecaptcha.execute();
850                    });
851                } else {
852                    postLoad.push(function () {
853                        btnRecaptcha.slideUp('fast', function () {
854                            btnRecaptcha.hide();
855                            btnRecaptcha.prop("disabled", true);
856                            recaptchaContent.find(':first').addClass('center-block');
857                            recaptchaContent.slideDown('fast', function() {
858                                // just in case there's a delay in DOM; rare
859                                recaptchaContent.find(':first').addClass('center-block');
860                            });
861                        });
862                    });
863                }
864            });
865
866            // fetch/invoke the grecaptcha lib
867            if (recaptchaForms.length) {
868                var gUrl = "https://www.google.com/recaptcha/api.js";
869                jQuery.getScript(gUrl, function () {
870                    for(var i = postLoad.length -1; i >= 0 ; i--){
871                        postLoad[i]();
872                    }
873                });
874            }
875        };
876
877        return this;
878    });
879
880/**
881 * General utilities module
882 *
883 * @copyright Copyright (c) WHMCS Limited 2005-2017
884 * @license http://www.whmcs.com/license/ WHMCS Eula
885 */
886(function(module) {
887    if (!WHMCS.hasModule('utils')) {
888        WHMCS.loadModule('utils', module);
889    }
890})(
891function () {
892    /**
893     * Not crypto strong; server-side must discard for
894     * something with more entropy; the value is sufficient
895     * for strong client-side validation check
896     */
897    this.simpleRNG = function () {
898        var chars = './$_-#!,^*()|';
899        var r = 0;
900        for (var i = 0; r < 3; i++) {
901            r += Math.floor((Math.random() * 10) / 2);
902        }
903        r = Math.floor(r);
904        var s = '';
905        for (var x = 0; x < r; x++) {
906            v = (Math.random() + 1).toString(24).split('.')[1];
907            if ((Math.random()) > 0.5) {
908                s += btoa(v).substr(0,4)
909            } else {
910                s += v
911            }
912
913            if ((Math.random()) > 0.5) {
914                s += chars.substr(
915                    Math.floor(Math.random() * 13),
916                    1
917                );
918            }
919        }
920
921        return s;
922    };
923
924    this.getRouteUrl = function (path) {
925        return whmcsBaseUrl + "/index.php?rp=" + path;
926    };
927
928
929    this.validateBaseUrl = function() {
930        if (typeof window.whmcsBaseUrl === 'undefined') {
931            console.log('Warning: The WHMCS Base URL definition is missing '
932                + 'from your active template. Please refer to '
933                + 'https://docs.whmcs.com/WHMCS_Base_URL_Template_Variable '
934                + 'for more information and details of how to resolve this '
935                + 'warning.');
936            window.whmcsBaseUrl = this.autoDetermineBaseUrl();
937            window.whmcsBaseUrlAutoSet = true;
938        } else if (window.whmcsBaseUrl === ''
939            && typeof window.whmcsBaseUrlAutoSet !== 'undefined'
940            && window.whmcsBaseUrlAutoSet === true
941        ) {
942            window.whmcsBaseUrl = this.autoDetermineBaseUrl();
943        }
944    };
945
946    this.autoDetermineBaseUrl = function() {
947        var windowLocation = window.location.href;
948        var phpExtensionLocation = -1;
949
950        if (typeof windowLocation !== 'undefined') {
951            phpExtensionLocation = windowLocation.indexOf('.php');
952        }
953
954        if (phpExtensionLocation === -1) {
955            windowLocation = jQuery('#Primary_Navbar-Home a').attr('href');
956            if (typeof windowLocation !== 'undefined') {
957                phpExtensionLocation = windowLocation.indexOf('.php');
958            }
959        }
960
961        if (phpExtensionLocation !== -1) {
962            windowLocation = windowLocation.substring(0, phpExtensionLocation);
963            var lastTrailingSlash = windowLocation.lastIndexOf('/');
964            if (lastTrailingSlash !== false) {
965                return windowLocation.substring(0, lastTrailingSlash);
966            }
967        }
968
969        return '';
970    };
971
972    return this;
973});
974
975WHMCS.utils.validateBaseUrl();
976
977// Default catch for all other popovers
978jQuery('[data-toggle="popover"]').popover({
979    html: true
980});
981
982// Logic to dismiss popovers on click outside
983jQuery('body').on('click', function (e) {
984    jQuery('[data-toggle="popover"]').each(function () {
985        if (!jQuery(this).is(e.target) && jQuery(this).has(e.target).length === 0 && jQuery('.popover').has(e.target).length === 0) {
986            jQuery(this).popover('hide');
987        }
988    });
989});
990
991(function(j) {
992  j.fn.extend({
993    accordion: function() {
994      return this.each(function() {
995        function b(c, b) {
996          jQuery(c).parent(d).siblings().removeClass(e).children(f).slideUp(g);
997          jQuery(c).siblings(f)[b || h](b == "show" ? g : !1, function() {
998            jQuery(c).siblings(f).is(":visible") ? jQuery(c).parents(d).not(a.parents()).addClass(e) : jQuery(c).parent(d).removeClass(e);
999            b == "show" && jQuery(c).parents(d).not(a.parents()).addClass(e);
1000            jQuery(c).parents().show()
1001          })
1002        }
1003        var a = jQuery(this), e = "active", h = "slideToggle", f = "ul, div", g = "fast", d = "li";
1004        if (a.data("accordiated"))
1005          return !1;
1006        jQuery.each(a.find("ul, li>div"),
1007          function() {
1008            jQuery(this).data("accordiated", !0);
1009            jQuery(this).hide()
1010          });
1011        jQuery.each(a.find("a"), function() {
1012          jQuery(this).click(function() {
1013            b(this, h)
1014          });
1015          jQuery(this).bind("activate-node", function() {
1016            a.find(f).not(jQuery(this).parents()).not(jQuery(this).siblings()).slideUp(g);
1017            b(this, "slideDown")
1018          })
1019        });
1020        var i = location.hash ? a.find("a[href='" + location.hash + "']")[0]: a.find("li.current a")[0];
1021        i && b(i, !1)
1022      })
1023}
1024})
1025})(jQuery);
1026
1027jQuery(function(){
1028    var url = document.location.toString();
1029    if (url.match('#')) {
1030        jQuery('.nav a[href="#' + url.split('#')[1] + '"]').tab('show');
1031    }
1032});
1033
1034// Checkboxes Toggle
1035// ===============================
1036function toggleCheckboxes(classname) {
1037  jQuery("."+classname).attr('checked',!jQuery("."+classname+":first").is(':checked'));
1038}
1039// Disable Field Class
1040// ===============================
1041function disableFields(classname,disable) {
1042  if (disable) jQuery("."+classname).attr("disabled","disabled");
1043  else jQuery("."+classname).removeAttr("disabled");
1044}
1045
1046/**
1047 * Used to toggle display of editable billing address fields.
1048 */
1049function editBillingAddress() {
1050    jQuery("#billingAddressSummary").hide();
1051    jQuery(".cc-billing-address").hide().removeClass('hidden').fadeIn();
1052}
1053
1054
1055/**
1056 * Show new credit card input fields.
1057 */
1058function showNewCardInputFields() {
1059    if (jQuery(".cc-details").hasClass("hidden")) {
1060        jQuery(".cc-details").hide().removeClass("hidden");
1061    }
1062    jQuery(".cc-details").slideDown();
1063    jQuery("#btnEditBillingAddress").removeAttr("disabled");
1064}
1065
1066/**
1067 * Hide new credit card input fields.
1068 */
1069function hideNewCardInputFields() {
1070    jQuery(".cc-billing-address").slideUp();
1071    jQuery(".cc-details").slideUp();
1072    jQuery("#btnEditBillingAddress").attr("disabled", "disabled");
1073    if (jQuery("#billingAddressSummary").hasClass('hidden')) {
1074        jQuery("#billingAddressSummary").hide().removeClass('hidden').slideDown();
1075    } else {
1076        jQuery("#billingAddressSummary").slideDown();
1077    }
1078}
1079
1080/**
1081 * Redirect on click if an element is not a button or link.
1082 *
1083 * Where table rows are clickable, we only want to redirect if the row
1084 * itself is clicked. If a button or link within the row is clicked,
1085 * the event tied to that object should be executed. This function
1086 * stops the standard JS event bubbling required to make that happen.
1087 *
1088 * @param {object} clickEvent jQuery click event
1089 * @param {string} target     Redirect location
1090 * @param {bool} newWindow    Open link in new window
1091 */
1092function clickableSafeRedirect(clickEvent, target, newWindow) {
1093    var eventSource = clickEvent.target.tagName.toLowerCase();
1094    var eventParent = clickEvent.target.parentNode.tagName.toLowerCase();
1095    var eventTable = clickEvent.target.parentNode.parentNode.parentNode;
1096    if (jQuery(eventTable).hasClass('collapsed')) {
1097        // This is a mobile device sized display, and datatables has triggered folding
1098        return false;
1099    }
1100    if(eventSource != 'button' && eventSource != 'a') {
1101        if(eventParent != 'button' && eventParent != 'a') {
1102            if (newWindow) {
1103                window.open(target);
1104            } else {
1105                window.location.href = target;
1106            }
1107        }
1108    }
1109}
1110
1111// Open Centered Popup
1112// ===============================
1113function popupWindow(addr,popname,w,h,features) {
1114  var winl = (screen.width-w)/2;
1115  var wint = (screen.height-h)/2;
1116  if (winl < 0) winl = 0;
1117  if (wint < 0) wint = 0;
1118  var settings = 'height=' + h + ',';
1119  settings += 'width=' + w + ',';
1120  settings += 'top=' + wint + ',';
1121  settings += 'left=' + winl + ',';
1122  settings += features;
1123  win = window.open(addr,popname,settings);
1124  win.window.focus();
1125}
1126// Support Tickets
1127// ===============================
1128function extraTicketAttachment() {
1129  jQuery("#fileuploads").append('<p><div class="input-group"><span class="input-group-btn"><span class="btn btn-default btn-sm btn-file"><span class="glyphicon glyphicon-folder-open"></span> <input type="file" name="attachments[]" multiple=""></span></span><input type="text" class="form-control input-sm" readonly=""></div></p>');
1130  jQuery(document).ready( function() {
1131    jQuery('.btn-file :file').on('fileselect', function(event, numFiles, label) {
1132
1133      var input = jQuery(this).parents('.input-group').find(':text'),
1134      log = numFiles > 1 ? numFiles + ' files selected' : label;
1135
1136      if( input.length ) {
1137        input.val(log);
1138      } else {
1139        if( log ) alert(log);
1140      }
1141
1142    });
1143  });
1144}
1145function rating_hover(id) {
1146    var selrating=id.split('_');
1147    for(var i=1; i<=5; i++){
1148        if(i<=selrating[1]) document.getElementById(selrating[0]+'_'+i).childNodes[0].className="glyphicon glyphicon-star";
1149        if(i>selrating[1]) document.getElementById(selrating[0]+'_'+i).childNodes[0].className="glyphicon glyphicon-star-empty";
1150    }
1151}
1152function rating_leave(id){
1153    for(var i=1; i<=5; i++){
1154        document.getElementById(id+'_'+i).childNodes[0].className="glyphicon glyphicon-star-empty";
1155    }
1156}
1157function rating_select(tid,c,id){
1158  window.location='viewticket.php?tid='+tid+'&c='+c+'&rating='+id;
1159}
1160// Sidebar
1161// ===============================
1162jQuery('ul.nav-list').accordion();
1163jQuery('.site-holder.container .nav > li > ul > li.active').parent().css('display','block');
1164jQuery('.site-holder.container.mini-sidebar .nav > li > ul > li.active').parent().css('display','none');
1165jQuery('.btn-nav-toggle-responsive').click(function(){
1166  jQuery('.left-sidebar').toggleClass('show-fullsidebar');
1167});
1168jQuery('li.nav-toggle > button').click(function(e){
1169        //Set cookie
1170        if(jQuery.cookie('minibar')==null||jQuery.cookie('minibar')==0) {
1171          jQuery.cookie('minibar',1);
1172          jQuery('li.submenu').removeClass('active');
1173          jQuery('li.submenu > ul').hide();
1174          jQuery('.fa.arrow.rotate').removeClass('down');
1175        }
1176        else {
1177          jQuery.cookie('minibar',0);
1178        }
1179        e.preventDefault();
1180        changeSidebarState();
1181      });
1182    //Load sidebar state
1183    jQuery(function(){
1184      if(jQuery.cookie('minibar')==1) {
1185        changeSidebarStateNoAnimate();
1186      }
1187    });
1188    function changeSidebarState(){
1189      jQuery('.hidden-minibar').toggleClass("hide");
1190      jQuery('.site-holder').toggleClass("mini-sidebar");
1191
1192      if(jQuery('.toggle-right').hasClass('fa-angle-double-right')){ jQuery('.toggle-right').removeClass('fa-angle-double-right').addClass('fa-angle-double-left'); }
1193            else { jQuery('.toggle-right').removeClass('fa-angle-double-left').addClass('fa-angle-double-right'); }
1194
1195      if(jQuery('.toggle-left').hasClass('fa-angle-double-left')){ jQuery('.toggle-left').removeClass('fa-angle-double-left').addClass('fa-angle-double-right'); }
1196            else { jQuery('.toggle-left').removeClass('fa-angle-double-right').addClass('fa-angle-double-left'); }
1197
1198      if(jQuery('.site-holder').hasClass('mini-sidebar'))
1199      {
1200        jQuery('.sidebar-holder').tooltip({
1201          selector: "a",
1202          container: "body",
1203          placement: "right"
1204        });
1205        jQuery('li.submenu ul').tooltip('destroy');
1206      }
1207      else
1208      {
1209        jQuery('.sidebar-holder').tooltip('destroy');
1210      }
1211    }
1212    function changeSidebarStateNoAnimate(){
1213      jQuery('.toggle-left').removeClass('fa-angle-double-left').addClass('fa-angle-double-right');
1214      jQuery('.toggle-right').removeClass('fa-angle-double-right').addClass('fa-angle-double-left');
1215      if(jQuery('.site-holder').hasClass('mini-sidebar'))
1216      {
1217        jQuery('.sidebar-holder').tooltip({
1218          selector: "a",
1219          container: "body",
1220          placement: "right"
1221        });
1222        jQuery('li.submenu ul').tooltip('destroy');
1223      }
1224      else
1225      {
1226        jQuery('.sidebar-holder').tooltip('destroy');
1227      }
1228    }
1229      //
1230      if(jQuery('.site-holder').hasClass('mini-sidebar'))
1231      {
1232        jQuery('.sidebar-holder').tooltip({
1233          selector: "a",
1234          container: "body",
1235          placement: "right"
1236        });
1237        jQuery('li.submenu').tooltip('destroy');
1238      }
1239      else
1240      {
1241        jQuery('.sidebar-holder').tooltip('destroy');
1242      }
1243      jQuery('.show-info').click(function(){
1244       jQuery(this).toggleClass("down");
1245        jQuery('.page-information').toggleClass('hidden');
1246      });
1247
1248      jQuery('.show-task-info').click(function(){
1249       jQuery(this).toggleClass("down");
1250        jQuery(this).parents('.todo-task').find('.task-info').toggleClass('hidden');
1251      });
1252
1253      jQuery('.site-holder.mini-sidebar .content').click(function () {
1254       jQuery('.site-holder.mini-sidebar li.submenu ul').hide();
1255       jQuery('.site-holder.mini-sidebar li.submenu').removeClass('active');
1256
1257     });
1258
1259// Rotate icon
1260// ===============================
1261jQuery(".sidebar-holder .nav a.dropdown").click(function(){
1262jQuery('.rotate', this).toggleClass("down")  ;
1263})
1264
1265
1266// Language Dropdown
1267// ===============================
1268
1269
1270jQuery('.settings-toggle').click(function(e){
1271  e.preventDefault();
1272  jQuery('.right-sidebar').toggleClass('right-sidebar-hidden');
1273});
1274jQuery('.theme-panel-close').click(function(){
1275  jQuery('.right-sidebar').toggleClass('right-sidebar-hidden');
1276});
1277
1278jQuery(function(){
1279  jQuery('.right-sidebar-holder').perfectScrollbar();
1280});
1281
1282// Scrollbar
1283// ===============================
1284
1285
1286jQuery(function(){
1287  jQuery('.ps-messages').perfectScrollbar();
1288});
1289
1290jQuery(function(){
1291  jQuery('.ps-languages').perfectScrollbar();
1292});
1293
1294jQuery(function(){
1295  jQuery('.server-list').perfectScrollbar();
1296});
1297
1298// Server List
1299// ===============================
1300
1301
1302jQuery(function(){
1303        jQuery('.server-list').tooltip({
1304          selector: "a",
1305          container: "body",
1306          placement: "top"
1307        });
1308});
1309
1310 // Enable Switches for Checkboxes
1311    if (jQuery.prototype.bootstrapSwitch) {
1312        jQuery(".toggle-switch-success").bootstrapSwitch({
1313            onColor: 'success'
1314        });
1315    }
1316
1317// Handle Single Sign-On Toggle Setting
1318    jQuery("#inputAllowSso").on('switchChange.bootstrapSwitch', function(event, isChecked) {
1319        if (isChecked) {
1320            jQuery("#ssoStatusTextEnabled").removeClass('hidden').show();
1321            jQuery("#ssoStatusTextDisabled").hide();
1322        } else {
1323            jQuery("#ssoStatusTextDisabled").removeClass('hidden').show();
1324            jQuery("#ssoStatusTextEnabled").hide();
1325        }
1326        WHMCS.http.jqClient.post("clientarea.php", jQuery("#frmSingleSignOn").seri
1326alize());
1327    });
1328
1329
1330    // Single Sign-On call for Product/Service
1331    jQuery('.btn-service-sso').on('click', function(e) {
1332        e.preventDefault();
1333        var button = jQuery(this);
1334
1335        var form = button.parents('form');
1336
1337        if (form.length == 0) {
1338            form = button.find('form');
1339        }
1340        if (form.hasClass('disabled')) {
1341            return;
1342        }
1343
1344        button.find('.loading').removeClass('hidden').show().end()
1345            .attr('disabled', 'disabled');
1346        WHMCS.http.jqClient.post(
1347            window.location.href,
1348            form.serialize(),
1349            function (data) {
1350                button.find('.loading').hide().end().removeAttr('disabled');
1351                form.find('.login-feedback').html('');
1352                if (data.error) {
1353                    form.find('.login-feedback').html(data.error);
1354                }
1355                if (data.redirect !== undefined && data.redirect.substr(0, 7) === 'window|') {
1356                    window.open(data.redirect.substr(7), '_blank');
1357                }
1358            },
1359            'json'
1360        );
1361    });
1362    jQuery('.btn-sidebar-form-submit').on('click', function(e) {
1363        e.preventDefault();
1364        jQuery(this).find('.loading').removeClass('hidden').show().end()
1365            .attr('disabled', 'disabled');
1366
1367        var form = jQuery(this).parents('form');
1368
1369        if (form.length == 0) {
1370            form = jQuery(this).find('form');
1371        }
1372
1373        if (form.length !== 0 && form.hasClass('disabled') === false) {
1374            form.submit();
1375        } else {
1376            jQuery(this).find('.loading').hide().end().removeAttr('disabled');
1377        }
1378    });
1379
1380    // Email verification close
1381    jQuery('.email-verification .btn.close').click(function(e) {
1382        e.preventDefault();
1383        WHMCS.http.jqClient.post('clientarea.php', 'action=dismiss-email-banner&token=' + csrfToken);
1384        jQuery('.email-verification').hide();
1385    });
1386
1387    // Back to top animated scroll
1388    jQuery('.back-to-top').click(function(e) {
1389        e.preventDefault();
1390        jQuery('body,html').animate({scrollTop: 0}, 500);
1391    });
1392
1393    // Prevent page scroll on language choose click
1394    jQuery('.choose-language').click(function(e) {
1395        e.preventDefault();
1396    });
1397
1398
1399
1400// Sub-Account Activation Toggle
1401    jQuery("#inputSubaccountActivate").click(function () {
1402        if (jQuery("#inputSubaccountActivate:checked").val() != null) {
1403            jQuery("#subacct-container").removeClass('hidden');
1404        } else {
1405            jQuery("#subacct-container").addClass('hidden');
1406        }
1407    });
1408
1409/**
1410 * Add domain renewal to shopping cart.
1411 *
1412 * @param {number} renewalID    The domain ID to be added
1413 * @param {domElement} selfThis The object triggering the add
1414 */
1415function addRenewalToCart(renewalID, selfThis) {
1416    jQuery("#domainRow" + renewalID).attr('disabled', 'disabled');
1417    jQuery("#domainRow" + renewalID).find("select,button").attr("disabled", "disabled");
1418    jQuery(selfThis).html('<span class="glyphicon glyphicon-shopping-cart"></span> Adding...');
1419    var renewalPeriod = jQuery("#renewalPeriod" + renewalID).val();
1420    WHMCS.http.jqClient.post(
1421        "clientarea.php",
1422        "addRenewalToCart=1&token=" + csrfToken + "&renewID="+ renewalID + "&period=" + renewalPeriod,
1423        function( data ) {
1424            jQuery("#cartItemCount").html(((jQuery("#cartItemCount").html() * 1) + 1));
1425            jQuery(selfThis).html('<span class="glyphicon glyphicon-shopping-cart"></span> Added');
1426            jQuery("#btnCheckout").fadeIn();
1427        }
1428    );
1429}
1430
1431    // Mass Domain Management Bulk Action Handling
1432    jQuery(".setBulkAction").click(function(event) {
1433        event.preventDefault();
1434        var id = jQuery(this).attr('id').replace('Link', ''),
1435            domainForm = jQuery('#domainForm');
1436
1437        if (id === 'renewDomains') {
1438            domainForm.attr('action', WHMCS.utils.getRouteUrl('/cart/domain/renew'));
1439        } else {
1440            if (jQuery('#' + id).length !== 0) {
1441                var action = domainForm.attr('action');
1442                domainForm.attr('action', action + '#' + id);
1443            }
1444            jQuery('#bulkaction').val(id);
1445        }
1446        domainForm.submit();
1447    });
1448
1449/**
1450 * Submit default whois info and disable custom fields.
1451 *
1452 * @param {string} regType The contact registration type
1453 */
1454function useDefaultWhois(regType) {
1455    jQuery("." + regType.substr(0, regType.length - 1) + "customwhois").attr("disabled", true);
1456    jQuery("." + regType.substr(0, regType.length - 1) + "defaultwhois").attr("disabled", false);
1457    jQuery('#' + regType.substr(0, regType.length - 1) + '1').attr("checked", "checked");
1458}
1459
1460/**
1461 * Submit the first form that exists within a given container.
1462 *
1463 * @param {string} containerId The ID name of the container
1464 */
1465 function autoSubmitFormByContainer(containerId) {
1466     if (typeof noAutoSubmit === "undefined" || noAutoSubmit === false) {
1467         jQuery("#" + containerId).find("form:first").submit();
1468     }
1469 }
1470
1471/**
1472 * Submit custom fields and disable default whois info.
1473 *
1474 * @param {string} regType The contact registration type
1475 */
1476function useCustomWhois(regType) {
1477    jQuery("." + regType.substr(0, regType.length - 1) + "customwhois").attr("disabled", false);
1478    jQuery("." + regType.substr(0, regType.length - 1) + "defaultwhois").attr("disabled", true);
1479    jQuery('#' + regType.substr(0, regType.length - 1) + '2').attr("checked", "checked");
1480}
1481
1482
1483if (typeof Waves !== 'undefined') {
1484  Waves.init();
1485  Waves.attach(".sidebar-holder .nav a", ["waves-light", "waves-round"]);
1486}
1487
1488/**
1489 * Smooth scroll to named element.
1490 */
1491function smoothScroll(element) {
1492    $('html, body').animate({
1493        scrollTop: $(element).offset().top
1494    }, 500);
1495}
1496
1497function irtpSubmit()
1498{
1499    allowSubmit = true;
1500    var optOut = 0,
1501        optOutCheckbox = jQuery('#modalIrtpOptOut'),
1502        optOutReason = jQuery('#modalReason'),
1503        formOptOut = jQuery('#irtpOptOut'),
1504        formOptOutReason = jQuery('#irtpOptOutReason');
1505
1506    if (optOutCheckbox.is(':checked')) {
1507        optOut = 1;
1508    }
1509    formOptOut.val(optOut);
1510    formOptOutReason.val(optOutReason.val());
1511    jQuery('#frmDomainContactModification').submit();
1512}
1513
1514/*!
1515 * WHMCS Ajax Driven Modal Framework
1516 *
1517 * @copyright Copyright (c) WHMCS Limited 2005-2016
1518 * @license http://www.whmcs.com/license/ WHMCS Eula
1519 */
1520jQuery(document).ready(function(){
1521    jQuery(document).on('click', '.open-modal', function(e) {
1522        e.preventDefault();
1523        var url = jQuery(this).attr('href'),
1524            modalSize = jQuery(this).data('modal-size'),
1525            modalClass = jQuery(this).data('modal-class'),
1526            modalTitle = jQuery(this).data('modal-title'),
1527            submitId = jQuery(this).data('btn-submit-id'),
1528            submitLabel = jQuery(this).data('btn-submit-label'),
1529            hideClose = jQuery(this).data('btn-close-hide'),
1530            disabled = jQuery(this).attr('disabled'),
1531            successDataTable = jQuery(this).data('datatable-reload-success');
1532
1533        if (!disabled) {
1534            openModal(url, '', modalTitle, modalSize, modalClass, submitLabel, submitId, hideClose, successDataTable);
1535        }
1536    });
1537
1538    // define modal close reset action
1539    jQuery('#modalAjax').on('hidden.bs.modal', function (e) {
1540        if (jQuery(this).hasClass('modal-feature-highlights')) {
1541            var dismissForVersion = jQuery('#cbFeatureHighlightsDismissForVersion').is(':checked');
1542            WHMCS.http.jqClient.post(
1543                'whatsnew.php',
1544                {
1545                    dismiss: "1",
1546                    until_next_update: dismissForVersion ? '1' : '0',
1547                    token: csrfToken
1548                }
1549            );
1550        }
1551
1552        jQuery('#modalAjax').find('.modal-body').empty();
1553        jQuery('#modalAjax').children('div.modal-dialog').removeClass('modal-lg');
1554        jQuery('#modalAjax').removeClass().addClass('modal whmcs-modal fade');
1555        jQuery('#modalAjax .modal-title').html('Title');
1556        jQuery('#modalAjax .modal-submit').html('Submit')
1557            .removeClass()
1558            .addClass('btn btn-primary modal-submit')
1559            .removeAttr('id')
1560            .removeAttr('disabled');
1561        jQuery('#modalAjax .loader').show();
1562    });
1563});
1564
1565function openModal(url, postData, modalTitle, modalSize, modalClass, submitLabel, submitId, hideClose, successDataTable) {
1566    //set the text of the modal title
1567    jQuery('#modalAjax .modal-title').html(modalTitle);
1568
1569    // set the modal size via a class attribute
1570    if (modalSize) {
1571        jQuery('#modalAjax').children('div[class="modal-dialog"]').addClass(modalSize);
1572    }
1573    // set the modal class
1574    if (modalClass) {
1575        jQuery('#modalAjax').addClass(modalClass);
1576    }
1577
1578    // set the modal class
1579    if (modalClass) {
1580        jQuery('#modalAjax').addClass(modalClass);
1581    }
1582
1583    // set the text of the submit button
1584    if(!submitLabel){
1585       jQuery('#modalAjax .modal-submit').hide();
1586    } else {
1587        jQuery('#modalAjax .modal-submit').show().html(submitLabel);
1588        // set the button id so we can target the click function of it.
1589        if (submitId) {
1590            jQuery('#modalAjax .modal-submit').attr('id', submitId);
1591        }
1592    }
1593
1594    if (hideClose) {
1595        jQuery('#modalAjaxClose').hide();
1596    }
1597
1598    jQuery('#modalAjax .modal-body').html('');
1599
1600    jQuery('#modalSkip').hide();
1601    jQuery('#modalAjax .modal-submit').prop('disabled', true);
1602
1603    // show modal
1604    jQuery('#modalAjax').modal('show');
1605
1606    // fetch modal content
1607    WHMCS.http.jqClient.post(url, postData, function(data) {
1608        updateAjaxModal(data);
1609    }, 'json').fail(function() {
1610        jQuery('#modalAjax .modal-body').html('An error occurred while communicating with the server. Please try again.');
1611        jQuery('#modalAjax .loader').fadeOut();
1612    });
1613
1614    //define modal submit button click
1615    if (submitId) {
1616        /**
1617         * Reloading ajax modal multiple times on the same page can add
1618         * multiple "on" click events which submits the same form over
1619         * and over.
1620         * Remove the on click event with "off" to avoid multiple growl
1621         * and save events being run.
1622         *
1623         * @see http://api.jquery.com/off/
1624         */
1625        var submitButton = jQuery('#' + submitId);
1626        submitButton.off('click');
1627        submitButton.on('click', function() {
1628            var modalForm = jQuery('#modalAjax').find('form');
1629            jQuery('#modalAjax .loader').show();
1630            var modalPost = WHMCS.http.jqClient.post(
1631                modalForm.attr('action'),
1632                modalForm.serialize(),
1633                function(data) {
1634                    if (successDataTable) {
1635                        data.successDataTable = successDataTable;
1636                    }
1637                    updateAjaxModal(data);
1638                },
1639                'json'
1640            ).fail(function(xhr) {
1641                var data = xhr.responseJSON;
1642                var genericErrorMsg = 'An error occurred while communicating with the server. Please try again.';
1643                if (data && data.data) {
1644                    data = data.data;
1645                    if (data.errorMsg) {
1646                        jQuery.growl.warning({ title: data.errorMsgTitle, message: data.errorMsg });
1647                    } else if (data.data.body) {
1648                        jQuery('#modalAjax .modal-body').html(data.body);
1649                    } else {
1650                        jQuery('#modalAjax .modal-body').html(genericErrorMsg);
1651                    }
1652                } else {
1653                    jQuery('#modalAjax .modal-body').html(genericErrorMsg);
1654                }
1655                jQuery('#modalAjax .loader').fadeOut();
1656            });
1657        })
1658    }
1659}
1660
1661function updateAjaxModal(data) {
1662    if (data.successDataTable) {
1663        WHMCS.ui.dataTable.getTableById(data.successDataTable, undefined).ajax.reload();
1664    }
1665    if (data.dismiss) {
1666        dialogClose();
1667    }
1668    if (data.successMsg) {
1669        jQuery.growl.notice({ title: data.successMsgTitle, message: data.successMsg });
1670    }
1671    if (data.errorMsg) {
1672        jQuery.growl.warning({ title: data.errorMsgTitle, message: data.errorMsg });
1673    }
1674    if (data.title) {
1675        jQuery('#modalAjax .modal-title').html(data.title);
1676    }
1677    if (data.body) {
1678        jQuery('#modalAjax .modal-body').html(data.body);
1679    } else {
1680        if (data.url) {
1681            WHMCS.http.jqClient.post(data.url, '', function(data2) {
1682                jQuery('#modalAjax').find('.modal-body').html(data2.body);
1683            }, 'json').fail(function() {
1684                jQuery('#modalAjax').find('.modal-body').html('An error occurred while communicating with the server. Please try again.');
1685                jQuery('#modalAjax').find('.loader').fadeOut();
1686            });
1687        }
1688    }
1689    if (data.submitlabel) {
1690        jQuery('#modalAjax .modal-submit').html(data.submitlabel).show();
1691        if (data.submitId) {
1692            jQuery('#modalAjax').find('.modal-submit').attr('id', data.submitId);
1693        }
1694    }
1695
1696    if (data.submitId) {
1697        /**
1698         * Reloading ajax modal multiple times on the same page can add
1699         * multiple "on" click events which submits the same form over
1700         * and over.
1701         * Remove the on click event with "off" to avoid multiple growl
1702         * and save events being run.
1703         *
1704         * @see http://api.jquery.com/off/
1705         */
1706        var submitButton = jQuery('#' + data.submitId);
1707        submitButton.off('click');
1708        submitButton.on('click', function() {
1709            var modalForm = jQuery('#modalAjax').find('form');
1710            jQuery('#modalAjax .loader').show();
1711            var modalPost = WHMCS.http.jqClient.post(modalForm.attr('action'), modalForm.serialize(),
1712                function(data) {
1713                    updateAjaxModal(data);
1714                }, 'json').fail(function() {
1715                    jQuery('#modalAjax .modal-body').html('An error occurred while communicating with the server. Please try again.');
1716                    jQuery('#modalAjax .loader').fadeOut();
1717                }
1718            );
1719        })
1720    }
1721
1722    jQuery('#modalAjax .loader').fadeOut();
1723    jQuery('#modalAjax .modal-submit').removeProp('disabled');
1724}
1725
1726// backwards compat for older dialog implementations
1727
1728function dialogSubmit() {
1729    jQuery('#modalAjax .modal-submit').prop("disabled", true);
1730    jQuery('#modalAjax .loader').show();
1731    WHMCS.http.jqClient.post('', jQuery('#modalAjax').find('form').serialize(),
1732        function(data) {
1733            updateAjaxModal(data);
1734        }, 'json').fail(function() {
1735            jQuery('#modalAjax .modal-body').html('An error occurred while communicating with the server. Please try again.');
1736            jQuery('#modalAjax .loader').fadeOut();
1737        });
1738}
1739
1740function dialogClose() {
1741    jQuery('#modalAjax').modal('hide');
1742}
1743
1744
1745
1746
1747jQuery(document).ready(function() {
1748
1749    /**
1750     * Code will loop through each element that has the class markdown-editor and
1751     * enable the Markdown editor.
1752     */
1753    var count = 0,
1754        editorName = 'clientMDE',
1755        counter = 0;
1756    jQuery(".markdown-editor").each(function( index ) {
1757        count++;
1758        var autoSaveName = jQuery(this).data('auto-save-name'),
1759            footerId = jQuery(this).attr('id') + '-footer';
1760        if (typeof autoSaveName == "undefined") {
1761            autoSaveName = 'client_area';
1762        }
1763        window[editorName + count.toString()] = jQuery(this).markdown(
1764        {
1765            footer: '<div id="' + footerId + '" class="markdown-editor-status"></div>',
1766            autofocus: false,
1767            savable: false,
1768            resize: 'vertical',
1769            iconlibrary: 'fa',
1770            language: locale,
1771            onShow: function(e){
1772                var content = '',
1773                    save_enabled = false;
1774                if(typeof(Storage) !== "undefined") {
1775                    // Code for localStorage/sessionStorage.
1776                    content = localStorage.getItem(autoSaveName);
1777                    save_enabled = true;
1778                    if (content && typeof(content) !== "undefined") {
1779                        e.setContent(content);
1780                    }
1781                }
1782                jQuery("#" + footerId).html(parseMdeFooter(content, save_enabled, saved));
1783            },
1784            onChange: function(e){
1785                var content = e.getContent(),
1786                    save_enabled = false;
1787                if(typeof(Storage) !== "undefined") {
1788                    counter = 3;
1789                    save_enabled = true;
1790                    localStorage.setItem(autoSaveName, content);
1791                    doCountdown();
1792                }
1793                jQuery("#" + footerId).html(parseMdeFooter(content, save_enabled));
1794            },
1795            onPreview: function(e){
1796                var originalContent = e.getContent(),
1797                    parsedContent;
1798
1799                jQuery.ajax({
1800                    url: 'clientarea.php',
1801                    async: false,
1802                    data: {token: csrfToken, action: 'parseMarkdown', content: originalContent},
1803                    dataType: 'json',
1804                    success: function (data) {
1805                        parsedContent = data;
1806                    }
1807                });
1808
1809                return parsedContent.body ? parsedContent.body : '';
1810            },
1811            additionalButtons: [
1812                [{
1813                    name: "groupCustom",
1814                    data: [{
1815                        name: "cmdHelp",
1816                        title: "Help",
1817                        hotkey: "Ctrl+F1",
1818                        btnClass: "btn open-modal",
1819                        icon: {
1820                            glyph: 'glyphicons glyphicons-question-sign',
1821                            fa: 'fa fa-question-circle',
1822                            'fa-3': 'icon-question-sign'
1823                        },
1824                        callback: function(e) {
1825                            e.$editor.removeClass("md-fullscreen-mode");
1826                        }
1827                    }]
1828                }]
1829            ],
1830            hiddenButtons: [
1831                'cmdImage'
1832            ]
1833        });
1834        jQuery('button[data-handler="bootstrap-markdown-cmdHelp"]')
1835            .attr('data-modal-title', markdownGuide)
1836            .attr('href', 'submitticket.php?action=markdown');
1837
1838        jQuery(this).closest("form").bind({
1839            submit: function() {
1840                if(typeof(Storage) !== "undefined") {
1841                    localStorage.removeItem(autoSaveName);
1842                }
1843            }
1844        });
1845    });
1846
1847    // Email verification
1848    jQuery('#btnResendVerificationEmail').click(function() {
1849        WHMCS.http.jqClient.post('clientarea.php',
1850            {
1851                'token': csrfToken,
1852                'action': 'resendVerificationEmail'
1853            }).done(function(data) {
1854                jQuery('#btnResendVerificationEmail').html('Email Sent').prop('disabled', true);
1855            });
1856    });
1857
1858    /**
1859     * Parse the content to populate the markdown editor footer.
1860     *
1861     * @param {string} content
1862     * @param {bool} auto_save
1863     * @param {string} [saveText]
1864     * @returns {string}
1865     */
1866    function parseMdeFooter(content, auto_save, saveText)
1867    {
1868        saveText = saveText || saving;
1869        var pattern = /[a-zA-Z0-9_\u0392-\u03c9]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g,
1870            m = [],
1871            word_count = 0,
1872            line_count = 0;
1873        if (content) {
1874            m = content.match(pattern);
1875            line_count = content.split(/\\r\\n|\\r|\\n/).length;
1876        }
1877        for(var i = 0; i < m.length; i++) {
1878            if(m[i].charCodeAt(0) >= 0x4E00) {
1879                word_count += m[i].length;
1880            } else {
1881                word_count += 1;
1882            }
1883        }
1884        return '<div class="small-font">lines: ' + line_count
1885            + '&nbsp;&nbsp;&nbsp;words: ' + word_count + ''
1886            + (auto_save ? '&nbsp;&nbsp;&nbsp;<span class="markdown-save">' + saveText + '</span>' : '')
1887            + '</div>';
1888    }
1889
1890    /**
1891     * Countdown the save timeout. When zero, the span will update to show saved.
1892     */
1893    function doCountdown()
1894    {
1895        if (counter >= 0) {
1896            if (counter == 0) {
1897                jQuery("span.markdown-save").html(saved);
1898            }
1899            counter--;
1900            setTimeout(doCountdown, 1000);
1901        }
1902    }
1903
1904    // Two-Factor Activation Process Modal Handler.
1905    var frmTwoFactorActivation = jQuery('input[name=2fasetup]').parent('form');
1906    frmTwoFactorActivation.submit(function(e) {
1907        e.preventDefault();
1908        openModal(frmTwoFactorActivation.attr('action'), frmTwoFactorActivation.serialize(), 'Loading...');
1909    });
1910
1911    jQuery('#frmPayment').find('#btnSubmit').on('click', function(){
1912        jQuery(this).find('span').toggleClass('hidden');
1913    });
1914    // SSL Manage Action Button.
1915jQuery('.btn-resend-approver-email').click(function () {
1916        WHMCS.http.jqClient.post(
1917        jQuery(this).data('url'),
1918        {
1919            addonId: jQuery(this).data('addonid'),
1920            serviceId: jQuery(this).data('serviceid'),
1921        },
1922        function(data) {
1923            if (data.success == true) {
1924                jQuery('.alert-table-ssl-manage').addClass('alert-success').text('Approver Email Resent').removeClass('hidden');
1925            } else {
1926                jQuery('.alert-table-ssl-manage').addClass('alert-danger').text('Error: ' + data.message).removeClass('hidden');
1927            }
1928        }
1929    );
1930});
1931
1932    // Domain Pricing Table Filters
1933    jQuery(".tld-filters a").click(function(e) {
1934        e.preventDefault();
1935
1936        if (jQuery(this).hasClass('label-success')) {
1937            jQuery(this).removeClass('label-success');
1938        } else {
1939            jQuery(this).addClass('label-success');
1940        }
1941
1942        jQuery('.tld-row').removeClass('filtered-row');
1943        jQuery('.tld-filters a.label-success').each(function(index) {
1944            var filterValue = jQuery(this).data('category');
1945            jQuery('.tld-row[data-category*="' + filterValue + '"]').addClass('filtered-row');
1946        });
1947        jQuery(".filtered-row:even").removeClass('highlighted');
1948        jQuery(".filtered-row:odd").addClass('highlighted');
1949        jQuery('.tld-row:not(".filtered-row")').fadeOut('', function() {
1950            if (jQuery('.filtered-row').size() === 0) {
1951                jQuery('.tld-row.no-tlds').show();
1952            } else {
1953                jQuery('.tld-row.no-tlds').hide();
1954            }
1955        });
1956        jQuery('.tld-row.filtered-row').fadeIn();
1957    });
1958    jQuery(".filtered-row:even").removeClass('highlighted');
1959    jQuery(".filtered-row:odd").addClass('highlighted');
1960
1961// DataTable data-driven auto object registration
1962WHMCS.ui.dataTable.register();
1963
1964// Bootstrap Confirmation popup auto object registration
1965WHMCS.ui.confirmation.register();
1966
1967jQuery('#frmReply').submit(function(e) {
1968    jQuery('#frmReply').find('input[type="submit"]').addClass('disabled').prop('disabled', true);
1969  });
1970
1971jQuery('#frmDomainContactModification').on('submit', function(){
1972  if (!allowSubmit) {
1973      var changed = false;
1974      jQuery('.irtp-field').each(function() {
1975          var value = jQuery(this).val(),
1976              originalValue = jQuery(this).data('original-value');
1977          if (value !== originalValue) {
1978              changed = true;
1979          }
1980      });
1981      if (changed) {
1982          jQuery('#modalIRTPConfirmation').modal('show');
1983          return false;
1984      }
1985  }
1986  return true;
1987});
1988});
1989
1990/**
1991 * WHMCS Telephone Country Code Dropdown
1992 *
1993 * Using https://github.com/jackocnr/intl-tel-input
1994 *
1995 * @copyright Copyright (c) WHMCS Limited 2005-2017
1996 * @license http://www.whmcs.com/license/ WHMCS Eula
1997 */
1998
1999jQuery(document).ready(function() {
2000    if (jQuery('body').data('phone-cc-input')) {
2001        var phoneInput = jQuery('input[name^="phone"], input[name$="phone"]').not('input[type="hidden"]');
2002        if (phoneInput.length) {
2003            var countryInput = jQuery('[name^="country"], [name$="country"]'),
2004                initialCountry = 'us';
2005            if (countryInput.length) {
2006                initialCountry = countryInput.val().toLowerCase();
2007                if (initialCountry === 'um') {
2008                    initialCountry = 'us';
2009                }
2010            }
2011
2012            phoneInput.each(function(){
2013                var thisInput = jQuery(this),
2014                    inputName = thisInput.attr('name');
2015                jQuery(this).before(
2016                    '<input id="populatedCountryCode' + inputName + '" type="hidden" name="country-calling-code-' + inputName + '" value="" />'
2017                );
2018                thisInput.intlTelInput({
2019                    preferredCountries: [initialCountry, "us", "gb"].filter(function(value, index, self) {
2020                        return self.indexOf(value) === index;
2021                    }),
2022                    initialCountry: initialCountry,
2023                    autoPlaceholder: 'polite', //always show the helper placeholder
2024                    separateDialCode: true
2025                });
2026
2027                thisInput.on('countrychange', function (e, countryData) {
2028                    jQuery('#populatedCountryCode' + inputName).val(countryData.dialCode);
2029                    if (jQuery(this).val() === '+' + countryData.dialCode) {
2030                        jQuery(this).val('');
2031                    }
2032                });
2033                thisInput.on('blur keydown', function (e) {
2034                    if (e.type === 'blur' || (e.type === 'keydown' && e.keyCode === 13)) {
2035                        var number = jQuery(this).intlTelInput("getNumber"),
2036                            countryData = jQuery(this).intlTelInput("getSelectedCountryData"),
2037                            countryPrefix = '+' + countryData.dialCode;
2038
2039                        if (number.indexOf(countryPrefix) === 0 && (number.match(/\+/g) || []).length > 1) {
2040                            number = number.substr(countryPrefix.length);
2041                        }
2042                        jQuery(this).intlTelInput("setNumber", number);
2043                    }
2044                });
2045                jQuery('#populatedCountryCode' + inputName).val(thisInput.intlTelInput('getSelectedCountryData').dialCode);
2046
2047                countryInput.on('change', function() {
2048                    if (thisInput.val() === '') {
2049                        var country = jQuery(this).val().toLowerCase();
2050                        if (country === 'um') {
2051                            country = 'us';
2052                        }
2053                        phoneInput.intlTelInput('setCountry', country);
2054                    }
2055                });
2056            });
2057
2058            /**
2059             * In places where a form icon is present, hide it.
2060             * Where the input has a class of field, remove that and add form-control in place.
2061             */
2062            phoneInput.parents('div.form-group').find('.field-icon').addClass('hidden').end();
2063            phoneInput.removeClass('field').addClass('form-control');
2064        }
2065
2066        var registrarPhoneInput = jQuery('input[name$="][Phone Number]"], input[name$="][Phone]"]').not('input[type="hidden"]');
2067        if (registrarPhoneInput.length) {
2068            jQuery.each(registrarPhoneInput, function(index, input) {
2069                var thisInput = jQuery(this),
2070                    inputName = thisInput.attr('name');
2071                inputName = inputName.replace('contactdetails[', '').replace('][Phone Number]', '').replace('][Phone]', '');
2072
2073                var countryInput = jQuery('[name$="' + inputName + '][Country]"]'),
2074                    initialCountry = countryInput.val().toLowerCase();
2075                if (initialCountry === 'um') {
2076                    initialCountry = 'us';
2077                }
2078
2079                thisInput.before('<input id="populated' + inputName + 'CountryCode" type="hidden" name="contactdetails[' + inputName + '][Phone Country Code]" value="" />');
2080                thisInput.intlTelInput({
2081                    preferredCountries: [initialCountry, "us", "gb"].filter(function(value, index, self) {
2082                        return self.indexOf(value) === index;
2083                    }),
2084                    initialCountry: initialCountry,
2085                    autoPlaceholder: 'polite', //always show the helper placeholder
2086                    separateDialCode: true
2087                });
2088
2089                thisInput.on('countrychange', function (e, countryData) {
2090                    jQuery('#populated' + inputName + 'CountryCode').val(countryData.dialCode);
2091                    if (jQuery(this).val() === '+' + countryData.dialCode) {
2092                        jQuery(this).val('');
2093                    }
2094                });
2095                thisInput.on('blur keydown', function (e) {
2096                    if (e.type === 'blur' || (e.type === 'keydown' && e.keyCode === 13)) {
2097                        var number = jQuery(this).intlTelInput("getNumber"),
2098                            countryData = jQuery(this).intlTelInput("get
2098SelectedCountryData"),
2099                            countryPrefix = '+' + countryData.dialCode;
2100
2101                        if (number.indexOf(countryPrefix) === 0 && (number.match(/\+/g) || []).length > 1) {
2102                            number = number.substr(countryPrefix.length);
2103                        }
2104                        jQuery(this).intlTelInput("setNumber", number);
2105                    }
2106                });
2107                jQuery('#populated' + inputName + 'CountryCode').val(thisInput.intlTelInput('getSelectedCountryData').dialCode);
2108
2109                countryInput.on('blur', function() {
2110                    if (thisInput.val() === '') {
2111                        var country = jQuery(this).val().toLowerCase();
2112                        if (country === 'um') {
2113                            country = 'us';
2114                        }
2115                        thisInput.intlTelInput('setCountry', country);
2116                    }
2117                });
2118
2119            });
2120        }
2121    }
2122});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.