admin.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101
  1. /**
  2. * Developer's Notice:
  3. *
  4. * Note: JS in this file (and this file itself) is not garunteed backwards compatibility. JS can be added, changed or removed at any time without notice.
  5. * For more information see the `Backwards Compatibility Guidelines for Developers` section of the README.md file.
  6. */
  7. /**
  8. * Handles:
  9. * - Copy to Clipboard functionality
  10. * - Dismissable Notices
  11. *
  12. * @since 6.0.0
  13. */
  14. (function() {
  15. var list, dbjsError,
  16. errors = [];
  17. window.onerror = function( errorMsg, url, lineNumber ) {
  18. if ( ! document.getElementById( 'monsterinsights-ublock-origin-error' ) )
  19. errors[ errors.length ] = [errorMsg, url, lineNumber];
  20. else
  21. dbjsError(errorMsg, url, lineNumber);
  22. };
  23. jQuery(document).ready( function(){
  24. for ( var err in errors )
  25. dbjsError( errors[err][0], errors[err][1], errors[err][2] );
  26. });
  27. dbjsError = function( errorMsg, url, lineNumber ) {
  28. var errorLine, place, button, tab;
  29. if ( !list )
  30. list = document.getElementById( 'monsterinsights-ublock-origin-error' );
  31. if (!list )
  32. return; // threw way too early... @todo cache these?
  33. errorLine = document.createElement( 'li' );
  34. errorLine.className = 'debug-bar-js-error';
  35. errorLine.textContent = errorMsg + ' on ';
  36. place = document.createElement( 'span' );
  37. place.textContent = url + ' line ' + lineNumber;
  38. errorLine.appendChild( place );
  39. list.appendChild( errorLine );
  40. };
  41. })();
  42. jQuery( document ).ready( function( $ ) {
  43. // Disable function
  44. jQuery.fn.extend({
  45. disable: function(state) {
  46. return this.each(function() {
  47. this.disabled = state;
  48. });
  49. }
  50. });
  51. jQuery("#screen-meta-links").prependTo("#monsterinsights-header-temp");
  52. jQuery("#screen-meta").prependTo("#monsterinsights-header-temp");
  53. // Tooltips
  54. jQuery('.monsterinsights-help-tip').tooltip({
  55. content: function() {
  56. return jQuery(this).prop('title');
  57. },
  58. tooltipClass: 'monsterinsights-ui-tooltip',
  59. position: {
  60. my: 'center top',
  61. at: 'center bottom+10',
  62. collision: 'flipfit',
  63. },
  64. hide: {
  65. duration: 200,
  66. },
  67. show: {
  68. duration: 200,
  69. },
  70. });
  71. // Reports Tooltips
  72. jQuery("body").tooltip({
  73. selector: '.monsterinsights-reports-uright-tooltip',
  74. items: "[data-tooltip-title], [data-tooltip-description]",
  75. content: function() {
  76. return '<div class="monsterinsights-reports-tooltip-title">' + jQuery(this).data("tooltip-title") + '</div>' +
  77. '<div class="monsterinsights-reports-tooltip-content">' + jQuery(this).data("tooltip-description") + '</div>';
  78. },
  79. tooltipClass: 'monsterinsights-reports-ui-tooltip',
  80. position: { my: "right-10 top", at: "left top", collision: "flipfit" },
  81. hide: {duration: 200},
  82. show: {duration: 200},
  83. });
  84. /**
  85. * Copy to Clipboard
  86. */
  87. if ( typeof Clipboard !== 'undefined' ) {
  88. var monsterinsights_clipboard = new Clipboard( '.monsterinsights-copy-to-clipboard' );
  89. jQuery( document ).on( 'click', '.monsterinsights-copy-to-clipboard', function( e ) {
  90. e.preventDefault();
  91. } );
  92. function fallbackMessage(action){
  93. var actionMsg='';var actionKey=(action==='cut'?'X':'C');
  94. if (/iPhone|iPad/i.test(navigator.userAgent ) ) {
  95. actionMsg='No support :(';
  96. } else if (/Mac/i.test(navigator.userAgent ) ) {
  97. actionMsg='Press ⌘-'+ actionKey+' to '+ action;
  98. } else {
  99. actionMsg='Press Ctrl-'+ actionKey+' to '+ action;
  100. }
  101. return actionMsg;
  102. }
  103. monsterinsights_clipboard.on('success',function(e){
  104. e.trigger.textContent = monsterinsights_admin.copied;
  105. window.setTimeout(function() {
  106. e.trigger.textContent = monsterinsights_admin.copytoclip;
  107. }, 2000);
  108. });
  109. monsterinsights_clipboard.on('error',function(e){
  110. e.trigger.textContent = fallbackMessage(e.action);
  111. });
  112. }
  113. function modelMatcher(params, data) {
  114. data.parentText = data.parentText || "";
  115. // Always return the object if there is nothing to compare
  116. if (jQuery.trim(params.term) === '') {
  117. return data;
  118. }
  119. // Do a recursive check for options with children
  120. if (data.children && data.children.length > 0) {
  121. // Clone the data object if there are children
  122. // This is required as we modify the object to remove any non-matches
  123. var match = $.extend(true, {}, data);
  124. // Check each child of the option
  125. for (var c = data.children.length - 1; c >= 0; c--) {
  126. var child = data.children[c];
  127. child.parentText += data.parentText + " " + data.text;
  128. var matches = modelMatcher(params, child);
  129. // If there wasn't a match, remove the object in the array
  130. if (matches == null) {
  131. match.children.splice(c, 1);
  132. }
  133. }
  134. // If any children matched, return the new object
  135. if (match.children.length > 0) {
  136. return match;
  137. }
  138. // If there were no matching children, check just the plain object
  139. return modelMatcher(params, match);
  140. }
  141. // If the typed-in term matches the text of this term, or the text from any
  142. // parent term, then it's a match.
  143. var original = (data.parentText + ' ' + data.text).toUpperCase();
  144. var term = params.term.toUpperCase();
  145. // Check if the text contains the term
  146. if (original.indexOf(term) > -1) {
  147. return data;
  148. }
  149. // If it doesn't contain the term, don't return anything
  150. return null;
  151. }
  152. // Setup Select2
  153. jQuery('.monsterinsights-select300').select300();
  154. var fields_changed = false;
  155. jQuery(document).on('change', '#monsterinsights-settings :input', function(){
  156. fields_changed = true;
  157. });
  158. jQuery(document).on('click', 'a:not(.monsterinsights-settings-click-excluded)', function( e ){
  159. if ( fields_changed ) {
  160. var answer = confirm( monsterinsights_admin.settings_changed_confirm );
  161. if ( answer ){
  162. fields_changed = false;
  163. return true;
  164. } else {
  165. e.preventDefault();
  166. return false;
  167. }
  168. }
  169. });
  170. // Auth Actions
  171. // Auth and Reauth
  172. jQuery('#monsterinsights-google-authenticate-submit').on( "click", function( e ) {
  173. e.preventDefault();
  174. swal({
  175. type: 'info',
  176. title: monsterinsights_admin.redirect_loading_title_text,
  177. text: monsterinsights_admin.redirect_loading_text_text,
  178. allowOutsideClick: false,
  179. allowEscapeKey: false,
  180. allowEnterKey: false,
  181. onOpen: function () {
  182. swal.showLoading();
  183. }
  184. }).catch(swal.noop);
  185. var data = {
  186. 'action': 'monsterinsights_maybe_authenticate',
  187. 'nonce': monsterinsights_admin.admin_nonce,
  188. 'isnetwork': monsterinsights_admin.isnetwork
  189. };
  190. jQuery.post(ajaxurl, data, function( response ) {
  191. if ( response.success ) {
  192. window.location = response.data.redirect;
  193. } else {
  194. swal({
  195. type: 'error',
  196. title: monsterinsights_admin.redirect_loading_error_title,
  197. text: response.data.message,
  198. confirmButtonText: monsterinsights_admin.ok_text,
  199. }).catch(swal.noop);
  200. }
  201. }).fail( function(xhr, textStatus, errorThrown) {
  202. var message = jQuery(xhr.responseText).text();
  203. message = message.substring(0, message.indexOf("Call Stack"));
  204. swal({
  205. type: 'error',
  206. title: monsterinsights_admin.redirect_loading_error_title,
  207. text: message,
  208. confirmButtonText: monsterinsights_admin.ok_text,
  209. }).catch(swal.noop);
  210. });
  211. });
  212. // Reauth
  213. jQuery('#monsterinsights-google-reauthenticate-submit').on( "click", function( e ) {
  214. e.preventDefault();
  215. swal({
  216. type: 'info',
  217. title: monsterinsights_admin.redirect_loading_title_text,
  218. text: monsterinsights_admin.redirect_loading_text_text,
  219. allowOutsideClick: false,
  220. allowEscapeKey: false,
  221. allowEnterKey: false,
  222. onOpen: function () {
  223. swal.showLoading();
  224. }
  225. }).catch(swal.noop);
  226. var data = {
  227. 'action': 'monsterinsights_maybe_reauthenticate',
  228. 'nonce': monsterinsights_admin.admin_nonce,
  229. 'isnetwork': monsterinsights_admin.isnetwork
  230. };
  231. jQuery.post(ajaxurl, data, function( response ) {
  232. if ( response.success ) {
  233. window.location = response.data.redirect;
  234. } else {
  235. swal({
  236. type: 'error',
  237. title: monsterinsights_admin.redirect_loading_error_title,
  238. text: response.data.message,
  239. confirmButtonText: monsterinsights_admin.ok_text,
  240. }).catch(swal.noop);
  241. }
  242. }).fail( function(xhr, textStatus, errorThrown) {
  243. var message = jQuery(xhr.responseText).text();
  244. message = message.substring(0, message.indexOf("Call Stack"));
  245. swal({
  246. type: 'error',
  247. title: monsterinsights_admin.redirect_loading_error_title,
  248. text: message,
  249. confirmButtonText: monsterinsights_admin.ok_text,
  250. }).catch(swal.noop);
  251. });
  252. });
  253. // Verify
  254. jQuery('#monsterinsights-google-verify-submit').on( "click", function( e ) {
  255. e.preventDefault();
  256. swal({
  257. type: 'info',
  258. title: monsterinsights_admin.verify_loading_title_text,
  259. text: monsterinsights_admin.verify_loading_text_text,
  260. allowOutsideClick: false,
  261. allowEscapeKey: false,
  262. allowEnterKey: false,
  263. onOpen: function () {
  264. swal.showLoading();
  265. }
  266. }).catch(swal.noop);
  267. var data = {
  268. 'action': 'monsterinsights_maybe_verify',
  269. 'nonce': monsterinsights_admin.admin_nonce,
  270. 'isnetwork': monsterinsights_admin.isnetwork
  271. };
  272. jQuery.post(ajaxurl, data, function( response ) {
  273. if ( response.success ) {
  274. swal({
  275. type: 'success',
  276. title: monsterinsights_admin.verify_success_title_text,
  277. text: monsterinsights_admin.verify_success_text_text,
  278. confirmButtonText: monsterinsights_admin.ok_text,
  279. }).catch(swal.noop);
  280. } else {
  281. swal({
  282. type: 'error',
  283. title: monsterinsights_admin.verify_loading_error_title,
  284. text: response.data.message,
  285. confirmButtonText: monsterinsights_admin.ok_text,
  286. }).catch(swal.noop);
  287. }
  288. }).fail( function(xhr, textStatus, errorThrown) {
  289. var message = jQuery(xhr.responseText).text();
  290. message = message.substring(0, message.indexOf("Call Stack"));
  291. swal({
  292. type: 'error',
  293. title: monsterinsights_admin.verify_loading_error_title,
  294. text: message,
  295. confirmButtonText: monsterinsights_admin.ok_text,
  296. }).catch(swal.noop);
  297. });
  298. });
  299. // Delete
  300. jQuery(document).on('click','#monsterinsights-google-deauthenticate-submit', function( e ){
  301. e.preventDefault();
  302. monsterinsights_delete_auth( $(this), false );
  303. });
  304. // Force Delete
  305. jQuery(document).on('click','#monsterinsights-google-force-deauthenticate-submit', function( e ){
  306. e.preventDefault();
  307. monsterinsights_delete_auth( $(this), true );
  308. });
  309. function monsterinsights_delete_auth( buttonObject, force ) {
  310. swal({
  311. type: 'info',
  312. title: monsterinsights_admin.deauth_loading_title_text,
  313. text: monsterinsights_admin.deauth_loading_text_text,
  314. allowOutsideClick: false,
  315. allowEscapeKey: false,
  316. allowEnterKey: false,
  317. onOpen: function () {
  318. swal.showLoading();
  319. }
  320. }).catch(swal.noop);
  321. var data = {
  322. 'action': 'monsterinsights_maybe_delete',
  323. 'nonce': monsterinsights_admin.admin_nonce,
  324. 'isnetwork': monsterinsights_admin.isnetwork,
  325. 'forcedelete' : force.toString(),
  326. };
  327. jQuery.post(ajaxurl, data, function( response ) {
  328. if ( response.success ) {
  329. swal({
  330. type: 'success',
  331. title: monsterinsights_admin.deauth_success_title_text,
  332. text: monsterinsights_admin.deauth_success_text_text,
  333. confirmButtonText: monsterinsights_admin.ok_text,
  334. allowOutsideClick: false,
  335. allowEscapeKey: false,
  336. allowEnterKey: false,
  337. }).then(function () {
  338. location.reload();
  339. }).catch(swal.noop);
  340. } else {
  341. if ( ! force ) {
  342. // Replace name, ID, value
  343. buttonObject.attr('name', 'monsterinsights-google-force-deauthenticate-submit' );
  344. buttonObject.attr('id', 'monsterinsights-google-force-deauthenticate-submit' );
  345. buttonObject.attr('value', monsterinsights_admin.force_deauth_button_text );
  346. }
  347. swal({
  348. type: 'error',
  349. title: monsterinsights_admin.deauth_loading_error_title,
  350. text: response.data.message,
  351. confirmButtonText: monsterinsights_admin.ok_text,
  352. }).catch(swal.noop);
  353. }
  354. }).fail( function(xhr, textStatus, errorThrown) {
  355. var message = jQuery(xhr.responseText).text();
  356. message = message.substring(0, message.indexOf("Call Stack"));
  357. swal({
  358. type: 'error',
  359. title: monsterinsights_admin.deauth_loading_error_title,
  360. text: message,
  361. confirmButtonText: monsterinsights_admin.ok_text,
  362. }).catch(swal.noop);
  363. });
  364. };
  365. // Tools JS
  366. jQuery('#monsterinsights-url-builder input').keyup(monsterinsights_update_campaign_url);
  367. jQuery('#monsterinsights-url-builder input').click(monsterinsights_update_campaign_url);
  368. function monsterinsights_update_campaign_url() {
  369. var domain = jQuery('#monsterinsights-url-builer-domain').val().trim();
  370. var source = jQuery('#monsterinsights-url-builer-source').val().trim();
  371. var medium = jQuery('#monsterinsights-url-builer-medium').val().trim();
  372. var term = jQuery('#monsterinsights-url-builer-term').val().trim();
  373. var content = jQuery('#monsterinsights-url-builer-content').val().trim();
  374. var name = jQuery('#monsterinsights-url-builer-name').val().trim();
  375. var fragment = jQuery('#monsterinsights-url-builer-fragment').is(':checked');
  376. var file = domain.substring(domain.lastIndexOf("/") + 1);
  377. if ( fragment && file.length > 0 && file.indexOf('#') > -1 ) {
  378. // If we're going to use hash, but there's already a hash, use &
  379. fragment = '&';
  380. } else if ( ! fragment && file.length > 0 && file.indexOf('?') > -1 ) {
  381. // If we're going to use ?, but there's already one of those, use &
  382. fragment = '&';
  383. } else {
  384. // The attachment we want to use doesn't exist yet, use requested (? or #)
  385. fragment = fragment ? '#' : '?';
  386. }
  387. var html = domain + fragment + 'utm_source=' + encodeURIComponent(source);
  388. if (medium) {
  389. html = html + '&utm_medium=' + encodeURIComponent(medium);
  390. }
  391. if (name) {
  392. html = html + '&utm_campaign=' + encodeURIComponent(name);
  393. }
  394. if (term) {
  395. html = html + '&utm_term=' + encodeURIComponent(term);
  396. }
  397. if (content) {
  398. html = html + '&utm_content=' + encodeURIComponent(content);
  399. }
  400. if ( domain && source ) {
  401. jQuery('#monsterinsights-url-builer-url').html(html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"));
  402. } else {
  403. jQuery('#monsterinsights-url-builer-url').html('');
  404. }
  405. }
  406. // Addons JS
  407. // Addon background color
  408. if ( jQuery( "#monsterinsights-addons" ).length !== 0 ) {
  409. jQuery( "#wpbody").css("background-color", "#f1f1f1");
  410. jQuery( "body").css("background-color", "#f1f1f1");
  411. jQuery( "#wpfooter").css("background-color", "#f1f1f1");
  412. jQuery( "#wpbody-content").css("padding-bottom", "0px");
  413. }
  414. // Addons Search
  415. var addon_search_timeout;
  416. jQuery( 'form#add-on-search input#add-on-searchbox' ).on( 'keyup', function() {
  417. // Clear timeout
  418. clearTimeout( addon_search_timeout );
  419. // Get the search input, heading, results and cancel elements
  420. var search = jQuery( this ),
  421. search_terms = jQuery( search ).val().toLowerCase(),
  422. search_heading = jQuery( search ).data( 'heading' ),
  423. search_results = jQuery( search ).data( 'results' ),
  424. search_cancel = jQuery( search ).data( 'cancel' );
  425. // Show the Spinner
  426. jQuery( 'form#add-on-search .spinner' ).css( 'visibility', 'visible' );
  427. // If the search terms is less than 3 characters, show all Addons
  428. if ( search_terms.length < 3 ) {
  429. jQuery( 'div.monsterinsights-addon' ).fadeIn( 'fast', function() {
  430. // Hide the Spinner
  431. jQuery( 'form#add-on-search .spinner' ).css( 'visibility', 'hidden' );
  432. } );
  433. return;
  434. }
  435. // Iterate through the Addons, showing or hiding them depending on whether they
  436. // match the given search terms.
  437. jQuery( 'div.monsterinsights-addon' ).each( function() {
  438. if ( jQuery( 'h3.monsterinsights-addon-title', jQuery( this ) ).text().toLowerCase().search( search_terms ) >= 0 ) {
  439. // This Addon's title does match the search terms
  440. // Show
  441. jQuery( this ).fadeIn();
  442. } else {
  443. // This Addon's title does not match the search terms
  444. // Hide
  445. jQuery( this ).fadeOut();
  446. }
  447. } );
  448. // Hide the Spinner
  449. jQuery( 'form#add-on-search .spinner' ).css( 'visibility', 'hidden' );
  450. } );
  451. // Addons Sorting
  452. var monsterinsights_addons_licensed_sorting = new List( 'monsterinsights-addons-licensed', {
  453. valueNames: [ 'monsterinsights-addon-title' ]
  454. } );
  455. var monsterinsights_addons_unlicensed_sorting = new List( 'monsterinsights-addons-unlicensed', {
  456. valueNames: [ 'monsterinsights-addon-title' ]
  457. } );
  458. jQuery( 'select#monsterinsights-filter-select' ).on( 'change', function() {
  459. if ( typeof monsterinsights_addons_licensed_sorting.sort !== 'undefined' ) {
  460. monsterinsights_addons_licensed_sorting.sort( 'monsterinsights-addon-title', {
  461. order: jQuery( this ).val(),
  462. } );
  463. }
  464. if ( typeof monsterinsights_addons_unlicensed_sorting.sort !== 'undefined' ) {
  465. monsterinsights_addons_unlicensed_sorting.sort( 'monsterinsights-addon-title', {
  466. order: jQuery( this ).val(),
  467. } );
  468. }
  469. } );
  470. // Re-enable install button if user clicks on it, needs creds but tries to install another addon instead.
  471. jQuery('#monsterinsights-addons').on('click.refreshInstallAddon', '.monsterinsights-addon-action-button', function(e) {
  472. var el = jQuery(this);
  473. var buttons = jQuery('#monsterinsights-addons').find('.monsterinsights-addon-action-button');
  474. $.each(buttons, function(i, element) {
  475. if ( el == element ) {
  476. return true;
  477. }
  478. monsterinsightsAddonRefresh(element);
  479. });
  480. });
  481. // Activate Addon
  482. jQuery('#monsterinsights-addons').on('click.activateAddon', '.monsterinsights-activate-addon', function(e) {
  483. e.preventDefault();
  484. var $this = jQuery(this);
  485. // Remove any leftover error messages, output an icon and get the plugin basename that needs to be activated.
  486. jQuery('.monsterinsights-addon-error').remove();
  487. jQuery(this).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.activating);
  488. jQuery(this).next().css({'display' : 'inline-block', 'margin-top' : '0px'});
  489. var button = jQuery(this);
  490. var plugin = jQuery(this).attr('rel');
  491. var el = jQuery(this).parent().parent();
  492. var message = jQuery(this).parent().parent().find('.addon-status');
  493. // Process the Ajax to perform the activation.
  494. var opts = {
  495. url: ajaxurl,
  496. type: 'post',
  497. async: true,
  498. cache: false,
  499. dataType: 'json',
  500. data: {
  501. action: 'monsterinsights_activate_addon',
  502. nonce: monsterinsights_admin.activate_nonce,
  503. plugin: plugin,
  504. isnetwork: monsterinsights_admin.isnetwork
  505. },
  506. success: function(response) {
  507. // If there is a WP Error instance, output it here and quit the script.
  508. if ( response && true !== response ) {
  509. jQuery(el).slideDown('normal', function() {
  510. jQuery(this).after('<div class="monsterinsights-addon-error"><strong>' + response.error + '</strong></div>');
  511. $this.next().hide();
  512. jQuery('.monsterinsights-addon-error').delay(3000).slideUp();
  513. });
  514. return;
  515. }
  516. // The Ajax request was successful, so let's update the output.
  517. if ( monsterinsights_admin.isnetwork ) {
  518. jQuery(button).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.networkdeactivate).removeClass('monsterinsights-activate-addon').addClass('monsterinsights-deactivate-addon');
  519. } else {
  520. jQuery(button).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.deactivate).removeClass('monsterinsights-activate-addon').addClass('monsterinsights-deactivate-addon');
  521. }
  522. jQuery(message).text(monsterinsights_admin.active);
  523. // Trick here to wrap a span around he last word of the status
  524. var heading = jQuery(message), word_array, last_word, first_part;
  525. word_array = heading.html().split(/\s+/); // split on spaces
  526. last_word = word_array.pop(); // pop the last word
  527. first_part = word_array.join(' '); // rejoin the first words together
  528. heading.html([first_part, ' <span>', last_word, '</span>'].join(''));
  529. // Proceed with CSS changes
  530. jQuery(el).removeClass('monsterinsights-addon-inactive').addClass('monsterinsights-addon-active');
  531. $this.next().hide();
  532. },
  533. error: function(xhr, textStatus ,e) {
  534. $this.next().hide();
  535. return;
  536. }
  537. };
  538. $.ajax(opts);
  539. });
  540. // Deactivate Addon
  541. jQuery('#monsterinsights-addons').on('click.deactivateAddon', '.monsterinsights-deactivate-addon', function(e) {
  542. e.preventDefault();
  543. var $this = jQuery(this);
  544. // Remove any leftover error messages, output an icon and get the plugin basename that needs to be activated.
  545. jQuery('.monsterinsights-addon-error').remove();
  546. jQuery(this).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.deactivating);
  547. jQuery(this).next().css({'display' : 'inline-block', 'margin-top' : '0px'});
  548. var button = jQuery(this);
  549. var plugin = jQuery(this).attr('rel');
  550. var el = jQuery(this).parent().parent();
  551. var message = jQuery(this).parent().parent().find('.addon-status');
  552. // Process the Ajax to perform the activation.
  553. var opts = {
  554. url: ajaxurl,
  555. type: 'post',
  556. async: true,
  557. cache: false,
  558. dataType: 'json',
  559. data: {
  560. action: 'monsterinsights_deactivate_addon',
  561. nonce: monsterinsights_admin.deactivate_nonce,
  562. plugin: plugin,
  563. isnetwork: monsterinsights_admin.isnetwork
  564. },
  565. success: function(response) {
  566. // If there is a WP Error instance, output it here and quit the script.
  567. if ( response && true !== response ) {
  568. jQuery(el).slideDown('normal', function() {
  569. jQuery(this).after('<div class="monsterinsights-addon-error"><strong>' + response.error + '</strong></div>');
  570. $this.next().hide();
  571. jQuery('.monsterinsights-addon-error').delay(3000).slideUp();
  572. });
  573. return;
  574. }
  575. // The Ajax request was successful, so let's update the output.
  576. if ( monsterinsights_admin.isnetwork ) {
  577. jQuery(button).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.networkactivate).removeClass('monsterinsights-deactivate-addon').addClass('monsterinsights-activate-addon');
  578. } else {
  579. jQuery(button).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.activate).removeClass('monsterinsights-deactivate-addon').addClass('monsterinsights-activate-addon');
  580. }
  581. jQuery(message).text(monsterinsights_admin.inactive);
  582. // Trick here to wrap a span around he last word of the status
  583. var heading = jQuery(message), word_array, last_word, first_part;
  584. word_array = heading.html().split(/\s+/); // split on spaces
  585. last_word = word_array.pop(); // pop the last word
  586. first_part = word_array.join(' '); // rejoin the first words together
  587. heading.html([first_part, ' <span>', last_word, '</span>'].join(''));
  588. // Proceed with CSS changes
  589. jQuery(el).removeClass('monsterinsights-addon-active').addClass('monsterinsights-addon-inactive');
  590. $this.next().hide();
  591. },
  592. error: function(xhr, textStatus ,e) {
  593. $this.next().hide();
  594. return;
  595. }
  596. };
  597. $.ajax(opts);
  598. });
  599. // Install Addon
  600. jQuery('#monsterinsights-addons').on('click.installAddon', '.monsterinsights-install-addon', function(e) {
  601. e.preventDefault();
  602. var $this = jQuery(this);
  603. // Remove any leftover error messages, output an icon and get the plugin basename that needs to be activated.
  604. jQuery('.monsterinsights-addon-error').remove();
  605. jQuery(this).html('<i class="monsterinsights-cloud-download"></i> ' + monsterinsights_admin.installing);
  606. jQuery(this).next().css({'display' : 'inline-block', 'margin-top' : '0px'});
  607. var button = jQuery(this);
  608. var plugin = jQuery(this).attr('rel');
  609. var el = jQuery(this).parent().parent();
  610. var message = jQuery(this).parent().parent().find('.addon-status');
  611. // Process the Ajax to perform the activation.
  612. var opts = {
  613. url: ajaxurl,
  614. type: 'post',
  615. async: true,
  616. cache: false,
  617. dataType: 'json',
  618. data: {
  619. action: 'monsterinsights_install_addon',
  620. nonce: monsterinsights_admin.install_nonce,
  621. plugin: plugin
  622. },
  623. success: function(response) {
  624. // If there is a WP Error instance, output it here and quit the script.
  625. if ( response.error ) {
  626. jQuery(el).slideDown('normal', function() {
  627. jQuery(button).parent().parent().after('<div class="monsterinsights-addon-error"><div class="xinterior"><p><strong>' + response.error + '</strong></p></div></div>');
  628. jQuery(button).html('<i class="monsterinsights-cloud-download"></i> ' + monsterinsights_admin.install);
  629. $this.next().hide();
  630. jQuery('.monsterinsights-addon-error').delay(4000).slideUp();
  631. });
  632. return;
  633. }
  634. // If we need more credentials, output the form sent back to us.
  635. if ( response.form ) {
  636. // Display the form to gather the users credentials.
  637. jQuery(el).slideDown('normal', function() {
  638. jQuery(this).after('<div class="monsterinsights-addon-error">' + response.form + '</div>');
  639. $this.next().hide();
  640. });
  641. // Add a disabled attribute the install button if the creds are needed.
  642. jQuery(button).attr('disabled', true);
  643. jQuery('#monsterinsights-addons').on('click.installCredsAddon', '#upgrade', function(e) {
  644. // Prevent the default action, let the user know we are attempting to install again and go with it.
  645. e.preventDefault();
  646. $this.next().hide();
  647. jQuery(this).html('<i class="monsterinsights-cloud-download"></i> ' + monsterinsights_admin.installing);
  648. jQuery(this).next().css({'display' : 'inline-block', 'margin-top' : '0px'});
  649. // Now let's make another Ajax request once the user has submitted their credentials.
  650. var hostname = jQuery(this).parent().parent().find('#hostname').val();
  651. var username = jQuery(this).parent().parent().find('#username').val();
  652. var password = jQuery(this).parent().parent().find('#password').val();
  653. var proceed = jQuery(this);
  654. var connect = jQuery(this).parent().parent().parent().parent();
  655. var cred_opts = {
  656. url: ajaxurl,
  657. type: 'post',
  658. async: true,
  659. cache: false,
  660. dataType: 'json',
  661. data: {
  662. action: 'monsterinsights_install_addon',
  663. nonce: monsterinsights_admin.install_nonce,
  664. plugin: plugin,
  665. hostname: hostname,
  666. username: username,
  667. password: password
  668. },
  669. success: function(response) {
  670. // If there is a WP Error instance, output it here and quit the script.
  671. if ( response.error ) {
  672. jQuery(el).slideDown('normal', function() {
  673. jQuery(button).parent().parent().after('<div class="monsterinsights-addon-error"><strong>' + response.error + '</strong></div>');
  674. jQuery(button).html('<i class="monsterinsights-cloud-download"></i> ' + monsterinsights_admin.install);
  675. $this.next().hide();
  676. jQuery('.monsterinsights-addon-error').delay(4000).slideUp();
  677. });
  678. return;
  679. }
  680. if ( response.form ) {
  681. $this.next().hide();
  682. jQuery('.monsterinsights-inline-error').remove();
  683. jQuery(proceed).val(monsterinsights_admin.proceed);
  684. jQuery(proceed).after('<span class="monsterinsights-inline-error">' + monsterinsights_admin.connect_error + '</span>');
  685. return;
  686. }
  687. // The Ajax request was successful, so let's update the output.
  688. jQuery(connect).remove();
  689. jQuery(button).show();
  690. if ( monsterinsights_admin.isnetwork ) {
  691. jQuery(button).text(monsterinsights_admin.networkactivate).removeClass('monsterinsights-install-addon').addClass('monsterinsights-activate-addon');
  692. } else {
  693. jQuery(button).text(monsterinsights_admin.activate).removeClass('monsterinsights-install-addon').addClass('monsterinsights-activate-addon');
  694. }
  695. jQuery(button).attr('rel', response.plugin);
  696. jQuery(button).removeAttr('disabled');
  697. jQuery(message).text(monsterinsights_admin.inactive);
  698. // Trick here to wrap a span around he last word of the status
  699. var heading = jQuery(message), word_array, last_word, first_part;
  700. word_array = heading.html().split(/\s+/); // split on spaces
  701. last_word = word_array.pop(); // pop the last word
  702. first_part = word_array.join(' '); // rejoin the first words together
  703. heading.html([first_part, ' <span>', last_word, '</span>'].join(''));
  704. // Proceed with CSS changes
  705. jQuery(el).removeClass('monsterinsights-addon-not-installed').addClass('monsterinsights-addon-inactive');
  706. $this.next().hide();
  707. },
  708. error: function(xhr, textStatus ,e) {
  709. $this.next().hide();
  710. return;
  711. }
  712. };
  713. $.ajax(cred_opts);
  714. });
  715. // No need to move further if we need to enter our creds.
  716. return;
  717. }
  718. // The Ajax request was successful, so let's update the output.
  719. if ( monsterinsights_admin.isnetwork ) {
  720. jQuery(button).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.networkactivate).removeClass('monsterinsights-install-addon').addClass('monsterinsights-activate-addon');
  721. } else {
  722. jQuery(button).html('<i class="monsterinsights-toggle-on"></i> ' + monsterinsights_admin.activate).removeClass('monsterinsights-install-addon').addClass('monsterinsights-activate-addon');
  723. }
  724. jQuery(button).attr('rel', response.plugin);
  725. jQuery(message).text(monsterinsights_admin.inactive);
  726. // Trick here to wrap a span around he last word of the status
  727. var heading = jQuery(message), word_array, last_word, first_part;
  728. word_array = heading.html().split(/\s+/); // split on spaces
  729. last_word = word_array.pop(); // pop the last word
  730. first_part = word_array.join(' '); // rejoin the first words together
  731. heading.html([first_part, ' <span>', last_word, '</span>'].join(''));
  732. // Proceed with CSS changes
  733. jQuery(el).removeClass('monsterinsights-addon-not-installed').addClass('monsterinsights-addon-inactive');
  734. $this.next().hide();
  735. },
  736. error: function(xhr, textStatus ,e) {
  737. $this.next().hide();
  738. return;
  739. }
  740. };
  741. $.ajax(opts);
  742. });
  743. // Function to clear any disabled buttons and extra text if the user needs to add creds but instead tries to install a different addon.
  744. function monsterinsightsAddonRefresh(element) {
  745. if ( jQuery(element).attr('disabled') ) {
  746. jQuery(element).removeAttr('disabled');
  747. }
  748. if ( jQuery(element).parent().parent().hasClass('monsterinsights-addon-not-installed') ) {
  749. jQuery(element).text( monsterinsights_admin.install );
  750. }
  751. }
  752. jQuery(document).ready(function($) {
  753. monsterinsights_equalheight2column();
  754. });
  755. jQuery(document).on('click', ".monsterinsights-reports-show-selector-group > .btn", function( e ){
  756. e.preventDefault();
  757. var id = jQuery(this).attr("data-tid");
  758. jQuery(this).addClass("active").disable(true).siblings().removeClass("active").disable(false);
  759. if ( jQuery(this).hasClass("ten") ) {
  760. jQuery("#" + id + " .monsterinsights-reports-pages-list > .monsterinsights-listing-table-row").slice(10,50).hide();
  761. jQuery("#" + id + " .monsterinsights-reports-pages-list > .monsterinsights-listing-table-row").slice(0,10).show();
  762. } else if ( jQuery(this).hasClass("twentyfive") ) {
  763. jQuery("#" + id + " .monsterinsights-reports-pages-list > .monsterinsights-listing-table-row").slice(25,50).hide();
  764. jQuery("#" + id + " .monsterinsights-reports-pages-list > .monsterinsights-listing-table-row").slice(0,25).show();
  765. } else if ( jQuery(this).hasClass("fifty") ) {
  766. jQuery("#" + id + " .monsterinsights-reports-pages-list > .monsterinsights-listing-table-row").slice(0,50).show();
  767. }
  768. });
  769. /**
  770. * Handles tabbed interfaces within MonsterInsights:
  771. * - Settings Page
  772. * - Reports Page
  773. * - Tools Page
  774. */
  775. /* @todo: remove this comment, convert other comments to multiline (reduction safe), and namespace all variables (reduction safe) */
  776. // Reports graph tabs
  777. jQuery(document).on('click', '.monsterinsights-tabbed-nav > .monsterinsights-tabbed-nav-tab-title', function( e ){
  778. e.preventDefault();
  779. var tabname = jQuery(this).attr("data-tab");
  780. jQuery(this).addClass("active").siblings().removeClass("active");
  781. jQuery('.monsterinsights-tabbed-nav-panel').hide();
  782. jQuery('.monsterinsights-tabbed-nav-panel.' + tabname ).show();
  783. });
  784. jQuery( function() {
  785. MonsterInsightsTriggerTabs( true );
  786. });
  787. jQuery( window ).on( "hashchange", function( e ) {
  788. e.preventDefault();
  789. MonsterInsightsTriggerTabs( false );
  790. });
  791. function MonsterInsightsTriggerTabs( init ) {
  792. var window_hash = window.location.hash;
  793. var current_tab = '';
  794. var tab_nav = '.monsterinsights-main-nav-container';
  795. var tabs_section = '.monsterinsights-main-nav-tabs';
  796. var current_sub_tab = '';
  797. var sub_tabs_nav = '.monsterinsights-sub-nav-container';
  798. var sub_tabs_section = '.monsterinsights-sub-nav-tabs';
  799. var current_sub_tab_div = '';
  800. // If there's no hash, then we're on the default, which the page will auto load first tab + subtab as active
  801. if ( window_hash.indexOf( '#' ) > -1 ) {
  802. if ( window_hash.indexOf( '?' ) < 1 ) {
  803. // No ?, but there is a #
  804. current_tab = window_hash;
  805. var firstchildclick = jQuery( sub_tabs_nav );
  806. // If there's no subtab defined, let's see if the page has subtabs, and if so select the first one.
  807. if ( "0" in firstchildclick && "firstElementChild" in firstchildclick[0] && "hash" in firstchildclick[0].firstElementChild ) {
  808. current_sub_tab = firstchildclick[0].firstElementChild.hash;
  809. current_sub_tab_div = '#' + ( firstchildclick[0].firstElementChild.hash ).split( '?' )[1];
  810. }
  811. } else {
  812. // ? and a #
  813. var tab_split = window_hash.split( '?' );
  814. current_tab = tab_split[0];
  815. current_sub_tab = window_hash;
  816. current_sub_tab_div = '#' + tab_split[1];
  817. }
  818. // @todo: if the tab doesn't exist, we should fallback to finding the first tab and opening that
  819. // If we fallback, we should clear the sub_tab so we ensure we land on the first subtab of the new
  820. // tab, if that pages has subtabs.
  821. jQuery( tab_nav ).find( '.monsterinsights-active' ).removeClass( 'monsterinsights-active' );
  822. jQuery( tabs_section ).find( '.monsterinsights-active' ).removeClass( 'monsterinsights-active' );
  823. jQuery( sub_tabs_nav ).find( '.monsterinsights-active' ).removeClass( 'monsterinsights-active' );
  824. jQuery( sub_tabs_section ).find( '.monsterinsights-active' ).removeClass( 'monsterinsights-active' );
  825. jQuery( tab_nav ).find( 'a[href="' + current_tab + '"]' ).addClass( 'monsterinsights-active' );
  826. jQuery( tabs_section ).find( current_tab ).addClass( 'monsterinsights-active' );
  827. // Check to make sure the subtab given in the url exists, and then open it.
  828. if ( jQuery( sub_tabs_nav ).find( 'a[href="' + current_sub_tab + '"]' ).length == 1 ) {
  829. jQuery( sub_tabs_nav ).find( 'a[href="' + current_sub_tab + '"]' ).addClass( 'monsterinsights-active' );
  830. jQuery( sub_tabs_section ).find( current_sub_tab_div ).addClass( 'monsterinsights-active' );
  831. } else {
  832. // If the subtab given in the URL doesn't exist, let's see if the page has subtabs, and if so select the first one.
  833. var firstchildclick = jQuery( sub_tabs_nav );
  834. if ( "0" in firstchildclick && "firstElementChild" in firstchildclick[0] && "hash" in firstchildclick[0].firstElementChild ) {
  835. jQuery( sub_tabs_nav ).find( 'a[href="#' + (firstchildclick[0].firstElementChild.hash).split( '?' )[1] + '"]' ).addClass( 'monsterinsights-active' );
  836. jQuery( sub_tabs_section ).find( '#' + (firstchildclick[0].firstElementChild.hash).split( '?' )[1] ).addClass( 'monsterinsights-active' );
  837. }
  838. }
  839. if ( jQuery('.monsterinsights-main-nav-tabs .monsterinsights-main-nav-tab:not(".monsterinsights-active") .monsterinsights-tab-settings-notices .monsterinsights-notice' ).length > 0 ) {
  840. jQuery('.monsterinsights-main-nav-tabs .monsterinsights-main-nav-tab:not(".monsterinsights-active") .monsterinsights-tab-settings-notices .monsterinsights-notice' ).remove();
  841. }
  842. if ( jQuery('.monsterinsights-sub-nav-tabs .monsterinsights-sub-nav-tab:not("' + current_sub_tab_div + '") .monsterinsights-subtab-settings-notices .monsterinsights-notice' ).length > 0 ) {
  843. jQuery('.monsterinsights-sub-nav-tabs .monsterinsights-sub-nav-tab:not("' + current_sub_tab_div + '") .monsterinsights-subtab-settings-notices .monsterinsights-notice' ).remove();
  844. }
  845. if ( current_tab !== '#monsterinsights-main-tab-tracking' ) {
  846. if ( jQuery('.monsterinsights-sub-nav-tabs .monsterinsights-sub-nav-tab .monsterinsights-subtab-settings-notices .monsterinsights-notice' ).length > 0 ) {
  847. jQuery('.monsterinsights-sub-nav-tabs .monsterinsights-sub-nav-tab .monsterinsights-subtab-settings-notices .monsterinsights-notice' ).remove();
  848. }
  849. }
  850. // Is the window taller than the #adminmenuwrap?
  851. if (jQuery(window).height() > jQuery("#adminmenuwrap").height()) {
  852. // ...if so, make the #adminmenuwrap fixed
  853. jQuery('#adminmenuwrap').css('position', 'fixed');
  854. } else {
  855. //...otherwise, leave it relative
  856. jQuery('#adminmenuwrap').css('position', 'relative');
  857. }
  858. } else if ( init ) {
  859. // If we have a default open, else open one
  860. if ( jQuery(tab_nav + " .monsterinsights-active").length > 0 ){
  861. return;
  862. }
  863. jQuery(tab_nav).find('a:first').addClass( 'monsterinsights-active' );
  864. jQuery( tabs_section ).find('div:first').addClass( 'monsterinsights-active' );
  865. jQuery(sub_tabs_nav).find('a:first').addClass( 'monsterinsights-active' );
  866. jQuery( sub_tabs_section ).find('div:first').addClass( 'monsterinsights-active' );
  867. }
  868. }
  869. });
  870. function monsterinsights_equalheight2column(){
  871. jQuery('.monsterinsights-reports-2-column-container').each(function(i, elem) {
  872. jQuery(elem)
  873. .find('.monsterinsights-reports-data-table-tbody') // Only children of this row
  874. .matchHeight({byRow: false}); // Row detection gets confused so disable it
  875. jQuery(elem)
  876. .find('.monsterinsights-reports-2-column-panel') // Only children of this row
  877. .matchHeight({byRow: true}); // Row detection gets confused so disable it
  878. });
  879. }
  880. function monsterinsights_show_manual( ){
  881. document.getElementById("monsterinsights-google-ua-box").className = "";
  882. }
  883. var uorigindetected = 'no';
  884. // Reports:
  885. // Thanks ChartJS for making us have to do this nonsense.
  886. // A huge Thanks ChartJS for making us have to do this nonsense. Why ChartJS can't just fix non-initalization on hidden elements (or at least
  887. // give a generic action to re-fire initialization for in-view charts generically is beyond me)
  888. jQuery(document).ready(function($) {
  889. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  890. jQuery.fn.attrchange = function(callback) {
  891. if (MutationObserver) {
  892. var options = {
  893. subtree: false,
  894. attributes: true,
  895. attributeName: "class",
  896. };
  897. var observer = new MutationObserver(function(mutations) {
  898. mutations.forEach(function(e) {
  899. callback.call(e.target, e.attributeName);
  900. });
  901. });
  902. return this.each(function() {
  903. observer.observe(this, options);
  904. });
  905. }
  906. };
  907. jQuery('#monsterinsights-reports-page-main-nav .monsterinsights-main-nav-item.monsterinsights-nav-item').attrchange(function(attrName) {
  908. if ( attrName != 'class' ){
  909. return;
  910. }
  911. // Blur report shown
  912. jQuery( "#monsterinsights-reports-pages" ).addClass( "monsterinsights-mega-blur" );
  913. // Which report?
  914. var reportname = jQuery("#monsterinsights-reports-pages").find( "div.monsterinsights-main-nav-tab.monsterinsights-active" ).attr("id").replace("monsterinsights-main-tab-", "" );
  915. var reportid = jQuery("#monsterinsights-reports-pages").find( "div.monsterinsights-main-nav-tab.monsterinsights-active" ).attr("id");
  916. var start = moment( moment().subtract(30, 'days') ).tz(monsterinsights_admin.timezone).format('YYYY-MM-DD');
  917. var end = moment( moment().subtract( 1, 'days' ) ).tz(monsterinsights_admin.timezone).format('YYYY-MM-DD');
  918. swal({
  919. type: 'info',
  920. title: monsterinsights_admin.refresh_report_title,
  921. text: monsterinsights_admin.refresh_report_text,
  922. allowOutsideClick: false,
  923. allowEscapeKey: false,
  924. allowEnterKey: false,
  925. onOpen: function () {
  926. swal.showLoading();
  927. var data = {
  928. 'action' : 'monsterinsights_refresh_reports',
  929. 'security' : monsterinsights_admin.admin_nonce,
  930. 'isnetwork': monsterinsights_admin.isnetwork,
  931. 'start' : start,
  932. 'end' : end,
  933. 'report' : reportname,
  934. };
  935. jQuery.post(ajaxurl, data, function( response ) {
  936. if ( response.success && response.data.html ) {
  937. // Insert new data here
  938. jQuery("#monsterinsights-main-tab-" + reportname + " > .monsterinsights-reports-wrap").html( response.data.html );
  939. // Resize divs
  940. monsterinsights_equalheight2column();
  941. swal.close();
  942. } else {
  943. var swal_settings = {
  944. type: 'error',
  945. title: monsterinsights_admin.refresh_report_failure_title,
  946. html: response.data.message,
  947. };
  948. if ( response.data.data && response.data.data.footer ) {
  949. swal_settings.footer = response.data.data.footer;
  950. }
  951. swal(swal_settings).catch(swal.noop);
  952. }
  953. }).then(function (result) {
  954. // Unblur reports
  955. jQuery( "#monsterinsights-reports-pages" ).removeClass( "monsterinsights-mega-blur" );
  956. }).fail( function(xhr, textStatus, errorThrown) {
  957. var message = jQuery(xhr.responseText).text();
  958. message = message.substring(0, message.indexOf("Call Stack"));
  959. swal({
  960. type: 'error',
  961. title: monsterinsights_admin.refresh_report_failure_title,
  962. text: message,
  963. }).catch(swal.noop);
  964. // Unblur reports
  965. jQuery( "#monsterinsights-reports-pages" ).removeClass( "monsterinsights-mega-blur" );
  966. });
  967. }
  968. });
  969. });
  970. });