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