[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-admin/js/ -> privacy-tools.js (source)

   1  /**
   2   * @output wp-admin/js/privacy-tools.js
   3   */
   4  
   5  /**
   6   * Sets the interactions used by the User Privacy tools in WordPress.
   7   *
   8   * @param {jQueryStatic} $ The jQuery object.
   9   */
  10  jQuery( function( $ ) {
  11      var __ = wp.i18n.__,
  12          copiedNoticeTimeout;
  13  
  14      /**
  15       * Sets the state of the action.
  16       *
  17       * @param {jQuery} $action The action to set the state for.
  18       * @param {string} state   The state to set the action to.
  19       * @return {void}
  20       */
  21  	function setActionState( $action, state ) {
  22          $action.children().addClass( 'hidden' );
  23          $action.children( '.' + state ).removeClass( 'hidden' );
  24      }
  25  
  26      /**
  27       * Clears any results row after the request row.
  28       *
  29       * @param {jQuery} $requestRow The request row to clear results for.
  30       * @return {void}
  31       */
  32  	function clearResultsAfterRow( $requestRow ) {
  33          if ( $requestRow.next().hasClass( 'request-results' ) ) {
  34              $requestRow.next().remove();
  35          }
  36      }
  37  
  38      /**
  39       * Appends a results row after the request row.
  40       *
  41       * @param {jQuery}   $requestRow        The request row to append the results after.
  42       * @param {string}   classes            The classes to add to the results row.
  43       * @param {string}   summaryMessage     The summary message to display in the results row.
  44       * @param {string[]} additionalMessages Additional messages to display in the results row.
  45       * @return {void}
  46       */
  47  	function appendResultsAfterRow( $requestRow, classes, summaryMessage, additionalMessages ) {
  48          var itemList = '',
  49              resultRowClasses = 'request-results';
  50  
  51          clearResultsAfterRow( $requestRow );
  52  
  53          if ( additionalMessages.length ) {
  54              $.each( additionalMessages, function( index, value ) {
  55                  itemList = itemList + '<li>' + value + '</li>';
  56              });
  57              itemList = '<ul>' + itemList + '</ul>';
  58          }
  59  
  60          if ( $requestRow.hasClass( 'status-request-confirmed' ) ) {
  61              resultRowClasses = resultRowClasses + ' status-request-confirmed';
  62          }
  63  
  64          if ( $requestRow.hasClass( 'status-request-failed' ) ) {
  65              resultRowClasses = resultRowClasses + ' status-request-failed';
  66          }
  67  
  68          $requestRow.after( function() {
  69              return '<tr class="' + resultRowClasses + '"><th colspan="5">' +
  70                  '<div class="notice inline notice-alt ' + classes + '" role="alert">' +
  71                  '<p>' + summaryMessage + '</p>' +
  72                  itemList +
  73                  '</div>' +
  74                  '</th>' +
  75                  '</tr>';
  76          });
  77      }
  78  
  79      $( '.export-personal-data-handle' ).on( 'click', function( event ) {
  80          var $this          = $( this ),
  81              $action        = $this.parents( '.export-personal-data' ),
  82              $requestRow    = $this.parents( 'tr' ),
  83              $progress      = $requestRow.find( '.export-progress' ),
  84              $rowActions    = $this.parents( '.row-actions' ),
  85              requestID      = $action.data( 'request-id' ),
  86              nonce          = $action.data( 'nonce' ),
  87              exportersCount = $action.data( 'exporters-count' ),
  88              sendAsEmail    = $action.data( 'send-as-email' ) ? true : false;
  89  
  90          event.preventDefault();
  91          event.stopPropagation();
  92  
  93          $rowActions.addClass( 'processing' );
  94  
  95          $action.trigger( 'blur' );
  96          clearResultsAfterRow( $requestRow );
  97          setExportProgress( 0 );
  98  
  99          /**
 100           * Handles a successful export.
 101           *
 102           * @param {string} zipUrl The URL of the generated ZIP file, if available.
 103           * @return {void}
 104           */
 105  		function onExportDoneSuccess( zipUrl ) {
 106              var summaryMessage = __( 'This user&#8217;s personal data export link was sent.' );
 107  
 108              if ( 'undefined' !== typeof zipUrl ) {
 109                  summaryMessage = __( 'This user&#8217;s personal data export file was downloaded.' );
 110              }
 111  
 112              setActionState( $action, 'export-personal-data-success' );
 113  
 114              appendResultsAfterRow( $requestRow, 'notice-success', summaryMessage, [] );
 115  
 116              if ( 'undefined' !== typeof zipUrl ) {
 117                  window.location = zipUrl;
 118              } else if ( ! sendAsEmail ) {
 119                  onExportFailure( __( 'No personal data export file was generated.' ) );
 120              }
 121  
 122              setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
 123          }
 124  
 125          /**
 126           * Handles an export failure.
 127           *
 128           * @param {string} errorMessage The error message to display.
 129           * @return {void}
 130           */
 131  		function onExportFailure( errorMessage ) {
 132              var summaryMessage = __( 'An error occurred while attempting to export personal data.' );
 133  
 134              setActionState( $action, 'export-personal-data-failed' );
 135  
 136              if ( errorMessage ) {
 137                  appendResultsAfterRow( $requestRow, 'notice-error', summaryMessage, [ errorMessage ] );
 138              }
 139  
 140              setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
 141          }
 142  
 143          /**
 144           * Updates the progress of the export process.
 145           *
 146           * @param {number} exporterIndex The index of the exporter to process.
 147           * @return {void}
 148           */
 149  		function setExportProgress( exporterIndex ) {
 150              var progress       = ( exportersCount > 0 ? exporterIndex / exportersCount : 0 ),
 151                  progressString = Math.round( progress * 100 ).toString() + '%';
 152  
 153              $progress.html( progressString );
 154          }
 155  
 156          /**
 157           * Performs the next export request.
 158           *
 159           * @param {number} exporterIndex The index of the exporter to process.
 160           * @param {number} pageIndex     The index of the page to process for the current exporter.
 161           * @return {void}
 162           */
 163  		function doNextExport( exporterIndex, pageIndex ) {
 164              $.ajax(
 165                  {
 166                      url: window.ajaxurl,
 167                      data: {
 168                          action: 'wp-privacy-export-personal-data',
 169                          exporter: exporterIndex,
 170                          id: requestID,
 171                          page: pageIndex,
 172                          security: nonce,
 173                          sendAsEmail: sendAsEmail
 174                      },
 175                      method: 'post'
 176                  }
 177              ).done( function( response ) {
 178                  var responseData = response.data;
 179  
 180                  if ( ! response.success ) {
 181                      // e.g. invalid request ID.
 182                      setTimeout( function() { onExportFailure( response.data ); }, 500 );
 183                      return;
 184                  }
 185  
 186                  if ( ! responseData.done ) {
 187                      setTimeout( doNextExport( exporterIndex, pageIndex + 1 ) );
 188                  } else {
 189                      setExportProgress( exporterIndex );
 190                      if ( exporterIndex < exportersCount ) {
 191                          setTimeout( doNextExport( exporterIndex + 1, 1 ) );
 192                      } else {
 193                          setTimeout( function() { onExportDoneSuccess( responseData.url ); }, 500 );
 194                      }
 195                  }
 196              }).fail( function( jqxhr, textStatus, error ) {
 197                  // e.g. Nonce failure.
 198                  setTimeout( function() { onExportFailure( error ); }, 500 );
 199              });
 200          }
 201  
 202          // And now, let's begin.
 203          setActionState( $action, 'export-personal-data-processing' );
 204          doNextExport( 1, 1 );
 205      });
 206  
 207      $( '.remove-personal-data-handle' ).on( 'click', function( event ) {
 208          var $this         = $( this ),
 209              $action       = $this.parents( '.remove-personal-data' ),
 210              $requestRow   = $this.parents( 'tr' ),
 211              $progress     = $requestRow.find( '.erasure-progress' ),
 212              $rowActions   = $this.parents( '.row-actions' ),
 213              requestID     = $action.data( 'request-id' ),
 214              nonce         = $action.data( 'nonce' ),
 215              erasersCount  = $action.data( 'erasers-count' ),
 216              hasRemoved    = false,
 217              hasRetained   = false,
 218              messages      = [];
 219  
 220          event.preventDefault();
 221          event.stopPropagation();
 222  
 223          $rowActions.addClass( 'processing' );
 224  
 225          $action.trigger( 'blur' );
 226          clearResultsAfterRow( $requestRow );
 227          setErasureProgress( 0 );
 228  
 229          /**
 230           * Handles a successful erasure.
 231           *
 232           * @return {void}
 233           */
 234  		function onErasureDoneSuccess() {
 235              var summaryMessage = __( 'No personal data was found for this user.' ),
 236                  classes = 'notice-success';
 237  
 238              setActionState( $action, 'remove-personal-data-success' );
 239  
 240              if ( false === hasRemoved ) {
 241                  if ( false === hasRetained ) {
 242                      summaryMessage = __( 'No personal data was found for this user.' );
 243                  } else {
 244                      summaryMessage = __( 'Personal data was found for this user but was not erased.' );
 245                      classes = 'notice-warning';
 246                  }
 247              } else {
 248                  if ( false === hasRetained ) {
 249                      summaryMessage = __( 'All of the personal data found for this user was erased.' );
 250                  } else {
 251                      summaryMessage = __( 'Personal data was found for this user but some of the personal data found was not erased.' );
 252                      classes = 'notice-warning';
 253                  }
 254              }
 255              appendResultsAfterRow( $requestRow, classes, summaryMessage, messages );
 256  
 257              setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
 258          }
 259  
 260          /**
 261           * Handles an erasure failure.
 262           */
 263  		function onErasureFailure() {
 264              var summaryMessage = __( 'An error occurred while attempting to find and erase personal data.' );
 265  
 266              setActionState( $action, 'remove-personal-data-failed' );
 267  
 268              appendResultsAfterRow( $requestRow, 'notice-error', summaryMessage, [] );
 269  
 270              setTimeout( function() { $rowActions.removeClass( 'processing' ); }, 500 );
 271          }
 272  
 273          /**
 274           * Updates the progress of the erasure process.
 275           *
 276           * @param {number} eraserIndex The index of the eraser to process.
 277           * @return {void}
 278           */
 279  		function setErasureProgress( eraserIndex ) {
 280              var progress       = ( erasersCount > 0 ? eraserIndex / erasersCount : 0 ),
 281                  progressString = Math.round( progress * 100 ).toString() + '%';
 282  
 283              $progress.html( progressString );
 284          }
 285  
 286          /**
 287           * Performs the next erasure request.
 288           *
 289           * @param {number} eraserIndex The index of the eraser to process.
 290           * @param {number} pageIndex   The index of the page to process for the current eraser.
 291           * @return {void}
 292           */
 293  		function doNextErasure( eraserIndex, pageIndex ) {
 294              $.ajax({
 295                  url: window.ajaxurl,
 296                  data: {
 297                      action: 'wp-privacy-erase-personal-data',
 298                      eraser: eraserIndex,
 299                      id: requestID,
 300                      page: pageIndex,
 301                      security: nonce
 302                  },
 303                  method: 'post'
 304              }).done( function( response ) {
 305                  var responseData = response.data;
 306  
 307                  if ( ! response.success ) {
 308                      setTimeout( function() { onErasureFailure(); }, 500 );
 309                      return;
 310                  }
 311                  if ( responseData.items_removed ) {
 312                      hasRemoved = hasRemoved || responseData.items_removed;
 313                  }
 314                  if ( responseData.items_retained ) {
 315                      hasRetained = hasRetained || responseData.items_retained;
 316                  }
 317                  if ( responseData.messages ) {
 318                      messages = messages.concat( responseData.messages );
 319                  }
 320                  if ( ! responseData.done ) {
 321                      setTimeout( doNextErasure( eraserIndex, pageIndex + 1 ) );
 322                  } else {
 323                      setErasureProgress( eraserIndex );
 324                      if ( eraserIndex < erasersCount ) {
 325                          setTimeout( doNextErasure( eraserIndex + 1, 1 ) );
 326                      } else {
 327                          setTimeout( function() { onErasureDoneSuccess(); }, 500 );
 328                      }
 329                  }
 330              }).fail( function() {
 331                  setTimeout( function() { onErasureFailure(); }, 500 );
 332              });
 333          }
 334  
 335          // And now, let's begin.
 336          setActionState( $action, 'remove-personal-data-processing' );
 337  
 338          doNextErasure( 1, 1 );
 339      });
 340  
 341      // Privacy Policy page, copy action.
 342      $( document ).on( 'click', function( event ) {
 343          var $parent,
 344              range,
 345              $target = $( event.target ),
 346              copiedNotice = $target.siblings( '.success' );
 347  
 348          clearTimeout( copiedNoticeTimeout );
 349  
 350          if ( $target.is( 'button.privacy-text-copy' ) ) {
 351              $parent = $target.closest( '.privacy-settings-accordion-panel' );
 352  
 353              if ( $parent.length ) {
 354                  try {
 355                      var documentPosition = document.documentElement.scrollTop,
 356                          bodyPosition     = document.body.scrollTop;
 357  
 358                      // Setup copy.
 359                      window.getSelection().removeAllRanges();
 360  
 361                      // Hide tutorial content to remove from copied content.
 362                      range = document.createRange();
 363                      $parent.addClass( 'hide-privacy-policy-tutorial' );
 364  
 365                      // Copy action. Select only the dedicated copy-content wrapper
 366                      // so the actions toolbar (which contains the "Copied!" notice
 367                      // and button label) is never part of the selection - see #58969.
 368                      range.selectNodeContents( $parent.find( '.privacy-text-copy-content' )[0] );
 369                      window.getSelection().addRange( range );
 370                      document.execCommand( 'copy' );
 371  
 372                      // Reset section.
 373                      $parent.removeClass( 'hide-privacy-policy-tutorial' );
 374                      window.getSelection().removeAllRanges();
 375  
 376                      // Return scroll position - see #49540.
 377                      if ( documentPosition > 0 && documentPosition !== document.documentElement.scrollTop ) {
 378                          document.documentElement.scrollTop = documentPosition;
 379                      } else if ( bodyPosition > 0 && bodyPosition !== document.body.scrollTop ) {
 380                          document.body.scrollTop = bodyPosition;
 381                      }
 382  
 383                      // Display and speak notice to indicate action complete.
 384                      copiedNotice.addClass( 'visible' );
 385                      wp.a11y.speak( __( 'The suggested policy text has been copied to your clipboard.' ) );
 386  
 387                      // Delay notice dismissal.
 388                      copiedNoticeTimeout = setTimeout( function() {
 389                          copiedNotice.removeClass( 'visible' );
 390                      }, 3000 );
 391                  } catch ( er ) {}
 392              }
 393          }
 394      });
 395  
 396      // Label handling to focus the create page button on Privacy settings page.
 397      $( 'body.options-privacy-php label[for=create-page]' ).on( 'click', function( e ) {
 398          e.preventDefault();
 399          $( 'input#create-page' ).trigger( 'focus' );
 400      } );
 401  
 402      // Accordion handling in various new Privacy settings pages.
 403      $( '.privacy-settings-accordion' ).on( 'click', '.privacy-settings-accordion-trigger', function() {
 404          var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
 405  
 406          if ( isExpanded ) {
 407              $( this ).attr( 'aria-expanded', 'false' );
 408              $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
 409          } else {
 410              $( this ).attr( 'aria-expanded', 'true' );
 411              $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
 412          }
 413      } );
 414  });


Generated : Mon Sep 21 08:20:32 2026 Cross-referenced by PHPXref