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 + ' words: ' + word_count + '' 1886 + (auto_save ? ' <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.