whmcs.js 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  1. /*!
  2. * WHMCS Twenty-One Theme
  3. * Global Javascript
  4. * Copyright (c) 2020 WHMCS Limited
  5. * https://www.whmcs.com/license/
  6. */
  7. jQuery(document).ready(function() {
  8. // when the page loads
  9. autoCollapse('#nav', 30);
  10. if (jQuery('#lightbox').length === 0) {
  11. lightbox.init();
  12. }
  13. // when the window is resized
  14. jQuery(window).on('resize', function () {
  15. if (jQuery('button[data-target="#mainNavbar"], button[data-toggle="collapse"]').is(':visible')) {
  16. return;
  17. }
  18. autoCollapse('#nav', 30);
  19. });
  20. // Item selector
  21. jQuery('.item-selector .item').click(function(e) {
  22. e.preventDefault();
  23. jQuery(this).closest('.item-selector').find('.item').removeClass('active').end()
  24. .find('input').val(jQuery(this).data('value'));
  25. jQuery(this).addClass('active');
  26. });
  27. // Password reveal
  28. jQuery(document).on('click', '.btn-reveal-pw', function (e) {
  29. $targetField = jQuery(this).closest('.input-group').find('.pw-input');
  30. if ($targetField.attr('type') == 'password') {
  31. $targetField.attr('type', 'text');
  32. } else {
  33. $targetField.attr('type', 'password');
  34. }
  35. });
  36. // Account notifications popover
  37. jQuery("#accountNotifications").popover({
  38. container: 'body',
  39. placement: 'bottom',
  40. template: '<div class="popover popover-user-notifications" role="tooltip"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-header"></h3><div class="popover-body"><p></p></div></div></div>',
  41. html: true,
  42. content: function() {
  43. return jQuery("#accountNotificationsContent").html();
  44. },
  45. });
  46. jQuery('.card-sidebar .truncate').each(function () {
  47. jQuery(this).attr('title', jQuery(this).text())
  48. .attr('data-toggle', 'tooltip')
  49. .attr('data-placement', 'bottom');
  50. });
  51. // Default catch for all other popovers
  52. jQuery('[data-toggle="popover"]').popover({
  53. html: true
  54. });
  55. // Enable tooltips
  56. // Attach function to body so tooltips inserted by ajax will load
  57. jQuery(function(jQuery){
  58. jQuery('body').tooltip({
  59. selector: '[data-toggle="tooltip"]'
  60. });
  61. });
  62. // Logic to dismiss popovers on click outside
  63. jQuery('body').on('click', function (e) {
  64. jQuery('[data-toggle="popover"]').each(function () {
  65. if (!jQuery(this).is(e.target) && jQuery(this).has(e.target).length === 0 && jQuery('.popover').has(e.target).length === 0) {
  66. jQuery(this).popover('hide');
  67. }
  68. });
  69. });
  70. // Sidebar active class toggle
  71. jQuery(".list-group-tab-nav a").click(function() {
  72. if (jQuery(this).hasClass('disabled')) {
  73. return false;
  74. }
  75. var urlFragment = this.href.split('#')[1];
  76. if (urlFragment) {
  77. // set the fragment in the URL bar for bookmarking and such.
  78. window.location.hash = '#' + urlFragment;
  79. }
  80. });
  81. // Sidebar minimise/maximise
  82. jQuery('.card-minimise').click(function(e) {
  83. e.preventDefault();
  84. var collapsableBody = jQuery(this).closest('.card').find('.collapsable-card-body');
  85. if (jQuery(this).hasClass('minimised')) {
  86. collapsableBody.slideDown();
  87. jQuery(this).removeClass('minimised');
  88. } else {
  89. collapsableBody.slideUp();
  90. jQuery(this).addClass('minimised');
  91. }
  92. });
  93. // Minimise sidebar panels by default on small devices
  94. if (jQuery('.container').width() <= 720) {
  95. jQuery('.card-sidebar').find('.collapsable-card-body').hide().end()
  96. .find('.card-minimise').addClass('minimised');
  97. }
  98. // Internal page tab selection handling via location hash
  99. var internalSelectionDisabled = false;
  100. if (
  101. typeof(disableInternalTabSelection) !== 'undefined'
  102. &&
  103. disableInternalTabSelection
  104. ) {
  105. internalSelectionDisabled = true;
  106. }
  107. if (!internalSelectionDisabled) {
  108. if (jQuery(location).attr('hash').substr(1) !== "") {
  109. var activeTab = jQuery(location).attr('hash');
  110. jQuery(".primary-content > .tab-content > .tab-pane").removeClass('active');
  111. jQuery(activeTab).removeClass('fade').addClass('active');
  112. jQuery(".list-group-tab-nav a").removeClass('active');
  113. jQuery('a[href="' + activeTab + '"]').addClass('active');
  114. setTimeout(function() {
  115. // Browsers automatically scroll on page load with a fragment.
  116. // This scrolls back to the top right after page complete, but
  117. // just before render (no perceptible scroll).
  118. window.scrollTo(0, 0);
  119. }, 1);
  120. }
  121. }
  122. // Enable Switches for Checkboxes
  123. if (jQuery.prototype.bootstrapSwitch) {
  124. jQuery(".toggle-switch-success").bootstrapSwitch({
  125. onColor: 'success'
  126. });
  127. }
  128. // Collapsable Panels
  129. jQuery(".panel-collapsable .card-header").click(function(e) {
  130. var $this = jQuery(this);
  131. if (!$this.closest('.card').hasClass('panel-collapsed')) {
  132. $this.closest('.card').addClass('panel-collapsed').find('.card-body').slideUp();
  133. $this.find('.collapse-icon i').removeClass('fa-minus').addClass('fa-plus');
  134. } else {
  135. $this.closest('.card').removeClass('panel-collapsed').find('.card-body').slideDown();
  136. $this.find('.collapse-icon i').removeClass('fa-plus').addClass('fa-minus');
  137. }
  138. });
  139. // Two-Factor Authentication Auto Focus Rules
  140. if (("#frmLogin").length > 0) {
  141. jQuery("#frmLogin input:text:visible:first").focus();
  142. }
  143. if (("#twofaactivation").length > 0) {
  144. jQuery("#twofaactivation input:text:visible:first,#twofaactivation input:password:visible:first").focus();
  145. }
  146. // Sub-Account Activation Toggle
  147. jQuery("#inputSubaccountActivate").click(function () {
  148. if (jQuery("#inputSubaccountActivate:checked").val() != null) {
  149. jQuery("#subacct-container").show();
  150. } else {
  151. jQuery("#subacct-container").hide();
  152. }
  153. });
  154. // Mass Domain Management Bulk Action Handling
  155. jQuery(".setBulkAction").click(function(event) {
  156. event.preventDefault();
  157. var id = jQuery(this).attr('id').replace('Link', ''),
  158. domainForm = jQuery('#domainForm');
  159. if (id === 'renewDomains') {
  160. domainForm.attr('action', WHMCS.utils.getRouteUrl('/cart/domain/renew'));
  161. } else {
  162. if (jQuery('#' + id).length !== 0) {
  163. var action = domainForm.attr('action');
  164. domainForm.attr('action', action + '#' + id);
  165. }
  166. jQuery('#bulkaction').val(id);
  167. }
  168. domainForm.submit();
  169. });
  170. // Stop events on objects with this class from bubbling up the dom
  171. jQuery('.stopEventBubble').click( function(event) {
  172. event.stopPropagation();
  173. });
  174. // Tab Control Link handling for tab switching via regular links
  175. jQuery('.tabControlLink').on(
  176. 'click',
  177. function(event) {
  178. event.preventDefault();
  179. var id = jQuery(this).attr('href');
  180. jQuery("a[href='/"+id+"']").click();
  181. }
  182. );
  183. jQuery(document).on('click', '.delete-cc-email', function() {
  184. var self = jQuery(this),
  185. email = self.data('email'),
  186. feedback = jQuery('#divCcEmailFeedback');
  187. if (feedback.is(':visible')) {
  188. feedback.slideUp('fast');
  189. }
  190. WHMCS.http.jqClient.jsonPost({
  191. url: window.location.href,
  192. data: {
  193. action: 'delete',
  194. email: email,
  195. token: csrfToken
  196. },
  197. success: function (data) {
  198. if (data.success) {
  199. self.closest('.ticket-cc-email').parent('div').slideUp('fast').remove();
  200. feedback.removeClass('alert-danger')
  201. .addClass('alert-success')
  202. .html(data.message)
  203. .slideDown('fast');
  204. }
  205. },
  206. error: function (error) {
  207. if (error) {
  208. feedback.removeClass('alert-success')
  209. .addClass('alert-danger')
  210. .html(error)
  211. .slideDown('fast');
  212. }
  213. }
  214. });
  215. }).on('submit', '#frmAddCcEmail', function(e) {
  216. e.preventDefault();
  217. var frm = jQuery(this),
  218. cloneRow = jQuery('#ccCloneRow').clone().removeAttr('id'),
  219. email = jQuery('#inputAddCcEmail'),
  220. feedback = jQuery('#divCcEmailFeedback');
  221. if (feedback.is(':visible')) {
  222. feedback.slideUp('fast');
  223. }
  224. WHMCS.http.jqClient.jsonPost({
  225. url: frm.attr('action'),
  226. data: frm.serialize(),
  227. success: function (data) {
  228. if (data.success) {
  229. cloneRow.find('span.email')
  230. .html(email.val())
  231. .find('button')
  232. .data('email', email.val())
  233. .end();
  234. cloneRow.show()
  235. .appendTo(jQuery('#sidebarTicketCc').find('.list-group'));
  236. email.val('');
  237. feedback.slideUp('fast')
  238. .removeClass('alert-danger hidden')
  239. .addClass('alert-success')
  240. .html(data.message)
  241. .slideDown('fast');
  242. }
  243. },
  244. error: function (error) {
  245. if (error) {
  246. feedback.slideUp('fast')
  247. .removeClass('alert-success hidden')
  248. .addClass('alert-danger')
  249. .html(error)
  250. .slideDown('fast');
  251. }
  252. }
  253. });
  254. });
  255. // Ticket Rating Click Handler
  256. jQuery('.ticket-reply .rating span.star').click( function(event) {
  257. window.location = 'viewticket.php?tid='
  258. + jQuery(this).parent('.rating').attr("ticketid")
  259. + '&c=' + jQuery(this).parent('.rating').attr("ticketkey")
  260. + '&rating=rate' + jQuery(this).parent('.rating').attr("ticketreplyid")
  261. + '_' + jQuery(this).attr("rate");
  262. });
  263. // Prevent malicious window.opener activity from auto-linked URLs
  264. jQuery('a.autoLinked').click(function (e) {
  265. e.preventDefault();
  266. if (jQuery(this).hasClass('disabled')) {
  267. return false;
  268. }
  269. var child = window.open();
  270. child.opener = null;
  271. child.location = e.target.href;
  272. });
  273. // Handle Single Sign-On Toggle Setting
  274. jQuery("#inputAllowSso").on('switchChange.bootstrapSwitch', function(event, isChecked) {
  275. if (isChecked) {
  276. jQuery("#ssoStatusTextEnabled").show();
  277. jQuery("#ssoStatusTextDisabled").hide();
  278. } else {
  279. jQuery("#ssoStatusTextDisabled").show();
  280. jQuery("#ssoStatusTextEnabled").hide();
  281. }
  282. WHMCS.http.jqClient.post("clientarea.php", jQuery("#frmSingleSignOn").serialize());
  283. });
  284. // Single Sign-On call for Product/Service
  285. jQuery('.btn-service-sso').on('click', function(e) {
  286. e.preventDefault();
  287. var button = jQuery(this);
  288. var form = button.closest('form');
  289. if (form.length === 0) {
  290. form = button.find('form');
  291. }
  292. if (form.hasClass('disabled') || button.hasClass('disabled')) {
  293. return;
  294. }
  295. var url = form.data('href');
  296. if (!url) {
  297. url = window.location.href;
  298. }
  299. button.attr('disabled', 'disabled').addClass('disabled');
  300. jQuery('.loading', button).show().end();
  301. jQuery('.login-feedback', form).slideUp();
  302. WHMCS.http.jqClient.post(
  303. url,
  304. form.serialize(),
  305. function (data) {
  306. jQuery('.loading', button).hide().end().removeAttr('disabled');
  307. jQuery('.login-feedback', form).html('');
  308. if (data.error) {
  309. jQuery('.login-feedback', form).hide().html(data.error).slideDown();
  310. }
  311. if (data.redirect !== undefined && data.redirect.substr(0, 7) === 'window|') {
  312. window.open(data.redirect.substr(7), '_blank');
  313. }
  314. },
  315. 'json'
  316. ).always(function() {
  317. button.removeAttr('disabled').removeClass('disabled');
  318. button.find('.loading').hide().end();
  319. });
  320. });
  321. jQuery('.btn-sidebar-form-submit').on('click', function(e) {
  322. e.preventDefault();
  323. jQuery(this).find('.loading').show().end()
  324. .attr('disabled', 'disabled');
  325. var form = jQuery(this).closest('form');
  326. if (form.length === 0) {
  327. form = jQuery(this).find('form');
  328. }
  329. if (form.length !== 0 && form.hasClass('disabled') === false) {
  330. form.submit();
  331. } else {
  332. jQuery(this).find('.loading').hide().end().removeAttr('disabled');
  333. }
  334. });
  335. // Back to top animated scroll
  336. jQuery('.back-to-top').click(function(e) {
  337. e.preventDefault();
  338. jQuery('body,html').animate({scrollTop: 0}, 500);
  339. });
  340. // Prevent page scroll on language choose click
  341. jQuery('.choose-language').click(function(e) {
  342. e.preventDefault();
  343. });
  344. // Activate copy to clipboard functionality
  345. jQuery('.copy-to-clipboard').click(WHMCS.ui.clipboard.copy);
  346. // Handle Language Chooser modal
  347. jQuery('#modalChooseLanguage button[type=submit]').click(function(e) {
  348. e.preventDefault();
  349. var form = jQuery(this).closest('form');
  350. var currency = form.find('input[name="currency"]');
  351. var language = form.find('input[name="language"]');
  352. var fields = [];
  353. if (language.data('current') != language.val()) {
  354. fields.push('language=' + language.val());
  355. }
  356. if (currency.data('current') != currency.val() && currency.val() != "") {
  357. fields.push('currency=' + currency.val());
  358. }
  359. window.location.replace(form.attr('action') + fields.join('&'));
  360. });
  361. // Password Generator
  362. jQuery('.generate-password').click(function(e) {
  363. jQuery('#frmGeneratePassword').submit();
  364. jQuery('#modalGeneratePassword')
  365. .data('targetfields', jQuery(this).data('targetfields'))
  366. .modal('show');
  367. });
  368. jQuery('#frmGeneratePassword').submit(function(e) {
  369. e.preventDefault();
  370. var length = parseInt(jQuery('#inputGeneratePasswordLength').val(), 10);
  371. // Check length
  372. if (length < 8 || length > 64) {
  373. jQuery('#generatePwLengthError').show();
  374. return;
  375. }
  376. jQuery('#inputGeneratePasswordOutput').val(WHMCS.utils.generatePassword(length));
  377. });
  378. jQuery('#btnGeneratePasswordInsert')
  379. .click(WHMCS.ui.clipboard.copy)
  380. .click(function(e) {
  381. jQuery(this).closest('.modal').modal('hide');
  382. var targetFields = jQuery(this).closest('.modal').data('targetfields'),
  383. generatedPassword = jQuery('#inputGeneratePasswordOutput');
  384. targetFields = targetFields.split(',');
  385. for(var i = 0; i < targetFields.length; i++) {
  386. jQuery('#' + targetFields[i]).val(generatedPassword.val())
  387. .trigger('keyup');
  388. }
  389. // Remove the generated password.
  390. generatedPassword.val('');
  391. });
  392. /**
  393. * If we are logged into the admin area and can edit a category and click edit,
  394. * we need to stop the default and click the edit instead since its nested.
  395. */
  396. jQuery('a.card-body').click(function(e) {
  397. if (e.target.id.includes('btnEditCategory')) {
  398. e.preventDefault();
  399. var editUrl = jQuery('#btnEditCategory-' + jQuery(this).data('id')).data('url');
  400. window.location.href = editUrl;
  401. }
  402. });
  403. jQuery('.kb-article-item').click(function(e) {
  404. if (e.target.id.includes('btnEditArticle')) {
  405. e.preventDefault();
  406. var editUrl = jQuery('#btnEditArticle-' + jQuery(this).data('id')).data('url');
  407. window.location.href = editUrl;
  408. }
  409. });
  410. /**
  411. * Code will loop through each element that has the class markdown-editor and
  412. * enable the Markdown editor.
  413. */
  414. var count = 0,
  415. editorName = 'clientMDE',
  416. counter = 0;
  417. jQuery(".markdown-editor").each(function( index ) {
  418. count++;
  419. var autoSaveName = jQuery(this).data('auto-save-name'),
  420. footerId = jQuery(this).attr('id') + '-footer';
  421. if (typeof autoSaveName == "undefined") {
  422. autoSaveName = 'client_area';
  423. }
  424. window[editorName + count.toString()] = jQuery(this).markdown(
  425. {
  426. footer: '<div id="' + footerId + '" class="markdown-editor-status"></div>',
  427. autofocus: false,
  428. savable: false,
  429. resize: 'vertical',
  430. iconlibrary: 'fa-5',
  431. language: locale,
  432. onShow: function(e){
  433. var content = '',
  434. save_enabled = false;
  435. if(typeof(Storage) !== "undefined") {
  436. // Code for localStorage/sessionStorage.
  437. content = localStorage.getItem(autoSaveName);
  438. save_enabled = true;
  439. if (content && typeof(content) !== "undefined") {
  440. e.setContent(content);
  441. }
  442. }
  443. jQuery("#" + footerId).html(parseMdeFooter(content, save_enabled, saved));
  444. },
  445. onChange: function(e){
  446. var content = e.getContent(),
  447. save_enabled = false;
  448. if(typeof(Storage) !== "undefined") {
  449. counter = 3;
  450. save_enabled = true;
  451. localStorage.setItem(autoSaveName, content);
  452. doCountdown();
  453. }
  454. jQuery("#" + footerId).html(parseMdeFooter(content, save_enabled));
  455. },
  456. onPreview: function(e){
  457. var originalContent = e.getContent(),
  458. parsedContent;
  459. jQuery.ajax({
  460. url: WHMCS.utils.getRouteUrl('/clientarea/message/preview'),
  461. async: false,
  462. data: {token: csrfToken, content: originalContent},
  463. dataType: 'json',
  464. success: function (data) {
  465. parsedContent = data;
  466. }
  467. });
  468. return parsedContent.body ? parsedContent.body : '';
  469. },
  470. additionalButtons: [
  471. [{
  472. name: "groupCustom",
  473. data: [{
  474. name: "cmdHelp",
  475. title: "Help",
  476. hotkey: "Ctrl+F1",
  477. btnClass: "btn open-modal",
  478. icon: {
  479. glyph: 'fas fa-question-circle',
  480. fa: 'fas fa-question-circle',
  481. 'fa-3': 'icon-question-sign',
  482. 'fa-5': 'fas fa-question-circle',
  483. },
  484. callback: function(e) {
  485. e.$editor.removeClass("md-fullscreen-mode");
  486. }
  487. }]
  488. }]
  489. ],
  490. hiddenButtons: [
  491. 'cmdImage'
  492. ]
  493. });
  494. jQuery('button[data-handler="bootstrap-markdown-cmdHelp"]')
  495. .attr('data-modal-title', markdownGuide)
  496. .attr('href', 'submitticket.php?action=markdown');
  497. jQuery(this).closest("form").bind({
  498. submit: function() {
  499. if(typeof(Storage) !== "undefined") {
  500. localStorage.removeItem(autoSaveName);
  501. }
  502. }
  503. });
  504. });
  505. // Email verification
  506. var btnResendEmail = jQuery('.btn-resend-verify-email');
  507. jQuery(btnResendEmail).click(function() {
  508. $(this).prop('disabled', true).find('.loader').show();
  509. WHMCS.http.jqClient.post(
  510. jQuery(this).data('uri'),
  511. {
  512. 'token': csrfToken,
  513. }).done(function(data) {
  514. btnResendEmail.find('.loader').hide();
  515. if (data.success) {
  516. btnResendEmail.text(btnResendEmail.data('email-sent'));
  517. } else {
  518. btnResendEmail.text(btnResendEmail.data('error-msg'));
  519. }
  520. });
  521. });
  522. jQuery('#btnEmailVerificationClose').click(function(e) {
  523. e.preventDefault();
  524. WHMCS.http.jqClient.post(jQuery(this).data('uri'),
  525. {
  526. 'token': csrfToken
  527. });
  528. jQuery('.verification-banner.email-verification').hide();
  529. });
  530. jQuery('#btnUserValidationClose').click(function(e) {
  531. e.preventDefault();
  532. WHMCS.http.jqClient.post(jQuery(this).data('uri'),
  533. {
  534. 'token': csrfToken
  535. });
  536. jQuery('.verification-banner.user-validation').hide();
  537. });
  538. var ssoDropdown = jQuery('#servicesPanel').find('.list-group');
  539. if (parseInt(ssoDropdown.css('height'), 10) < parseInt(ssoDropdown.css('max-height'), 10)) {
  540. ssoDropdown.css('overflow', 'unset');
  541. }
  542. /**
  543. * Parse the content to populate the markdown editor footer.
  544. *
  545. * @param {string} content
  546. * @param {bool} auto_save
  547. * @param {string} [saveText]
  548. * @returns {string}
  549. */
  550. function parseMdeFooter(content, auto_save, saveText)
  551. {
  552. saveText = saveText || saving;
  553. var pattern = /[^\s]+/g,
  554. m = [],
  555. word_count = 0,
  556. line_count = 0;
  557. if (content) {
  558. m = content.match(pattern);
  559. line_count = content.split(/\\r\\n|\\r|\\n/).length;
  560. }
  561. if (m) {
  562. for (var i = 0; i < m.length; i++) {
  563. if (m[i].charCodeAt(0) >= 0x4E00) {
  564. word_count += m[i].length;
  565. } else {
  566. word_count += 1;
  567. }
  568. }
  569. }
  570. return '<div class="small-font">lines: ' + line_count
  571. + '&nbsp;&nbsp;&nbsp;words: ' + word_count + ''
  572. + (auto_save ? '&nbsp;&nbsp;&nbsp;<span class="markdown-save">' + saveText + '</span>' : '')
  573. + '</div>';
  574. }
  575. /**
  576. * Countdown the save timeout. When zero, the span will update to show saved.
  577. */
  578. function doCountdown()
  579. {
  580. if (counter >= 0) {
  581. if (counter === 0) {
  582. jQuery("span.markdown-save").html(saved);
  583. }
  584. counter--;
  585. setTimeout(doCountdown, 1000);
  586. }
  587. }
  588. // Two-Factor Activation Process Modal Handler.
  589. var frmTwoFactorActivation = jQuery('input[name=2fasetup]').parent('form');
  590. frmTwoFactorActivation.submit(function(e) {
  591. e.preventDefault();
  592. openModal(frmTwoFactorActivation.attr('action'), frmTwoFactorActivation.serialize(), 'Loading...');
  593. });
  594. $.fn.setInputError = function(error) {
  595. this.closest('.form-group').addClass('has-error').find('.field-error-msg').text(error);
  596. return this;
  597. };
  598. jQuery.fn.showInputError = function () {
  599. this.closest('.form-group').addClass('has-error').find('.field-error-msg').show();
  600. return this;
  601. };
  602. jQuery('#frmPayment').on('submit', function() {
  603. var btn = jQuery('#btnSubmit');
  604. btn.find('span').toggle();
  605. btn.prop('disabled', true).addClass('disabled');
  606. });
  607. // SSL Manage Action Button.
  608. jQuery('.btn-resend-approver-email').click(function () {
  609. WHMCS.http.jqClient.post(
  610. jQuery(this).data('url'),
  611. {
  612. addonId: jQuery(this).data('addonid'),
  613. serviceId: jQuery(this).data('serviceid'),
  614. },
  615. function(data) {
  616. if (data.success === true) {
  617. jQuery('.alert-table-ssl-manage').addClass('alert-success').text('Approver Email Resent').show();
  618. } else {
  619. jQuery('.alert-table-ssl-manage').addClass('alert-danger').text('Error: ' + data.message).show();
  620. }
  621. }
  622. );
  623. });
  624. // Domain Pricing Table Filters
  625. jQuery(".tld-filters a").click(function(e) {
  626. e.preventDefault();
  627. var noTlds = jQuery('.tld-row.no-tlds');
  628. if (jQuery(this).hasClass('badge-success')) {
  629. jQuery(this).removeClass('badge-success');
  630. } else {
  631. jQuery(this).addClass('badge-success');
  632. }
  633. if (noTlds.is(':visible')) {
  634. noTlds.hide();
  635. }
  636. jQuery('.tld-row').removeClass('filtered-row');
  637. jQuery('.tld-filters a.badge-success').each(function(index) {
  638. var filterValue = jQuery(this).data('category');
  639. jQuery('.tld-row[data-category*="' + filterValue + '"]').addClass('filtered-row');
  640. });
  641. jQuery(".filtered-row:even").removeClass('highlighted');
  642. jQuery(".filtered-row:odd").addClass('highlighted');
  643. var rowsToHide = jQuery('.tld-row:not(".filtered-row")');
  644. rowsToHide.fadeOut('fast');
  645. rowsToHide.promise().done(function () {
  646. if (jQuery('.filtered-row').length === 0) {
  647. noTlds.show();
  648. } else {
  649. jQuery('.tld-row.filtered-row').show();
  650. }
  651. });
  652. });
  653. jQuery(".filtered-row:even").removeClass('highlighted');
  654. jQuery(".filtered-row:odd").addClass('highlighted');
  655. // DataTable data-driven auto object registration
  656. WHMCS.ui.dataTable.register();
  657. WHMCS.ui.jsonForm.initAll();
  658. jQuery(document).on('click', '#btnTicketAttachmentsAdd', function() {
  659. jQuery('#fileUploadsContainer').append(jQuery('.file-upload').html());
  660. });
  661. jQuery(document).on('change', '.custom-file-input', function() {
  662. var fileName = jQuery(this).val().split('\\').pop();
  663. jQuery(this).siblings('.custom-file-label').text(fileName);
  664. });
  665. jQuery('#frmReply').submit(function(e) {
  666. jQuery('#frmReply').find('input[type="submit"]').addClass('disabled').prop('disabled', true);
  667. });
  668. jQuery('#frmDomainContactModification').on('submit', function(){
  669. if (!allowSubmit) {
  670. var changed = false;
  671. jQuery('.irtp-field').each(function() {
  672. var value = jQuery(this).val(),
  673. originalValue = jQuery(this).data('original-value');
  674. if (value !== originalValue) {
  675. changed = true;
  676. }
  677. });
  678. if (changed) {
  679. jQuery('#modalIRTPConfirmation').modal('show');
  680. return false;
  681. }
  682. }
  683. return true;
  684. });
  685. jQuery('.ssl-state.ssl-sync').each(function () {
  686. var self = jQuery(this),
  687. type = getSslAttribute(self, 'type'),
  688. domain = getSslAttribute(self, 'domain');
  689. WHMCS.http.jqClient.post(
  690. WHMCS.utils.getRouteUrl('/domain/ssl-check'),
  691. {
  692. 'type': type,
  693. 'domain': domain,
  694. 'token': csrfToken
  695. },
  696. function (data) {
  697. if (data.invalid) {
  698. self.hide();
  699. } else {
  700. var width = '',
  701. statusDisplayLabel = '';
  702. if (self.attr('width')) {
  703. width = ' width="' + self.attr('width') + '"';
  704. }
  705. if (self.data('showlabel')) {
  706. statusDisplayLabel = ' ' + data.statusDisplayLabel;
  707. }
  708. self.replaceWith(
  709. '<img src="' + data.image + '" data-toggle="tooltip" alt="' + data.tooltip + '" title="' + data.tooltip + '" class="' + data.class + '"' + width + '>'
  710. );
  711. if (data.ssl.status === 'active') {
  712. jQuery('#ssl-startdate').text(data.ssl.startDate);
  713. jQuery('#ssl-expirydate').text(data.ssl.expiryDate);
  714. jQuery('#ssl-issuer').text(data.ssl.issuer);
  715. } else {
  716. jQuery('#ssl-startdate').parent('div').hide();
  717. jQuery('#ssl-expirydate').parent('div').hide();
  718. jQuery('#ssl-issuer').parent('div').hide();
  719. }
  720. jQuery('#statusDisplayLabel').text(statusDisplayLabel);
  721. }
  722. }
  723. );
  724. });
  725. jQuery(document).on('click', '.ssl-state.ssl-inactive', function(e) {
  726. e.preventDefault();
  727. window.location.href = WHMCS.utils.getRouteUrl('/ssl-purchase');
  728. });
  729. WHMCS.recaptcha.register();
  730. var dynamicRecaptchaContainer = jQuery('#divDynamicRecaptcha');
  731. var homepageHasRecaptcha = jQuery(dynamicRecaptchaContainer).length > 0;
  732. var homepageHasInvisibleRecaptcha = homepageHasRecaptcha && jQuery(dynamicRecaptchaContainer).data('size') === 'invisible';
  733. var frmDomainHomepage = jQuery('#frmDomainHomepage');
  734. jQuery(frmDomainHomepage).find('button[data-domain-action="transfer"]').click(function () {
  735. jQuery(frmDomainHomepage).find('input[name="transfer"]').val('1');
  736. });
  737. if (homepageHasRecaptcha && !homepageHasInvisibleRecaptcha) {
  738. jQuery('section#home-banner').addClass('with-recaptcha');
  739. }
  740. if (jQuery('.domainchecker-homepage-captcha').length && !homepageHasInvisibleRecaptcha) {
  741. // invisible reCaptcha doesn't play well with onsubmit() handlers on all submissions following a prevented one
  742. jQuery(frmDomainHomepage).submit(function (e) {
  743. var inputDomain = jQuery(frmDomainHomepage).find('input[name="domain"]'),
  744. reCaptchaContainer = jQuery('#divDynamicRecaptcha'),
  745. reCaptcha = jQuery('#g-recaptcha-response'),
  746. captcha = jQuery('#inputCaptcha');
  747. if (reCaptcha.length && !reCaptcha.val()) {
  748. reCaptchaContainer.tooltip('show');
  749. e.preventDefault();
  750. return;
  751. }
  752. if (captcha.length && !captcha.val()) {
  753. captcha.tooltip('show');
  754. e.preventDefault();
  755. }
  756. });
  757. }
  758. $('.icheck-button').iCheck({
  759. inheritID: true,
  760. checkboxClass: 'icheckbox_square-blue',
  761. radioClass: 'iradio_square-blue',
  762. increaseArea: '20%'
  763. });
  764. jQuery('#inputNoStore').on('switchChange.bootstrapSwitch', function(event, state) {
  765. var descContainer = jQuery('#inputDescription');
  766. if (!state) {
  767. descContainer.prop('disabled', true).addClass('disabled');
  768. }
  769. if (state) {
  770. descContainer.removeClass('disabled').prop('disabled', false);
  771. }
  772. });
  773. jQuery(document).on('click', '#btnConfirmModalConfirmBtn', function () {
  774. var confirmButton = jQuery(this),
  775. confirmationModal = confirmButton.closest('div.modal'),
  776. targetUrl = confirmButton.data('target-url'),
  777. dataTable = confirmButton.closest('table.dataTable[data-on-draw-rebind-confirmation-modal="true"]');
  778. WHMCS.http.jqClient.jsonPost(
  779. {
  780. url: targetUrl,
  781. data: {
  782. token: csrfToken
  783. },
  784. success: function(data) {
  785. if (data.status === 'success' || data.status === 'okay') {
  786. if (dataTable.length > 0) {
  787. dataTable.DataTable().ajax.reload();
  788. }
  789. }
  790. }
  791. }
  792. );
  793. confirmationModal.modal('toggle');
  794. });
  795. hideOverlay();
  796. jQuery('input[name="approval_method"]').on('ifChecked', function(event) {
  797. var fileMethod = $('#containerApprovalMethodFile'),
  798. emailMethod = $('#containerApprovalMethodEmail'),
  799. dnsMethod = $('#containerApprovalMethodDns');
  800. if (jQuery(this).attr('value') == 'file') {
  801. fileMethod.show();
  802. dnsMethod.hide();
  803. emailMethod.hide();
  804. } else if (jQuery(this).attr('value') == 'dns-txt-token') {
  805. dnsMethod.show();
  806. fileMethod.hide();
  807. emailMethod.hide();
  808. } else {
  809. fileMethod.hide();
  810. dnsMethod.hide();
  811. emailMethod.show();
  812. }
  813. });
  814. (function () {
  815. jQuery('.div-service-status').css(
  816. 'width',
  817. (jQuery('.div-service-status .label-placeholder').outerWidth() + 5)
  818. );
  819. jQuery('div[menuitemname="Active Products/Services"] .list-group-item:visible')
  820. .last()
  821. .css('border-bottom', '1px solid #ddd');
  822. }());
  823. jQuery('div[menuitemname="Active Products/Services"] .btn-view-more').on('click', function(event) {
  824. var hiddenItems = jQuery('div[menuitemname="Active Products/Services"] .list-group-item:hidden');
  825. var itemAmount = 8;
  826. event.preventDefault();
  827. hiddenItems.slice(0,itemAmount).css('display', 'block');
  828. if ((hiddenItems.length - itemAmount) <= 0) {
  829. jQuery(event.target).addClass('disabled').attr("aria-disabled", true);
  830. }
  831. jQuery('div[menuitemname="Active Products/Services"] .list-group-item:visible')
  832. .css('border-bottom', '')
  833. .last()
  834. .css('border-bottom', '1px solid #ddd');
  835. })
  836. jQuery('div[menuitemname="Service Details Actions"] a[data-identifier][data-serviceid][data-active="1"]').on('click', function(event) {
  837. return customActionAjaxCall(event, jQuery(event.target).closest('a'));
  838. });
  839. jQuery('.div-service-item').on('click', function (event) {
  840. var element = jQuery(event.target);
  841. if (element.is('.dropdown-toggle, .dropdown-menu')) {
  842. return true;
  843. }
  844. if (element.hasClass('btn-custom-action')) {
  845. return customActionAjaxCall(event, element);
  846. }
  847. window.location.href = element.closest('.div-service-item').data('href');
  848. return false;
  849. });
  850. });
  851. /**
  852. * Control disabled/enabled state of elements by class name.
  853. *
  854. * @param {string} className Common element class name.
  855. * @param {bool} disabledState Whether the elements should be disabled or not.
  856. */
  857. function disableFields(className, disabledState) {
  858. if (className[0] !== '.') {
  859. className = '.' + className;
  860. }
  861. var elements = jQuery(className);
  862. elements.prop('disabled', disabledState);
  863. if (disabledState) {
  864. elements.addClass('disabled');
  865. } else {
  866. elements.removeClass('disabled');
  867. }
  868. }
  869. /**
  870. * Check all checkboxes with a given class.
  871. *
  872. * @param {string} className Common class name.
  873. * @param {Element} masterControl Parent checkbox to which the other checkboxes should mirror.
  874. */
  875. function checkAll(className, masterControl) {
  876. if (className[0] !== '.') {
  877. className = '.' + className;
  878. }
  879. // In jQuery, if you set the checked attribute directly, the dom
  880. // element is changed, but browsers don't show the check box as
  881. // checked. Using the click event will properly display.
  882. jQuery(className).removeAttr('checked');
  883. if(jQuery(masterControl).is(":checked")) {
  884. jQuery(className).click();
  885. }
  886. }
  887. /**
  888. * Redirect on click if an element is not a button or link.
  889. *
  890. * Where table rows are clickable, we only want to redirect if the row
  891. * itself is clicked. If a button or link within the row is clicked,
  892. * the event tied to that object should be executed. This function
  893. * stops the standard JS event bubbling required to make that happen.
  894. *
  895. * @param {object} clickEvent jQuery click event
  896. * @param {string} target Redirect location
  897. * @param {bool} newWindow Open link in new window
  898. */
  899. function clickableSafeRedirect(clickEvent, target, newWindow) {
  900. var eventSource = clickEvent.target.tagName.toLowerCase();
  901. var eventParent = clickEvent.target.parentNode.tagName.toLowerCase();
  902. var eventTable = clickEvent.target.parentNode.parentNode.parentNode;
  903. if (jQuery(eventTable).hasClass('collapsed')) {
  904. // This is a mobile device sized display, and datatables has triggered folding
  905. return false;
  906. }
  907. if (eventSource === 'i' && jQuery(clickEvent.target).hasClass('ssl-required')) {
  908. return false;
  909. }
  910. if(eventSource !== 'button' && eventSource !== 'a') {
  911. if(eventParent !== 'button' && eventParent !== 'a') {
  912. if (newWindow) {
  913. window.open(target);
  914. } else {
  915. window.location.href = target;
  916. }
  917. }
  918. }
  919. }
  920. /**
  921. * Open a centered popup window.
  922. *
  923. * @param {string} addr The URL to navigate to
  924. * @param {string} popname The name to assign the window
  925. * @param {number} w The width
  926. * @param {number} h The height
  927. * @param {string} features Any additional settings to apply
  928. */
  929. function popupWindow(addr, popname, w, h, features) {
  930. var winl = (screen.width-w) / 2,
  931. wint = (screen.height-h) / 2,
  932. win;
  933. if (winl < 0) {
  934. winl = 0;
  935. }
  936. if (wint < 0) {
  937. wint = 0;
  938. }
  939. var settings = 'height=' + h + ',';
  940. settings += 'width=' + w + ',';
  941. settings += 'top=' + wint + ',';
  942. settings += 'left=' + winl + ',';
  943. settings += features;
  944. win = window.open(addr, popname, settings);
  945. win.window.focus();
  946. }
  947. /**
  948. * Navigate to a page on dropdown change.
  949. *
  950. * This is implemented onblur() for a dropdown. When the dropdown
  951. * changes state, the value is pulled and the browser navigated to
  952. * the selected page.
  953. *
  954. * @param {Element} select The dropdown triggering the event
  955. */
  956. function selectChangeNavigate(select) {
  957. window.location.href = $(select).val();
  958. }
  959. /**
  960. * Fetch load and uptime for a given server.
  961. *
  962. * @param {number} num Server Id
  963. */
  964. function getStats(num) {
  965. WHMCS.http.jqClient.post('serverstatus.php', 'getstats=1&num=' + num, function(data) {
  966. jQuery("#load"+num).html(data.load);
  967. jQuery("#uptime"+num).html(data.uptime);
  968. },'json');
  969. }
  970. /**
  971. * Determine status of a given port for a given server.
  972. *
  973. * @param {number} num Server Id
  974. * @param {number} port Port Number
  975. */
  976. function checkPort(num, port) {
  977. WHMCS.http.jqClient.post('serverstatus.php', 'ping=1&num=' + num + '&port=' + port, function(data) {
  978. jQuery("#port" + port + "_" + num).html(data);
  979. });
  980. }
  981. /**
  982. * Fetch automated knowledgebase suggestions for ticket content.
  983. */
  984. var currentcheckcontent,
  985. lastcheckcontent;
  986. function getticketsuggestions() {
  987. currentcheckcontent = jQuery("#message").val();
  988. if (currentcheckcontent !== lastcheckcontent && currentcheckcontent !== "") {
  989. WHMCS.http.jqClient.post("submitticket.php", { action: "getkbarticles", text: currentcheckcontent },
  990. function(data){
  991. if (data) {
  992. jQuery("#searchresults").html(data).slideDown();
  993. }
  994. });
  995. lastcheckcontent = currentcheckcontent;
  996. }
  997. setTimeout('getticketsuggestions();', 3000);
  998. }
  999. /**
  1000. * Update custom fields upon department change.
  1001. *
  1002. * @param {Element} input The department selector dropdown object
  1003. */
  1004. function refreshCustomFields(input) {
  1005. jQuery("#customFieldsContainer").load(
  1006. "submitticket.php",
  1007. { action: "getcustomfields", deptid: $(input).val() }
  1008. );
  1009. }
  1010. /**
  1011. * Submit the first form that exists within a given container.
  1012. *
  1013. * @param {string} containerId The ID name of the container
  1014. */
  1015. function autoSubmitFormByContainer(containerId) {
  1016. if (typeof noAutoSubmit === "undefined" || noAutoSubmit === false) {
  1017. jQuery("#" + containerId).find("form:first").submit();
  1018. }
  1019. }
  1020. /**
  1021. * Submit default whois info and disable custom fields.
  1022. *
  1023. * @param {string} regType The contact registration type
  1024. */
  1025. function useDefaultWhois(regType) {
  1026. jQuery("." + regType.substr(0, regType.length - 1) + "customwhois").attr("disabled", true);
  1027. jQuery("." + regType.substr(0, regType.length - 1) + "defaultwhois").attr("disabled", false);
  1028. jQuery('#' + regType.substr(0, regType.length - 1) + '1').attr("checked", "checked");
  1029. }
  1030. /**
  1031. * Submit custom fields and disable default whois info.
  1032. *
  1033. * @param {string} regType The contact registration type
  1034. */
  1035. function useCustomWhois(regType) {
  1036. jQuery("." + regType.substr(0, regType.length - 1) + "customwhois").attr("disabled", false);
  1037. jQuery("." + regType.substr(0, regType.length - 1) + "defaultwhois").attr("disabled", true);
  1038. jQuery('#' + regType.substr(0, regType.length - 1) + '2').attr("checked", "checked");
  1039. }
  1040. function showNewBillingAddressFields() {
  1041. jQuery('#newBillingAddress').parent('div').slideDown();
  1042. }
  1043. function hideNewBillingAddressFields() {
  1044. jQuery('#newBillingAddress').parent('div').slideUp();
  1045. }
  1046. /**
  1047. * Show new credit card input fields.
  1048. */
  1049. function showNewCardInputFields() {
  1050. var ccDetails = jQuery('.cc-details'),
  1051. ccNumber = jQuery('#inputCardNumber'),
  1052. billAddress = jQuery('#billingAddressChoice'),
  1053. container;
  1054. container = ccDetails.parent('div');
  1055. if (container.not(':visible')) {
  1056. container.show();
  1057. }
  1058. jQuery('.cc-details').slideDown();
  1059. ccNumber.focus();
  1060. container = billAddress.parent('div');
  1061. if (container.not(':visible')) {
  1062. container.show();
  1063. }
  1064. billAddress.slideDown()
  1065. .find('input[name="billingcontact"]')
  1066. .first()
  1067. .iCheck('check');
  1068. }
  1069. /**
  1070. * Show new bank account input fields.
  1071. */
  1072. function showNewAccountInputFields() {
  1073. var bankDetails = jQuery('.bank-details').parent('div');
  1074. if (bankDetails.not(':visible')) {
  1075. bankDetails.slideDown();
  1076. }
  1077. jQuery("#billingAddressChoice")
  1078. .parent('div')
  1079. .slideDown()
  1080. .find('input[name="billingcontact"]')
  1081. .first()
  1082. .iCheck('check');
  1083. }
  1084. /**
  1085. * Hide new credit card input fields.
  1086. */
  1087. function hideNewCardInputFields() {
  1088. hideNewBillingAddressFields();
  1089. jQuery(".cc-details").slideUp();
  1090. jQuery("#billingAddressChoice").slideUp();
  1091. var contactId = jQuery('input[name="ccinfo"]:checked').data('billing-contact-id');
  1092. if (contactId != undefined) {
  1093. jQuery('#billingAddressChoice label.billing-contact-' + contactId)
  1094. .iCheck('check');
  1095. }
  1096. jQuery('#inputCardCvv').focus();
  1097. }
  1098. /**
  1099. * Hide new bank account input fields.
  1100. */
  1101. function hideNewAccountInputFields() {
  1102. hideNewBillingAddressFields();
  1103. jQuery(".bank-details").parent('div').slideUp();
  1104. jQuery("#billingAddressChoice").parent('div').slideUp();
  1105. var selectedAccount = jQuery('input[name="paymethod"]:checked'),
  1106. selectedContactId = jQuery(selectedAccount).data('billing-contact-id'),
  1107. selectedContactData = jQuery('.billing-contact-info[data-billing-contact-id="' + selectedContactId + '"]');
  1108. if (selectedContactData.length) {
  1109. jQuery('.billing-contact-info').hide();
  1110. jQuery(selectedContactData).show();
  1111. }
  1112. }
  1113. /**
  1114. * Get automatic knowledgebase suggestions for support ticket message.
  1115. */
  1116. var lastTicketMsg;
  1117. function getTicketSuggestions() {
  1118. var userMsg = jQuery("#inputMessage").val();
  1119. if (userMsg !== lastTicketMsg && userMsg !== '') {
  1120. WHMCS.http.jqClient.post("submitticket.php", { action: "getkbarticles", text: userMsg },
  1121. function (data) {
  1122. var suggestions = jQuery("#autoAnswerSuggestions");
  1123. if (data) {
  1124. suggestions.html(data);
  1125. if (suggestions.not(":visible")) {
  1126. suggestions.slideDown();
  1127. }
  1128. }
  1129. });
  1130. lastTicketMsg = userMsg;
  1131. }
  1132. setTimeout('getTicketSuggestions()', 3000);
  1133. }
  1134. /**
  1135. * Smooth scroll to named element.
  1136. */
  1137. function smoothScroll(element) {
  1138. $('html, body').animate({
  1139. scrollTop: $(element).offset().top
  1140. }, 500);
  1141. }
  1142. var allowSubmit = false;
  1143. function irtpSubmit() {
  1144. allowSubmit = true;
  1145. var optOut = 0,
  1146. optOutCheckbox = jQuery('#modalIrtpOptOut'),
  1147. optOutReason = jQuery('#modalReason'),
  1148. formOptOut = jQuery('#irtpOptOut'),
  1149. formOptOutReason = jQuery('#irtpOptOutReason');
  1150. if (optOutCheckbox.is(':checked')) {
  1151. optOut = 1;
  1152. }
  1153. formOptOut.val(optOut);
  1154. formOptOutReason.val(optOutReason.val());
  1155. jQuery('#frmDomainContactModification').submit();
  1156. }
  1157. function showOverlay(msg) {
  1158. jQuery('#fullpage-overlay .msg').html(msg);
  1159. jQuery('#fullpage-overlay').show();
  1160. }
  1161. function hideOverlay() {
  1162. jQuery('#fullpage-overlay').hide();
  1163. }
  1164. function getSslAttribute(element, attribute) {
  1165. if (element.data(attribute)) {
  1166. return element.data(attribute);
  1167. }
  1168. return element.parent('td').data(attribute);
  1169. }
  1170. function removeRetweets() {
  1171. jQuery('#twitter-widget-0')
  1172. .contents()
  1173. .find('.timeline-Tweet--isRetweet')
  1174. .parent('li')
  1175. .remove();
  1176. }
  1177. function addTwitterWidgetObserverWhenNodeAvailable() {
  1178. if (elementsWaitTimeout) {
  1179. clearTimeout(elementsWaitTimeout);
  1180. }
  1181. var targetTwitterWidget = document.getElementById('twitter-widget-0');
  1182. if (!targetTwitterWidget) {
  1183. elementsWaitTimeout = window.setTimeout(addTwitterWidgetObserverWhenNodeAvailable, 500);
  1184. return;
  1185. }
  1186. var targetTimelineTweets = targetTwitterWidget
  1187. .contentWindow
  1188. .document
  1189. .getElementsByClassName('timeline-TweetList')[0];
  1190. if (!targetTimelineTweets) {
  1191. elementsWaitTimeout = window.setTimeout(addTwitterWidgetObserverWhenNodeAvailable, 500);
  1192. return;
  1193. }
  1194. jQuery('#twitter-widget-0')
  1195. .contents()
  1196. .find('head')
  1197. .append("<style>.timeline-Tweet-text { font-size: 18px !important; line-height: 25px !important; margin-bottom: 0px !important; }</style>");
  1198. removeRetweets();
  1199. observerTwitterWidget.observe(targetTimelineTweets, observerConfig);
  1200. }
  1201. function openValidationSubmitModal(caller)
  1202. {
  1203. var validationSubmitModal = jQuery('#validationSubmitModal');
  1204. validationSubmitModal.find('.modal-body iframe').attr('src', caller.dataset.url);
  1205. validationSubmitModal.modal('show');
  1206. }
  1207. function completeValidationComClientWorkflow()
  1208. {
  1209. var submitDocsRequestBanner = jQuery('.user-validation'),
  1210. secondarySidebarStatus = jQuery('.validation-status-label'),
  1211. submitDiv = jQuery('.validation-submit-div'),
  1212. redirectUser = true;
  1213. $('#validationSubmitModal').modal('hide');
  1214. if (submitDocsRequestBanner.length !== 0) {
  1215. submitDocsRequestBanner.slideUp();
  1216. redirectUser = false;
  1217. }
  1218. if (secondarySidebarStatus.length !== 0) {
  1219. var submitString = submitDiv.find('a').data('submitted-string');
  1220. secondarySidebarStatus.text(submitString).removeClass('label-default').addClass('label-warning');
  1221. submitDiv.hide();
  1222. redirectUser = false;
  1223. }
  1224. if (redirectUser) {
  1225. window.location.href = WHMCS.utils.autoDetermineBaseUrl();
  1226. }
  1227. return false;
  1228. }
  1229. var autoCollapse = function (menu, maxHeight) {
  1230. var continueLoop = true,
  1231. nav = jQuery(menu),
  1232. navHeight = nav.innerHeight();
  1233. if (navHeight >= maxHeight) {
  1234. jQuery(menu + ' .collapsable-dropdown').removeClass('d-none');
  1235. jQuery(".navbar-nav").removeClass('w-auto').addClass("w-100");
  1236. while (navHeight > maxHeight && continueLoop) {
  1237. // add child to dropdown
  1238. var children = nav.children(menu + ' li:not(:last-child):not(".no-collapse")'),
  1239. count = children.length;
  1240. if (!count) {
  1241. continueLoop = false;
  1242. } else {
  1243. children.data('original-classes', children.attr('class'));
  1244. var child = jQuery(children[count - 1]);
  1245. child.removeClass().addClass('dropdown-item');
  1246. child.prependTo(menu + ' .collapsable-dropdown-menu');
  1247. }
  1248. navHeight = nav.innerHeight();
  1249. }
  1250. jQuery(".navbar-nav").addClass("w-auto").removeClass('w-100');
  1251. } else {
  1252. var collapsed = jQuery(menu + ' .collapsable-dropdown-menu').children(menu + ' li');
  1253. if (collapsed.length === 0) {
  1254. jQuery(menu + ' .collapsable-dropdown').addClass('d-none');
  1255. }
  1256. while (navHeight < maxHeight && (nav.children(menu + ' li').length > 0) && collapsed.length > 0) {
  1257. // remove child from dropdown
  1258. collapsed = jQuery(menu + ' .collapsable-dropdown-menu').children('li');
  1259. var child = jQuery(collapsed[0]);
  1260. child.removeClass().addClass(child.data('original-classes'));
  1261. child.insertBefore(nav.children(menu + ' li:last-child'));
  1262. navHeight = nav.innerHeight();
  1263. }
  1264. if (navHeight > maxHeight) {
  1265. autoCollapse(menu, maxHeight);
  1266. }
  1267. }
  1268. }
  1269. /**
  1270. * Perform the AjaxCall for a CustomAction.
  1271. *
  1272. * @param event
  1273. * @param element
  1274. * @returns {boolean}
  1275. */
  1276. function customActionAjaxCall(event, element) {
  1277. var loadingIcon = jQuery('.loading', element);
  1278. var standardIcon = jQuery('.sidebar-menu-item-icon', element);
  1279. event.stopPropagation();
  1280. if (!element.data('active')) {
  1281. return false;
  1282. }
  1283. element.attr('disabled', 'disabled').addClass('disabled');
  1284. loadingIcon.show();
  1285. standardIcon.hide();
  1286. const redirectFn = ((jQuery(element).data('ca-target') === '_self') || (jQuery(element).attr('target') === '_self'))
  1287. ? function(url) { window.location.href = url; }
  1288. : window.open;
  1289. WHMCS.http.jqClient.jsonPost({
  1290. url: WHMCS.utils.getRouteUrl(
  1291. '/clientarea/service/' + element.data('serviceid') + '/custom-action/' + element.data('identifier')
  1292. ),
  1293. data: {
  1294. 'token': csrfToken
  1295. },
  1296. success: function(data) {
  1297. if (data.success) {
  1298. redirectFn(data.redirectTo);
  1299. } else {
  1300. redirectFn('clientarea.php?action=productdetails&id=' + element.data('serviceid') + '&customaction_error=1');
  1301. }
  1302. },
  1303. fail: function () {
  1304. redirectFn('clientarea.php?action=productdetails&id=' + element.data('serviceid') + '&customaction_ajax_error=1');
  1305. },
  1306. error: function () {
  1307. redirectFn('clientarea.php?action=productdetails&id=' + element.data('serviceid') + '&customaction_ajax_error=1');
  1308. },
  1309. always: function() {
  1310. loadingIcon.hide();
  1311. standardIcon.show();
  1312. element.removeAttr('disabled').removeClass('disabled');
  1313. if (element.hasClass('dropdown-item')) {
  1314. element.closest('.dropdown-menu').removeClass('show');
  1315. }
  1316. },
  1317. });
  1318. return true;
  1319. }