PluginProbe
Authorizer / 2.8.8
Authorizer v2.8.8
3.15.3 3.15.2 3.15.1 3.15.0 3.14.3 3.14.4 3.14.2 3.14.1 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.9.0 2.9.1 2.9.10 2.9.11 2.9.12 2.9.13 2.9.2 2.9.3 2.9.6 All 126 releases
authorizer / js / authorizer.js

authorizer.js in Authorizer 2.8.8, at js/authorizer.js

1,340 lines 58.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * UI wiring for Authorizer Settings page.
3 */
4
5 /* global window, document, setTimeout, sessionStorage, ajaxurl, authL10n, history */
6 ( function( $ ) {
7
8 // Milliseconds for jQuery UI animations to complete.
9 var animationSpeed = 300;
10 // Milliseconds for shake animation (reject email address) to complete.
11 var shakeSpeed = 600;
12
13 /**
14 * Wiring and UI for Authorizer Settings page.
15 */
16
17 // Switch between pages in the Approved User list.
18 // @calls php wp_ajax_refresh_approved_user_list.
19 function refreshApprovedUserList( currentPage, searchTerm ) {
20 var $list = $( '#list_auth_settings_access_users_approved' );
21 var $spinner = $( '<span class="spinner is-active"></span>' ).css({
22 position: 'relative',
23 top: '40%',
24 left: '-240px',
25 });
26 var $overlay = $( '<div id="list_auth_settings_access_users_approved_overlay"></div>' ).css({
27 'background-color': '#f1f1f1',
28 'z-index': 1,
29 opacity: 0.8,
30 position: 'absolute',
31 top: $list.position().top + parseInt( $list.css( 'margin-top' ) ),
32 left: $list.position().left,
33 width: $list.width(),
34 height: $list.height(),
35 });
36 $overlay.append( $spinner );
37
38 // Show overlay and wait cursor.
39 $list.after( $overlay );
40 $( 'html' ).addClass( 'busy' );
41
42 $.post( ajaxurl, {
43 action: 'refresh_approved_user_list',
44 nonce: $( '#nonce_save_auth_settings' ).val(),
45 is_network_admin: authL10n.is_network_admin, // eslint-disable-line camelcase
46 paged: currentPage,
47 search: searchTerm,
48 }, function( response ) {
49 if ( response.success ) {
50 // Update user list and total user and page count.
51 $( '#list_auth_settings_access_users_approved' ).html( response.html );
52 $( '.displaying-num' ).html( response.total_users_html );
53 $( '.total-pages' ).html( response.total_pages_html );
54
55 // Adjust our current page if the query changed the total page count.
56 if ( currentPage > response.total_pages ) {
57 currentPage = response.total_pages;
58 }
59
60 // Update pager elements.
61 refreshApprovedUserPager( currentPage );
62
63 // Update querystring with new paged param value (but don't reload the page).
64 if ( history.pushState ) {
65 var url = window.location.href;
66 url = updateQueryStringParameter( url, 'paged', currentPage );
67 url = updateQueryStringParameter( url, 'search', searchTerm );
68 window.history.pushState( { path: url }, '', url );
69 }
70 }
71 // Remove overlay and wait cursor.
72 $overlay.remove();
73 $( 'html' ).removeClass( 'busy' );
74 }).fail( function() {
75 // Remove overlay and wait cursor.
76 $overlay.remove();
77 $( 'html' ).removeClass( 'busy' );
78 });
79 }
80
81 // Update the pager elements when changing pages.
82 function refreshApprovedUserPager( currentPage ) {
83 var totalPages = parseInt( $( '.total-pages' ).first().text().replace( /[^0-9]/g, '' ), 10 ) || 1;
84
85 // If total number of pages changed (because a search filter reduced it), make
86 // sure current page is not larger than it.
87 if ( currentPage > totalPages ) {
88 currentPage = totalPages;
89 }
90 if ( currentPage < 1 ) {
91 currentPage = 1;
92 }
93 if ( totalPages < 1 ) {
94 totalPages = 1;
95 }
96
97 // Update current page text input.
98 $( '#current-page-selector' ).val( currentPage );
99
100 // Update current page span.
101 $( '#table-paging .current-page-text' ).text( currentPage );
102
103 // Update first page button.
104 var $first = $( '.first-page' );
105 if ( $first.is( 'a' ) && currentPage <= 1 ) {
106 $first.replaceWith( '<span class="button disabled first-page tablenav-pages-navspan" aria-hidden="true">&laquo;</span>' );
107 } else if ( $first.is( 'span' ) && currentPage > 1 ) {
108 $first.replaceWith( '<a class="button first-page" href="' + updateQueryStringParameter( window.location.href, 'paged', '1' ) + '"><span class="screen-reader-text">' + authL10n.first_page + '</span><span aria-hidden="true">&laquo;</span></a>' );
109 }
110
111 // Update prev page button.
112 var $prev = $( '.prev-page' );
113 if ( $prev.is( 'a' ) && currentPage <= 1 ) {
114 $prev.replaceWith( '<span class="button disabled prev-page tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>' );
115 } else if ( currentPage > 1 ) {
116 $prev.replaceWith( '<a class="button prev-page" href="' + updateQueryStringParameter( window.location.href, 'paged', currentPage - 1 ) + '"><span class="screen-reader-text">' + authL10n.prev_page + '</span><span aria-hidden="true">&lsaquo;</span></a>' );
117 }
118
119 // Update next button.
120 var $next = $( '.next-page' );
121 if ( $next.is( 'a' ) && currentPage >= totalPages ) {
122 $next.replaceWith( '<span class="button disabled next-page tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>' );
123 } else if ( currentPage < totalPages ) {
124 $next.replaceWith( '<a class="button next-page" href="' + updateQueryStringParameter( window.location.href, 'paged', currentPage + 1 ) + '"><span class="screen-reader-text">' + authL10n.next_page + '</span><span aria-hidden="true">&rsaquo;</span></a>' );
125 }
126
127 // Update last button.
128 var $last = $( '.last-page' );
129 if ( $last.is( 'a' ) && currentPage >= totalPages ) {
130 $last.replaceWith( '<span class="button disabled last-page tablenav-pages-navspan" aria-hidden="true">&raquo;</span>' );
131 } else if ( $last.is( 'span' ) && currentPage < totalPages ) {
132 $last.replaceWith( '<a class="button last-page" href="' + updateQueryStringParameter( window.location.href, 'paged', totalPages ) + '"><span class="screen-reader-text">' + authL10n.next_page + '</span><span aria-hidden="true">&raquo;</span></a>' );
133 }
134 }
135
136 // Make changes to one of the user lists (pending, approved, blocked) via ajax.
137 // @calls php wp_ajax_update_auth_user.
138 function updateAuthUser( caller, setting, usersToEdit ) {
139 var accessUsersPending = [],
140 accessUsersApproved = [],
141 accessUsersBlocked = [],
142 nonce = $( '#nonce_save_auth_settings' ).val();
143
144 // Defaults:
145 // setting = 'access_users_pending' or 'access_users_approved' or 'access_users_blocked',
146 // usersToEdit = [
147 // {
148 // email: 'johndoe@example.com',
149 // role: 'subscriber',
150 // date_added: 'Jun 2014',
151 // edit_action: 'add' or 'remove' or 'change_role',
152 // local_user: true or false,
153 // multisite_user: true or false,
154 // }, {
155 // ...
156 // }
157 // ]
158 setting = typeof setting !== 'undefined' ? setting : 'none';
159
160 // If we are only editing a single user, make that user the only item in the array.
161 usersToEdit = typeof usersToEdit !== 'undefined' ? usersToEdit : [];
162 if ( ! Array.isArray( usersToEdit ) ) {
163 usersToEdit = [ usersToEdit ];
164 }
165
166 // Enable wait cursor.
167 $( 'html' ).addClass( 'busy' );
168
169 // Disable button (prevent duplicate clicks).
170 $( caller ).attr( 'disabled', 'disabled' );
171
172 // Enable spinner by element that triggered this event (caller).
173 var $row = $( caller ).closest( 'li' );
174 if ( $row.length > 0 ) {
175 var $spinner = $( '<span class="spinner is-active"></span>' ).css({
176 position: 'absolute',
177 top: $row.position().top,
178 left: $row.position().left + $row.width(),
179 });
180 $row.append( $spinner );
181 }
182
183 // Grab the value of the setting we are saving.
184 if ( setting === 'access_users_pending' ) {
185 accessUsersPending = usersToEdit;
186 } else if ( setting === 'access_users_approved' ) {
187 accessUsersApproved = usersToEdit;
188 } else if ( setting === 'access_users_blocked' ) {
189 accessUsersBlocked = usersToEdit;
190 }
191
192 $.post( ajaxurl, {
193 action: 'update_auth_user',
194 setting: setting,
195 access_users_pending: accessUsersPending, // eslint-disable-line camelcase
196 access_users_approved: accessUsersApproved, // eslint-disable-line camelcase
197 access_users_blocked: accessUsersBlocked, // eslint-disable-line camelcase
198 nonce: nonce,
199 }, function( response ) {
200 // Server responded, but if success isn't true it failed to save.
201 var succeeded = response.success;
202 var spinnerText = succeeded ? authL10n.saved + '.' : '<span style="color: red;">' + authL10n.failed + '.</span>';
203 var spinnerWait = succeeded ? 500 : 2000;
204
205 // Remove any new user entries that were rejected by the server.
206 if ( response.invalid_emails.length > 0 ) {
207 for ( var i = 0; i < response.invalid_emails.length; i++ ) {
208 var duplicateEmail = response.invalid_emails[i];
209 $( 'li.new-user .auth-email[value="' + duplicateEmail + '"]' )
210 .siblings( '.spinner' ).addClass( 'duplicate' ).append( '<span class="spinner-text" style="color: red;">' + authL10n.duplicate + '.</span>' )
211 .parent().fadeOut( spinnerWait, function() { $( this ).remove(); }); // jshint ignore:line
212 }
213 }
214
215 // Show message ('Saved', 'Failed', or 'Saved, removing duplicates').
216 $( 'form .spinner:not(:has(.spinner-text)):not(.duplicate)' ).append( '<span class="spinner-text">' + spinnerText + '</span>' ).delay( spinnerWait ).hide( animationSpeed, function() {
217 $( this ).remove();
218 });
219 $( caller ).removeAttr( 'disabled' );
220
221 // Disable wait cursor.
222 $( 'html' ).removeClass( 'busy' );
223 }).fail( function() {
224 // Fail fires if the server doesn't respond or responds with 500 codes
225 var succeeded = false;
226 var spinnerText = succeeded ? authL10n.saved + '.' : '<span style="color: red;">' + authL10n.failed + '.</span>';
227 var spinnerWait = succeeded ? 500 : 2000;
228 $( 'form .spinner:not(:has(.spinner-text))' ).append( '<span class="spinner-text">' + spinnerText + '</span>' ).delay( spinnerWait ).hide( animationSpeed, function() {
229 $( this ).remove();
230 });
231 $( caller ).removeAttr( 'disabled' );
232
233 // Disable wait cursor.
234 $( 'html' ).removeClass( 'busy' );
235 });
236 }
237
238
239 // Hide or show (with overlay) the multisite settings based on the "multisite override" setting.
240 function hideMultisiteSettingsIfDisabled() {
241 if ( $( '#auth_settings_multisite_override' ).length === 0 ) {
242 return;
243 }
244
245 var settings = $( '#auth_multisite_settings' );
246 var overlay = $( '#auth_multisite_settings_disabled_overlay' );
247
248 if ( $( '#auth_settings_multisite_override' ).is( ':checked' ) ) {
249 overlay.hide( animationSpeed );
250 } else {
251 overlay.css({
252 'background-color': '#f1f1f1',
253 'z-index': 1,
254 opacity: 0.8,
255 position: 'absolute',
256 top: settings.position().top,
257 left: settings.position().left - 20,
258 width: '100%',
259 height: settings.height(),
260 'padding-left': 20,
261 });
262 overlay.show();
263 }
264 }
265
266 // Helper function to remove duplicate entries from an array of strings.
267 function removeDuplicatesFromArrayOfStrings( arrayOfStrings ) {
268 var seen = {};
269 return arrayOfStrings.filter( function( item ) {
270 return seen.hasOwnProperty( item ) ? false : ( seen[item] = true );
271 });
272 }
273
274 // Helper function to hide/show wordpress option
275 function animateOption( action, option ) {
276 if ( action === 'show' ) {
277 $( 'div.animated_wrapper', option ).slideDown( animationSpeed );
278 $( 'th', option ).animate({ padding: '20px 10px 20px 0' }, { duration: animationSpeed });
279 $( 'td', option ).animate({ padding: '15px 10px' }, { duration: animationSpeed });
280 } else if ( action === 'hide' ) {
281 $( 'div.animated_wrapper', option ).slideUp( animationSpeed );
282 $( 'td, th', option ).animate({ padding: '0px' }, { duration: animationSpeed });
283 } else if ( action === 'hide_immediately' ) {
284 $( 'div.animated_wrapper', option ).hide();
285 $( 'td, th', option ).css({ padding: '0px' });
286 }
287 }
288
289 // Helper function to grab a querystring param value by name
290 function getParameterByName( needle, haystack ) {
291 needle = needle.replace( /[\[]/, '\\\[').replace(/[\]]/, '\\\]' ); // eslint-disable-line no-useless-escape
292 var regex = new RegExp( '[\\?&]' + needle + '=([^&#]*)' );
293 var results = regex.exec( haystack );
294 if ( results === null ) {
295 return '';
296 } else {
297 return decodeURIComponent( results[1].replace( /\+/g, ' ' ) );
298 }
299 }
300
301 // Helper function to return a short date (e.g., Jul 2013) for today's date
302 function getShortDate( date ) {
303 date = typeof date !== 'undefined' ? date : new Date();
304 var month = '';
305 switch ( date.getMonth() ) {
306 case 0: month = 'Jan'; break;
307 case 1: month = 'Feb'; break;
308 case 2: month = 'Mar'; break;
309 case 3: month = 'Apr'; break;
310 case 4: month = 'May'; break;
311 case 5: month = 'Jun'; break;
312 case 6: month = 'Jul'; break;
313 case 7: month = 'Aug'; break;
314 case 8: month = 'Sep'; break;
315 case 9: month = 'Oct'; break;
316 case 10: month = 'Nov'; break;
317 case 11: month = 'Dec'; break;
318 }
319 return month + ' ' + date.getFullYear();
320 }
321
322 // Helper function to grab a querystring value
323 function getQuerystringValuesByKey( key ) {
324 var re = new RegExp( '(?:\\?|&)' + key + '=(.*?)(?=&|$)', 'gi' );
325 var matchingValues = [];
326 var match;
327 while ( ( match = re.exec( document.location.search ) ) !== null ) {
328 matchingValues.push( match[1] );
329 }
330 return matchingValues;
331 }
332
333 // Helper function to check if an email address is valid. If allowWildcardEmail
334 // is true, then any string starting with an @ is valid.
335 function validEmail( email, allowWildcardEmail ) {
336 allowWildcardEmail = typeof allowWildcardEmail !== 'undefined' ? allowWildcardEmail : false;
337 var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
338 return email.length > 0 && ( re.test( email ) || email.startsWith( '@' ) );
339 }
340
341 // Helper function to set or update a querystring value.
342 function updateQueryStringParameter( uri, key, value ) {
343 // Remove the hash before operating on the URI.
344 var i = uri.indexOf( '#' );
345 var hash = i === -1 ? '' : uri.substr( i );
346 uri = i === -1 ? uri : uri.substr( 0, i );
347
348 var re = new RegExp( '([?&])' + key + '=.*?(&|$)', 'i' );
349 var separator = uri.indexOf( '?' ) !== -1 ? '&' : '?';
350
351 if ( ! value ) {
352 // Remove key-value pair if empty.
353 uri = uri.replace( new RegExp( '([?&]?)' + key + '=[^&]*', 'i' ), '' );
354 if ( uri.slice( -1 ) === '?' ) {
355 uri = uri.slice( 0, -1 );
356 }
357 // Replace first occurrence of & by ? if no ? is present.
358 if ( uri.indexOf( '?' ) === -1 ) {
359 uri = uri.replace( /&/, '?' );
360 }
361 } else if ( uri.match( re ) ) {
362 uri = uri.replace( re, '$1' + key + '=' + value + '$2' );
363 } else {
364 uri = uri + separator + key + '=' + value;
365 }
366 return uri + hash;
367 }
368
369
370 /**
371 * Wire up actions when document has loaded.
372 */
373
374
375 $( document ).ready( function() {
376 // Grab references to form elements that we will show/hide on page load
377 /* eslint-disable camelcase */
378 var auth_settings_access_role_receive_pending_emails = $( '#auth_settings_access_role_receive_pending_emails' ).closest( 'tr' );
379 var auth_settings_access_pending_redirect_to_message = $( '#wp-auth_settings_access_pending_redirect_to_message-wrap' ).closest( 'tr' );
380 var auth_settings_access_blocked_redirect_to_message = $( '#wp-auth_settings_access_blocked_redirect_to_message-wrap' ).closest( 'tr' );
381 var auth_settings_access_should_email_approved_users = $( '#auth_settings_access_should_email_approved_users' ).closest( 'tr' );
382 var auth_settings_access_email_approved_users_subject = $( '#auth_settings_access_email_approved_users_subject' ).closest( 'tr' );
383 var auth_settings_access_email_approved_users_body = $( '#wp-auth_settings_access_email_approved_users_body-wrap' ).closest( 'tr' );
384 var auth_settings_access_public_pages = $( '#auth_settings_access_public_pages' ).closest( 'tr' );
385 var auth_settings_access_redirect_to_login = $( '#radio_auth_settings_access_redirect_to_login' ).closest( 'tr' );
386 var auth_settings_access_public_warning = $( '#radio_auth_settings_access_public_warning' ).closest( 'tr' );
387 var auth_settings_access_redirect_to_message = $( '#wp-auth_settings_access_redirect_to_message-wrap' ).closest( 'tr' );
388 var auth_settings_external_google_clientid = $( '#auth_settings_google_clientid' ).closest( 'tr' );
389 var auth_settings_external_google_clientsecret = $( '#auth_settings_google_clientsecret' ).closest( 'tr' );
390 var auth_settings_external_google_hosteddomain = $( '#auth_settings_google_hosteddomain' ).closest( 'tr' );
391 var auth_settings_external_cas_custom_label = $( '#auth_settings_cas_custom_label' ).closest( 'tr' );
392 var auth_settings_external_cas_host = $( '#auth_settings_cas_host' ).closest( 'tr' );
393 var auth_settings_external_cas_port = $( '#auth_settings_cas_port' ).closest( 'tr' );
394 var auth_settings_external_cas_path = $( '#auth_settings_cas_path' ).closest( 'tr' );
395 var auth_settings_external_cas_version = $( '#auth_settings_cas_version' ).closest( 'tr' );
396 var auth_settings_external_cas_attr_email = $( '#auth_settings_cas_attr_email' ).closest( 'tr' );
397 var auth_settings_external_cas_attr_first_name = $( '#auth_settings_cas_attr_first_name' ).closest( 'tr' );
398 var auth_settings_external_cas_attr_last_name = $( '#auth_settings_cas_attr_last_name' ).closest( 'tr' );
399 var auth_settings_external_cas_attr_update_on_login = $( '#auth_settings_cas_attr_update_on_login' ).closest( 'tr' );
400 var auth_settings_external_cas_auto_login = $( '#auth_settings_cas_auto_login' ).closest( 'tr' );
401 var auth_settings_external_cas_link_on_username = $( '#auth_settings_cas_link_on_username' ).closest( 'tr' );
402 var auth_settings_external_ldap_host = $( '#auth_settings_ldap_host' ).closest( 'tr' );
403 var auth_settings_external_ldap_port = $( '#auth_settings_ldap_port' ).closest( 'tr' );
404 var auth_settings_external_ldap_search_base = $( '#auth_settings_ldap_search_base' ).closest( 'tr' );
405 var auth_settings_external_ldap_uid = $( '#auth_settings_ldap_uid' ).closest( 'tr' );
406 var auth_settings_external_ldap_attr_email = $( '#auth_settings_ldap_attr_email' ).closest( 'tr' );
407 var auth_settings_external_ldap_user = $( '#auth_settings_ldap_user' ).closest( 'tr' );
408 var auth_settings_external_ldap_password = $( '#auth_settings_ldap_password' ).closest( 'tr' );
409 var auth_settings_external_ldap_tls = $( '#auth_settings_ldap_tls' ).closest( 'tr' );
410 var auth_settings_external_ldap_lostpassword_url = $( '#auth_settings_ldap_lostpassword_url' ).closest( 'tr' );
411 var auth_settings_external_ldap_attr_first_name = $( '#auth_settings_ldap_attr_first_name' ).closest( 'tr' );
412 var auth_settings_external_ldap_attr_last_name = $( '#auth_settings_ldap_attr_last_name' ).closest( 'tr' );
413 var auth_settings_external_ldap_attr_update_on_login = $( '#auth_settings_ldap_attr_update_on_login' ).closest( 'tr' );
414 /* eslint-enable */
415
416 // Wrap the th and td in the rows above so we can animate their heights (can't animate tr heights with jquery)
417 $( 'th, td', auth_settings_access_role_receive_pending_emails ).wrapInner( '<div class="animated_wrapper" />' );
418 $( 'th, td', auth_settings_access_pending_redirect_to_message ).wrapInner( '<div class="animated_wrapper" />' );
419 $( 'th, td', auth_settings_access_blocked_redirect_to_message ).wrapInner( '<div class="animated_wrapper" />' );
420 $( 'th, td', auth_settings_access_should_email_approved_users ).wrapInner( '<div class="animated_wrapper" />' );
421 $( 'th, td', auth_settings_access_email_approved_users_subject ).wrapInner( '<div class="animated_wrapper" />' );
422 $( 'th, td', auth_settings_access_email_approved_users_body ).wrapInner( '<div class="animated_wrapper" />' );
423 $( 'th, td', auth_settings_access_public_pages ).wrapInner( '<div class="animated_wrapper" />' );
424 $( 'th, td', auth_settings_access_redirect_to_login ).wrapInner( '<div class="animated_wrapper" />' );
425 $( 'th, td', auth_settings_access_public_warning ).wrapInner( '<div class="animated_wrapper" />' );
426 $( 'th, td', auth_settings_access_redirect_to_message ).wrapInner( '<div class="animated_wrapper" />' );
427 $( 'th, td', auth_settings_external_google_clientid ).wrapInner( '<div class="animated_wrapper" />' );
428 $( 'th, td', auth_settings_external_google_clientsecret ).wrapInner( '<div class="animated_wrapper" />' );
429 $( 'th, td', auth_settings_external_google_hosteddomain ).wrapInner( '<div class="animated_wrapper" />' );
430 $( 'th, td', auth_settings_external_cas_custom_label ).wrapInner( '<div class="animated_wrapper" />' );
431 $( 'th, td', auth_settings_external_cas_host ).wrapInner( '<div class="animated_wrapper" />' );
432 $( 'th, td', auth_settings_external_cas_port ).wrapInner( '<div class="animated_wrapper" />' );
433 $( 'th, td', auth_settings_external_cas_path ).wrapInner( '<div class="animated_wrapper" />' );
434 $( 'th, td', auth_settings_external_cas_version ).wrapInner( '<div class="animated_wrapper" />' );
435 $( 'th, td', auth_settings_external_cas_attr_email ).wrapInner( '<div class="animated_wrapper" />' );
436 $( 'th, td', auth_settings_external_cas_attr_first_name ).wrapInner( '<div class="animated_wrapper" />' );
437 $( 'th, td', auth_settings_external_cas_attr_last_name ).wrapInner( '<div class="animated_wrapper" />' );
438 $( 'th, td', auth_settings_external_cas_attr_update_on_login ).wrapInner( '<div class="animated_wrapper" />' );
439 $( 'th, td', auth_settings_external_cas_auto_login ).wrapInner( '<div class="animated_wrapper" />' );
440 $( 'th, td', auth_settings_external_cas_link_on_username ).wrapInner( '<div class="animated_wrapper" />' );
441 $( 'th, td', auth_settings_external_ldap_host ).wrapInner( '<div class="animated_wrapper" />' );
442 $( 'th, td', auth_settings_external_ldap_port ).wrapInner( '<div class="animated_wrapper" />' );
443 $( 'th, td', auth_settings_external_ldap_search_base ).wrapInner( '<div class="animated_wrapper" />' );
444 $( 'th, td', auth_settings_external_ldap_uid ).wrapInner( '<div class="animated_wrapper" />' );
445 $( 'th, td', auth_settings_external_ldap_attr_email ).wrapInner( '<div class="animated_wrapper" />' );
446 $( 'th, td', auth_settings_external_ldap_user ).wrapInner( '<div class="animated_wrapper" />' );
447 $( 'th, td', auth_settings_external_ldap_password ).wrapInner( '<div class="animated_wrapper" />' );
448 $( 'th, td', auth_settings_external_ldap_tls ).wrapInner( '<div class="animated_wrapper" />' );
449 $( 'th, td', auth_settings_external_ldap_lostpassword_url ).wrapInner( '<div class="animated_wrapper" />' );
450 $( 'th, td', auth_settings_external_ldap_attr_first_name ).wrapInner( '<div class="animated_wrapper" />' );
451 $( 'th, td', auth_settings_external_ldap_attr_last_name ).wrapInner( '<div class="animated_wrapper" />' );
452 $( 'th, td', auth_settings_external_ldap_attr_update_on_login ).wrapInner( '<div class="animated_wrapper" />' );
453
454 // If we're viewing the dashboard widget, reset a couple of the relevant
455 // option variables (since they aren't nested in table rows).
456 if ( $( '#auth_dashboard_widget' ).length ) {
457 // Remove the helper link, since there are no tabs on the dashboard widget
458 $( '#dashboard_link_approved_users' ).contents().unwrap();
459 }
460
461 // Hide settings unless "Only approved users" is checked
462 if ( ! $( '#radio_auth_settings_access_who_can_login_approved_users' ).is( ':checked' ) ) {
463 animateOption( 'hide_immediately', auth_settings_access_role_receive_pending_emails );
464 animateOption( 'hide_immediately', auth_settings_access_pending_redirect_to_message );
465 animateOption( 'hide_immediately', auth_settings_access_blocked_redirect_to_message );
466 animateOption( 'hide_immediately', auth_settings_access_should_email_approved_users );
467 }
468
469 // Hide Welcome email body/subject options if "Send welcome email" is off.
470 if ( ! $( '#auth_settings_access_should_email_approved_users' ).is( ':checked' ) ) {
471 animateOption( 'hide_immediately', auth_settings_access_email_approved_users_subject );
472 animateOption( 'hide_immediately', auth_settings_access_email_approved_users_body );
473 }
474
475 // On load: Show/hide public access options if everyone can see site
476 if ( ! $( '#radio_auth_settings_access_who_can_view_logged_in_users' ).is( ':checked' ) ) {
477 animateOption( 'hide_immediately', auth_settings_access_public_pages );
478 animateOption( 'hide_immediately', auth_settings_access_redirect_to_login );
479 animateOption( 'hide_immediately', auth_settings_access_public_warning );
480 animateOption( 'hide_immediately', auth_settings_access_redirect_to_message );
481 }
482
483 // Hide Google options if unchecked
484 if ( ! $( '#auth_settings_google' ).is( ':checked' ) ) {
485 animateOption( 'hide_immediately', auth_settings_external_google_clientid );
486 animateOption( 'hide_immediately', auth_settings_external_google_clientsecret );
487 animateOption( 'hide_immediately', auth_settings_external_google_hosteddomain );
488 }
489
490 // Hide CAS options if unchecked
491 if ( ! $( '#auth_settings_cas' ).is( ':checked' ) ) {
492 animateOption( 'hide_immediately', auth_settings_external_cas_custom_label );
493 animateOption( 'hide_immediately', auth_settings_external_cas_host );
494 animateOption( 'hide_immediately', auth_settings_external_cas_port );
495 animateOption( 'hide_immediately', auth_settings_external_cas_path );
496 animateOption( 'hide_immediately', auth_settings_external_cas_version );
497 animateOption( 'hide_immediately', auth_settings_external_cas_attr_email );
498 animateOption( 'hide_immediately', auth_settings_external_cas_attr_first_name );
499 animateOption( 'hide_immediately', auth_settings_external_cas_attr_last_name );
500 animateOption( 'hide_immediately', auth_settings_external_cas_attr_update_on_login );
501 animateOption( 'hide_immediately', auth_settings_external_cas_auto_login );
502 animateOption( 'hide_immediately', auth_settings_external_cas_link_on_username );
503 }
504
505 // Hide LDAP options if unchecked
506 if ( ! $( '#auth_settings_ldap' ).is( ':checked' ) ) {
507 animateOption( 'hide_immediately', auth_settings_external_ldap_host );
508 animateOption( 'hide_immediately', auth_settings_external_ldap_port );
509 animateOption( 'hide_immediately', auth_settings_external_ldap_search_base );
510 animateOption( 'hide_immediately', auth_settings_external_ldap_uid );
511 animateOption( 'hide_immediately', auth_settings_external_ldap_attr_email );
512 animateOption( 'hide_immediately', auth_settings_external_ldap_user );
513 animateOption( 'hide_immediately', auth_settings_external_ldap_password );
514 animateOption( 'hide_immediately', auth_settings_external_ldap_tls );
515 animateOption( 'hide_immediately', auth_settings_external_ldap_lostpassword_url );
516 animateOption( 'hide_immediately', auth_settings_external_ldap_attr_first_name );
517 animateOption( 'hide_immediately', auth_settings_external_ldap_attr_last_name );
518 animateOption( 'hide_immediately', auth_settings_external_ldap_attr_update_on_login );
519 }
520
521 // Event handler: Hide "Handle unauthorized visitors" option if access is granted to "Everyone"
522 $( 'input[name="auth_settings[access_who_can_login]"]' ).change( function() {
523 // Hide settings unless "Only approved users" is checked
524 var action = $( '#radio_auth_settings_access_who_can_login_approved_users' ).is( ':checked' ) ? 'show' : 'hide';
525 animateOption( action, auth_settings_access_role_receive_pending_emails );
526 animateOption( action, auth_settings_access_pending_redirect_to_message );
527 animateOption( action, auth_settings_access_blocked_redirect_to_message );
528 animateOption( action, auth_settings_access_should_email_approved_users );
529 action = action === 'show' && $( '#auth_settings_access_should_email_approved_users' ).is( ':checked' ) ? 'show' : 'hide_immediately';
530 animateOption( action, auth_settings_access_email_approved_users_subject );
531 animateOption( action, auth_settings_access_email_approved_users_body );
532 });
533
534 // Event handler: Hide Welcome email body/subject options if "Send welcome email" is off.
535 $( 'input[name="auth_settings[access_should_email_approved_users]"]' ).change( function() {
536 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
537 animateOption( action, auth_settings_access_email_approved_users_subject );
538 animateOption( action, auth_settings_access_email_approved_users_body );
539 });
540
541 // Event handler: Hide "Handle unauthorized visitors" option if access is granted to "Everyone"
542 $( 'input[name="auth_settings[access_who_can_view]"]' ).change( function() {
543 var action = $( '#radio_auth_settings_access_who_can_view_everyone' ).is( ':checked' ) ? 'hide' : 'show';
544 animateOption( action, auth_settings_access_redirect_to_login );
545 animateOption( action, auth_settings_access_redirect_to_message );
546 animateOption( action, auth_settings_access_public_pages );
547 animateOption( action, auth_settings_access_public_warning );
548 });
549
550 // Event handler: Show/hide Google options based on checkbox
551 $( 'input[name="auth_settings[google]"]' ).change( function() {
552 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
553 animateOption( action, auth_settings_external_google_clientid );
554 animateOption( action, auth_settings_external_google_clientsecret );
555 animateOption( action, auth_settings_external_google_hosteddomain );
556 });
557
558 // Event handler: Show/hide CAS options based on checkbox
559 $( 'input[name="auth_settings[cas]"]' ).change( function() {
560 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
561 animateOption( action, auth_settings_external_cas_custom_label );
562 animateOption( action, auth_settings_external_cas_host );
563 animateOption( action, auth_settings_external_cas_port );
564 animateOption( action, auth_settings_external_cas_path );
565 animateOption( action, auth_settings_external_cas_version );
566 animateOption( action, auth_settings_external_cas_attr_email );
567 animateOption( action, auth_settings_external_cas_attr_first_name );
568 animateOption( action, auth_settings_external_cas_attr_last_name );
569 animateOption( action, auth_settings_external_cas_attr_update_on_login );
570 animateOption( action, auth_settings_external_cas_auto_login );
571 animateOption( action, auth_settings_external_cas_link_on_username );
572 });
573
574 // Event handler: Show/hide LDAP options based on checkbox
575 $( 'input[name="auth_settings[ldap]"]' ).change( function() {
576 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
577 animateOption( action, auth_settings_external_ldap_host );
578 animateOption( action, auth_settings_external_ldap_port );
579 animateOption( action, auth_settings_external_ldap_search_base );
580 animateOption( action, auth_settings_external_ldap_uid );
581 animateOption( action, auth_settings_external_ldap_attr_email );
582 animateOption( action, auth_settings_external_ldap_user );
583 animateOption( action, auth_settings_external_ldap_password );
584 animateOption( action, auth_settings_external_ldap_tls );
585 animateOption( action, auth_settings_external_ldap_lostpassword_url );
586 animateOption( action, auth_settings_external_ldap_attr_first_name );
587 animateOption( action, auth_settings_external_ldap_attr_last_name );
588 animateOption( action, auth_settings_external_ldap_attr_update_on_login );
589 });
590
591 // Show save button if usermeta field is modified.
592 $( 'form input.auth-usermeta' ).on( 'keyup', function( event ) {
593 // Don't do anything if tab or arrow keys were pressed.
594 if ( event.which === 9 || event.which === 37 || event.which === 38 || event.which === 39 || event.which === 40 ) {
595 return;
596 }
597 $( this ).siblings( '.button' ).css( 'display', 'inline-block' );
598 });
599
600 // List management function: pressing enter in the new approved or new
601 // blocked user (email or role field) adds the user to the list.
602 $( '#new_approved_user_email, #new_approved_user_role, #new_blocked_user_email' ).on( 'keyup', function( event ) {
603 // For textareas, make Enter add the user; for inputs, make enter add the user.
604 if ( $( this ).is( 'textarea' ) ) {
605 // Enter key adds a newline; Enter key with Ctrl, Alt, Shift, or Meta adds the user.
606 if ( event.which === 13 && ( event.ctrlKey || event.altKey || event.metaKey ) ) {
607 $( this ).parent().find( 'a.button-add-user' ).trigger( 'click' );
608 event.preventDefault();
609 }
610 } else if ( event.which === 13 ) { // Enter key on input[type="text"]
611 $( this ).parent().find( 'a.button-add-user' ).trigger( 'click' );
612 event.preventDefault();
613 }
614 });
615
616 // Don't submit form (i.e., save options) when hitting enter in any user list field.
617 $( 'input.auth-email, select.auth-role, input.auth-date-added, input.auth-usermeta' ).on( 'keydown', function( event ) {
618 if ( event.which === 13 ) { // Enter key
619 event.preventDefault();
620 return false;
621 }
622 });
623
624 // Enable the user-friendly multiselect form element on the options page.
625 $( '#auth_settings_access_public_pages' ).multiSelect({
626 selectableOptgroup: true,
627 selectableHeader: '<div class="custom-header">' + authL10n.private_pages + '</div>',
628 selectionHeader: '<div class="custom-header">' + authL10n.public_pages + '</div>',
629 });
630
631 // Switch to the first tab (or the tab indicated in sessionStorage, or the querystring).
632 var tab = '';
633 if ( getQuerystringValuesByKey( 'tab' ).length > 0 ) {
634 tab = getQuerystringValuesByKey( 'tab' )[0];
635 } else if ( sessionStorage.getItem( 'tab' ) ) {
636 tab = sessionStorage.getItem( 'tab' );
637 }
638 if ( $.inArray( tab, [ 'access_lists', 'access_login', 'access_public', 'external', 'advanced' ] ) < 0 ) {
639 tab = 'access_lists';
640 }
641 window.chooseTab( tab, animationSpeed );
642
643 // Hide/show multisite settings based on override checkbox.
644 $( 'input[name="auth_settings[multisite_override]"]' ).change( function() {
645 hideMultisiteSettingsIfDisabled();
646 });
647 hideMultisiteSettingsIfDisabled();
648
649 // Wire up pager events on Approved User list (first/last/next/previous
650 // buttons, go to page text input, and search.
651 $( '#current-page-selector, #user-search-input' ).on( 'keydown', function( event ) {
652 if ( event.which === 13 ) { // Enter key
653 var searchTerm = $( '#user-search-input' ).val();
654 var currentPage = parseInt( $( this ).val(), 10 ) || 1;
655 var totalPages = parseInt( $( '.total-pages' ).first().text().replace( /[^0-9]/g, '' ), 10 ) || 1;
656
657 // Make sure current page is between 1 and max pages.
658 if ( currentPage < 1 ) {
659 currentPage = 1;
660 } else if ( currentPage > totalPages ) {
661 currentPage = totalPages;
662 }
663
664 // Update user list with users on next page.
665 refreshApprovedUserList( currentPage, searchTerm );
666
667 // Prevent default behavior.
668 event.preventDefault();
669 return false;
670 }
671 });
672
673 $( '.tablenav' ).on( 'click', '.pagination-links a, #search-submit', function( event ) {
674 var searchTerm = $( '#user-search-input' ).val();
675 var currentPage = parseInt( getParameterByName( 'paged', $( this ).attr( 'href' ) ), 10 ) || 1;
676 var totalPages = parseInt( $( '.total-pages' ).first().text().replace( /[^0-9]/g, '' ), 10 ) || 1;
677 if ( currentPage > totalPages ) {
678 currentPage = totalPages;
679 }
680
681 // Update user list with users on next page.
682 refreshApprovedUserList( currentPage, searchTerm );
683
684 // Remove focus from clicked element.
685 $( this ).blur();
686
687 // Prevent default behavior.
688 event.preventDefault();
689 return false;
690 });
691
692 // Enable growable textarea for new user field.
693 $( 'textarea#new_approved_user_email' ).autogrow();
694
695 // Enable growable textarea for config fields.
696 $( 'textarea#auth_settings_ldap_search_base' ).autogrow();
697 $( 'textarea#auth_settings_google_hosteddomain' ).autogrow();
698
699 });
700
701
702 /**
703 * Globals.
704 */
705
706
707 // Switch between option tabs.
708 window.chooseTab = function( listName, delay ) {
709 // default delay is 0
710 delay = 'undefined' !== typeof delay ? delay : 0;
711
712 // default to the access list tab
713 listName = 'undefined' !== typeof listName ? listName : 'access_lists';
714
715 // Hide all tab content, then show selected tab content
716 $( 'div.section_info, div.section_info + table' ).hide();
717 $( '#section_info_' + listName + ', #section_info_' + listName + ' + table' ).show();
718
719 // Set active tab
720 $( '.nav-tab-wrapper a' ).removeClass( 'nav-tab-active' );
721 $( 'a.nav-tab-' + listName ).addClass( 'nav-tab-active' );
722
723 // Hide site options if they are overridden by a multisite setting.
724 setTimeout( window.hideMultisiteOverriddenOptions, delay );
725
726 // Hide Save Changes button if we're on the access lists page (changing
727 // access lists saves automatically via AJAX).
728 $( 'body:not(.network-admin) #submit' ).toggle( 'access_lists' !== listName );
729
730 // Save user's active tab to sessionStorage (so we can restore it on reload).
731 // Note: session storage persists until the browser tab is closed.
732 sessionStorage.setItem( 'tab', listName );
733 };
734
735 // Hide (with overlay) site options if overridden by a multisite option.
736 window.hideMultisiteOverriddenOptions = function() {
737 $( '.auth_multisite_override_overlay' ).each( function() {
738 // Option to hide is stored in the overlay's id with 'overlay-hide-' prefix.
739 var optionContainerToHide = $( this ).closest( 'tr' );
740 if ( optionContainerToHide.length > 0 ) {
741 $( this ).css({
742 'background-color': '#f1f1f1',
743 'z-index': 1,
744 opacity: 0.8,
745 position: 'absolute',
746 top: optionContainerToHide.position().top,
747 left: optionContainerToHide.position().left,
748 width: '100%',
749 height: optionContainerToHide.height(),
750 });
751 $( this ).show();
752 }
753 });
754 };
755
756 // Update user's usermeta field.
757 // @calls php wp_ajax_update_auth_usermeta.
758 window.authUpdateUsermeta = function( caller ) {
759 var $caller = $( caller ),
760 $usermeta = $caller.parent().children( '.auth-usermeta' ),
761 email = $caller.siblings( '.auth-email' ).val(),
762 usermeta = $usermeta.val(),
763 nonce = $( '#nonce_save_auth_settings' ).val();
764
765 // Remove reference to caller if it's the usermeta field itself (not a button triggering the save).
766 if ( $caller.hasClass( 'auth-usermeta' ) ) {
767 $caller = $();
768 }
769
770 // Disable inputs, show spinner.
771 $caller.attr( 'disabled', 'disabled' );
772 $usermeta.attr( 'disabled', 'disabled' );
773 var $row = $usermeta.closest( 'li' );
774 var $spinner = $( '<span class="spinner is-active"></span>' ).css({
775 position: 'absolute',
776 top: $row.position().top,
777 left: $row.position().left + $row.width(),
778 });
779 $usermeta.after( $spinner );
780 $( 'html' ).addClass( 'busy' );
781
782 // Call ajax save function.
783 $.post( ajaxurl, {
784 action: 'update_auth_usermeta',
785 email: email,
786 usermeta: usermeta,
787 nonce: nonce,
788 }, function( response ) {
789 var succeeded = response === 'success';
790 var spinnerText = succeeded ? authL10n.saved + '.' : '<span style="color: red;">' + authL10n.failed + '.</span>';
791 var spinnerWait = succeeded ? 500 : 2000;
792
793 // Enable inputs, remove spinner.
794 $caller.removeAttr( 'disabled' );
795 $usermeta.removeAttr( 'disabled' );
796 $caller.css( 'display', 'none' );
797 $( 'form .spinner:not(:has(.spinner-text))' ).animate( { width: '60px' }, 'fast' ).append( '<span class="spinner-text">' + spinnerText + '</span>' ).delay( spinnerWait ).hide( animationSpeed, function() {
798 $( this ).remove();
799 });
800 $( 'html' ).removeClass( 'busy' );
801
802 }).fail( function() {
803 var succeeded = false;
804 var spinnerText = succeeded ? authL10n.saved + '.' : '<span style="color: red;">' + authL10n.failed + '.</span>';
805 var spinnerWait = succeeded ? 500 : 2000;
806
807 // Enable inputs, remove spinner.
808 $caller.removeAttr( 'disabled' );
809 $usermeta.removeAttr( 'disabled' );
810 $caller.css( 'display', 'none' );
811 $( 'form .spinner:not(:has(.spinner-text))' ).animate( { width: '60px' }, 'fast' ).append( '<span class="spinner-text">' + spinnerText + '</span>' ).delay( spinnerWait ).hide( animationSpeed, function() {
812 $( this ).remove();
813 });
814 $( 'html' ).removeClass( 'busy' );
815
816 });
817 };
818
819 // Update user's role.
820 window.authChangeRole = function( caller, isMultisite ) {
821 // Set default for multisite flag (run different save routine if multisite)
822 isMultisite = typeof isMultisite !== 'undefined' ? isMultisite : false;
823
824 var email = $( caller ).parent().find( '.auth-email' );
825 var role = $( caller ).parent().find( '.auth-role' );
826 var dateAdded = $( caller ).parent().find( '.auth-date-added' );
827
828 var user = {
829 email: email.val(),
830 role: role.val(),
831 date_added: dateAdded.val(), // eslint-disable-line camelcase
832 edit_action: 'change_role', // eslint-disable-line camelcase
833 multisite_user: isMultisite, // eslint-disable-line camelcase
834 };
835
836 // Update the options in the database with this change.
837 updateAuthUser( caller, 'access_users_approved', user );
838
839 return true;
840 };
841
842 // Update user's role (multisite options page).
843 window.authMultisiteChangeRole = function( caller ) {
844 var isMultisite = true;
845 window.authChangeRole( caller, isMultisite );
846 };
847
848 // Add user to list (list = blocked or approved).
849 window.authAddUser = function( caller, list, shouldCreateLocalAccount, isMultisite ) {
850 // Skip email address validation if adding from pending list (not user-editable).
851 var skipValidation = $( caller ).parent().parent().attr( 'id' ) === 'list_auth_settings_access_users_pending';
852
853 // Skip email address validation if we're banning an existing user (since they're already in a list).
854 var blockingNewUser = $( caller ).attr( 'id' ).indexOf( 'block_user_new' ) > -1;
855 skipValidation = skipValidation || ( $( caller ).attr( 'id' ).indexOf( 'block_user' ) > -1 && ! blockingNewUser );
856
857 // Set default for multisite flag (run different save routine if multisite)
858 isMultisite = 'undefined' !== typeof isMultisite ? isMultisite : false;
859
860 // Default to the approved list.
861 list = 'undefined' !== typeof list ? list : 'approved';
862
863 // Default to not creating a local account.
864 shouldCreateLocalAccount = 'undefined' !== typeof shouldCreateLocalAccount ? shouldCreateLocalAccount : false;
865
866 var email = $( caller ).parent().find( '.auth-email' );
867 var role = $( caller ).parent().find( '.auth-role' );
868 var dateAdded = $( caller ).parent().find( '.auth-date-added' );
869
870 // Helper variable for disabling buttons while processing. This will be
871 // set differently if our clicked button is nested in a div (below).
872 var buttons = caller;
873
874 // Button (caller) might be nested in a div, so we need to walk up one more level
875 if ( 0 === email.length || 0 === role.length ) {
876 email = $( caller ).parent().parent().find( '.auth-email' );
877 role = $( caller ).parent().parent().find( '.auth-role' );
878 dateAdded = $( caller ).parent().parent().find( '.auth-date-added' );
879 buttons = $( caller ).parent().children();
880 }
881
882 // Support a single email address, or multiple (separated by newlines, commas, semicolons, or spaces).
883 var emails = $.trim( email.val() ).replace( /mailto:/g, '' ).split( /[\s,;]+/ );
884
885 // Remove any invalid email addresses.
886 if ( ! skipValidation ) {
887 // Check if the email(s) being added is well-formed.
888 emails = emails.filter( function( emailToValidate ) {
889 return validEmail( emailToValidate, blockingNewUser );
890 });
891 // Remove any duplicates in the list of emails to add.
892 emails = removeDuplicatesFromArrayOfStrings( emails );
893 }
894
895 // Shake and quit if no valid email addresses exist.
896 if ( 1 > emails.length ) {
897 $( '#new_' + list + '_user_email' ).parent().effect( 'shake', shakeSpeed );
898 return false;
899 }
900
901 $( buttons ).attr( 'disabled', 'disabled' );
902
903 var users = [];
904 for ( var i = 0; i < emails.length; i++ ) {
905 var user = {
906 email: emails[i],
907 role: role.val(),
908 date_added: dateAdded.val(), // eslint-disable-line camelcase
909 edit_action: 'add', // eslint-disable-line camelcase
910 local_user: shouldCreateLocalAccount, // eslint-disable-line camelcase
911 multisite_user: isMultisite, // eslint-disable-line camelcase
912 };
913 users.push( user );
914
915 // Get next highest user ID.
916 var nextId = 1 + Math.max.apply(
917 null,
918 // eslint-disable-next-line no-unused-vars
919 $( '#list_auth_settings_access_users_' + list + ' li .auth-email' ).map( function( el ) { // jshint ignore:line
920 return parseInt( this.id.replace( 'auth_multisite_settings_access_users_' + list + '_', '' ).replace( 'auth_settings_access_users_' + list + '_', '' ), 10 );
921 })
922 );
923
924 // Add the new item.
925 var authJsPrefix = isMultisite ? 'authMultisite' : 'auth';
926 var localIcon = shouldCreateLocalAccount ? '&nbsp;<a title="' + authL10n.local_wordpress_user + '" class="auth-local-user"><span class="glyphicon glyphicon-user"></span></a>' : '';
927 var banButton = list === 'approved' && ! isMultisite ? '<a class="button" id="block_user_' + nextId + '" onclick="' + authJsPrefix + 'AddUser( this, \'blocked\', false ); ' + authJsPrefix + 'IgnoreUser( this, \'approved\' );" title="' + authL10n.block_ban_user + '"><span class="glyphicon glyphicon-ban-circle"></span></a>' : '';
928 $( ' \
929 <li id="new_user_' + nextId + '" class="new-user" style="display: none;"> \
930 <input type="text" id="auth_settings_access_users_' + list + '_' + nextId + '" name="auth_settings[access_users_' + list + '][' + nextId + '][email]" value="' + user.email + '" readonly="true" class="auth-email" /> \
931 <select name="auth_settings[access_users_' + list + '][' + nextId + '][role]" class="auth-role" onchange="' + authJsPrefix + 'ChangeRole( this );"> \
932 </select> \
933 <input type="text" name="auth_settings[access_users_' + list + '][' + nextId + '][date_added]" value="' + getShortDate() + '" readonly="true" class="auth-date-added" /> \
934 ' + banButton + ' \
935 <a class="button" id="ignore_user_' + nextId + '" onclick="' + authJsPrefix + 'IgnoreUser( this, \'' + list + '\' );" title="' + authL10n.remove_user + '"><span class="glyphicon glyphicon-remove"></span></a> \
936 ' + localIcon + ' \
937 <span class="spinner is-active"></span> \
938 </li> \
939 ' ).appendTo( '#list_auth_settings_access_users_' + list ).slideDown( 250 );
940
941 // Populate the role dropdown in the new element. Because clone() doesn't
942 // save selected state on select elements, set that too.
943 $( 'option', role ).clone().appendTo( '#new_user_' + nextId + ' .auth-role' );
944 $( '#new_user_' + nextId + ' .auth-role' ).val( role.val() );
945 }
946
947 // Remove the 'empty list' item if it exists.
948 $( '#list_auth_settings_access_users_' + list + ' li.auth-empty' ).remove();
949
950 // Update the options in the database with this change.
951 updateAuthUser( buttons, 'access_users_' + list, users );
952
953 // Reset the new user textboxes
954 if ( email.hasClass( 'new' ) ) {
955 email.val( '' ).keydown();
956 }
957
958 // Re-enable the action buttons now that we're done saving.
959 $( buttons ).removeAttr( 'disabled' );
960 return true;
961 };
962
963 // Add user to list (multisite options page).
964 window.authMultisiteAddUser = function( caller, list, shouldCreateLocalAccount ) {
965 var isMultisite = true;
966
967 // Default to the approved list.
968 list = typeof list !== 'undefined' ? list : 'approved';
969
970 // Default to not creating a local account.
971 shouldCreateLocalAccount = typeof shouldCreateLocalAccount !== 'undefined' ? shouldCreateLocalAccount : false;
972
973 // There currently is no multisite blocked list, so do nothing.
974 if ( list === 'blocked' ) {
975 return;
976 }
977
978 window.authAddUser( caller, list, shouldCreateLocalAccount, isMultisite );
979 };
980
981 // Remove user from list.
982 window.authIgnoreUser = function( caller, listName, isMultisite ) {
983 // Set default for multisite flag (run different save routine if multisite)
984 isMultisite = typeof isMultisite !== 'undefined' ? isMultisite : false;
985
986 // Set default list if not provided.
987 listName = typeof listName !== 'undefined' ? listName : 'approved';
988
989 var email = $( caller ).parent().find( '.auth-email' );
990
991 var user = {
992 email: email.val(),
993 role: '',
994 date_added: '', // eslint-disable-line camelcase
995 edit_action: 'remove', // eslint-disable-line camelcase
996 multisite_user: isMultisite, // eslint-disable-line camelcase
997 };
998
999 // Show an 'empty list' message if we're deleting the last item
1000 var list = $( caller ).closest( 'ul' );
1001 if ( $( 'li', list ).length <= 1 ) {
1002 $( list ).append( '<li class="auth-empty"><em>' + authL10n.no_users_in + ' ' + listName + '</em></li>' );
1003 }
1004
1005 $( caller ).parent().slideUp( 250, function() {
1006 // Remove the list item.
1007 $( this ).remove();
1008
1009 // Update the options in the database with this change.
1010 updateAuthUser( caller, 'access_users_' + listName, user );
1011 });
1012 };
1013
1014 // Remove user from list (multisite options page).
1015 window.authMultisiteIgnoreUser = function( caller, listName ) {
1016 var isMultisite = true;
1017
1018 // Set default list if not provided.
1019 listName = typeof listName !== 'undefined' ? listName : '';
1020
1021 window.authIgnoreUser( caller, listName, isMultisite );
1022 };
1023
1024 // Save Authorizer Settings (multisite).
1025 // @calls php wp_ajax_save_auth_multisite_settings.
1026 /* eslint-disable camelcase */
1027 window.saveAuthMultisiteSettings = function( caller ) {
1028 // Enable wait cursor.
1029 $( 'html' ).addClass( 'busy' );
1030
1031 // Disable button (prevent duplicate clicks).
1032 $( caller ).attr( 'disabled', 'disabled' );
1033
1034 // Enable spinner by element that triggered this event (caller).
1035 var $spinner = $( '<span class="spinner is-active"></span>' ).css({
1036 position: 'absolute',
1037 top: $( caller ).position().top,
1038 left: $( caller ).position().left + $( caller ).width() + 20,
1039 });
1040 $( caller ).after( $spinner );
1041
1042 // Get form elements to save
1043 var nonce_save_auth_settings = $( '#nonce_save_auth_settings' ).val();
1044
1045 var multisite_override = $( '#auth_settings_multisite_override' ).is( ':checked' ) ? '1' : '';
1046
1047 var access_who_can_login = $( 'form input[name="auth_settings[access_who_can_login]"]:checked' ).val();
1048
1049 var access_who_can_view = $( 'form input[name="auth_settings[access_who_can_view]"]:checked' ).val();
1050
1051 var access_users_approved = {};
1052 $( '#list_auth_settings_access_users_approved li' ).each( function( index ) {
1053 var user = {};
1054 user.email = $( '.auth-email', this ).val();
1055 user.role = $( '.auth-role', this ).val();
1056 user.date_added = $( '.auth-date-added', this ).val();
1057 user.local_user = $( '.auth-local-user', this ).length !== 0;
1058 access_users_approved[index] = user;
1059 });
1060
1061 var access_default_role = $( '#auth_settings_access_default_role' ).val();
1062
1063 var google = $( '#auth_settings_google' ).is( ':checked' ) ? '1' : '';
1064 var google_clientid = $( '#auth_settings_google_clientid' ).val();
1065 var google_clientsecret = $( '#auth_settings_google_clientsecret' ).val();
1066 var google_hosteddomain = $( '#auth_settings_google_hosteddomain' ).val();
1067
1068 var cas = $( '#auth_settings_cas' ).is( ':checked' ) ? '1' : '';
1069 var cas_custom_label = $( '#auth_settings_cas_custom_label' ).val();
1070 var cas_host = $( '#auth_settings_cas_host' ).val();
1071 var cas_port = $( '#auth_settings_cas_port' ).val();
1072 var cas_path = $( '#auth_settings_cas_path' ).val();
1073 var cas_version = $( '#auth_settings_cas_version' ).val();
1074 var cas_attr_email = $( '#auth_settings_cas_attr_email' ).val();
1075 var cas_attr_first_name = $( '#auth_settings_cas_attr_first_name' ).val();
1076 var cas_attr_last_name = $( '#auth_settings_cas_attr_last_name' ).val();
1077 var cas_attr_update_on_login = $( '#auth_settings_cas_attr_update_on_login' ).is( ':checked' ) ? '1' : '';
1078 var cas_auto_login = $( '#auth_settings_cas_auto_login' ).is( ':checked' ) ? '1' : '';
1079 var cas_link_on_username = $( '#auth_settings_cas_link_on_username' ).is( ':checked' ) ? '1' : '';
1080
1081 var ldap = $( '#auth_settings_ldap' ).is( ':checked' ) ? '1' : '';
1082 var ldap_host = $( '#auth_settings_ldap_host' ).val();
1083 var ldap_port = $( '#auth_settings_ldap_port' ).val();
1084 var ldap_search_base = $( '#auth_settings_ldap_search_base' ).val();
1085 var ldap_uid = $( '#auth_settings_ldap_uid' ).val();
1086 var ldap_attr_email = $( '#auth_settings_ldap_attr_email' ).val();
1087 var ldap_user = $( '#auth_settings_ldap_user' ).val();
1088 var ldap_password = $( '#auth_settings_ldap_password' ).val();
1089 var ldap_tls = $( '#auth_settings_ldap_tls' ).is( ':checked' ) ? '1' : '';
1090 var ldap_lostpassword_url = $( '#auth_settings_ldap_lostpassword_url' ).val();
1091 var ldap_attr_first_name = $( '#auth_settings_ldap_attr_first_name' ).val();
1092 var ldap_attr_last_name = $( '#auth_settings_ldap_attr_last_name' ).val();
1093 var ldap_attr_update_on_login = $( '#auth_settings_ldap_attr_update_on_login' ).is( ':checked' ) ? '1' : '';
1094
1095 var advanced_lockouts = {
1096 attempts_1: $( '#auth_settings_advanced_lockouts_attempts_1' ).val(),
1097 duration_1: $( '#auth_settings_advanced_lockouts_duration_1' ).val(),
1098 attempts_2: $( '#auth_settings_advanced_lockouts_attempts_2' ).val(),
1099 duration_2: $( '#auth_settings_advanced_lockouts_duration_2' ).val(),
1100 reset_duration: $( '#auth_settings_advanced_lockouts_reset_duration' ).val(),
1101 };
1102 var advanced_hide_wp_login = $( '#auth_settings_advanced_hide_wp_login' ).is( ':checked' ) ? '1' : '';
1103 var advanced_widget_enabled = $( '#auth_settings_advanced_widget_enabled' ).is( ':checked' ) ? '1' : '';
1104 var advanced_users_per_page = $( '#auth_settings_advanced_users_per_page' ).val();
1105 var advanced_users_sort_by = $( '#auth_settings_advanced_users_sort_by' ).val();
1106 var advanced_users_sort_order = $( '#auth_settings_advanced_users_sort_order' ).val();
1107
1108 $.post( ajaxurl, {
1109 action: 'save_auth_multisite_settings',
1110 nonce: nonce_save_auth_settings,
1111 multisite_override: multisite_override,
1112 access_who_can_login: access_who_can_login,
1113 access_who_can_view: access_who_can_view,
1114 access_users_approved: access_users_approved,
1115 access_default_role: access_default_role,
1116 google: google,
1117 google_clientid: google_clientid,
1118 google_clientsecret: google_clientsecret,
1119 google_hosteddomain: google_hosteddomain,
1120 cas: cas,
1121 cas_custom_label: cas_custom_label,
1122 cas_host: cas_host,
1123 cas_port: cas_port,
1124 cas_path: cas_path,
1125 cas_version: cas_version,
1126 cas_attr_email: cas_attr_email,
1127 cas_attr_first_name: cas_attr_first_name,
1128 cas_attr_last_name: cas_attr_last_name,
1129 cas_attr_update_on_login: cas_attr_update_on_login,
1130 cas_auto_login: cas_auto_login,
1131 cas_link_on_username: cas_link_on_username,
1132 ldap: ldap,
1133 ldap_host: ldap_host,
1134 ldap_port: ldap_port,
1135 ldap_search_base: ldap_search_base,
1136 ldap_uid: ldap_uid,
1137 ldap_attr_email: ldap_attr_email,
1138 ldap_user: ldap_user,
1139 ldap_password: ldap_password,
1140 ldap_tls: ldap_tls,
1141 ldap_lostpassword_url: ldap_lostpassword_url,
1142 ldap_attr_first_name: ldap_attr_first_name,
1143 ldap_attr_last_name: ldap_attr_last_name,
1144 ldap_attr_update_on_login: ldap_attr_update_on_login,
1145 advanced_lockouts: advanced_lockouts,
1146 advanced_hide_wp_login: advanced_hide_wp_login,
1147 advanced_users_per_page: advanced_users_per_page,
1148 advanced_users_sort_by: advanced_users_sort_by,
1149 advanced_users_sort_order: advanced_users_sort_order,
1150 advanced_widget_enabled: advanced_widget_enabled,
1151 }, function( response ) {
1152 var succeeded = response === 'success';
1153 var spinnerText = succeeded ? authL10n.saved + '.' : '<span style="color: red;">' + authL10n.failed + '.</span>';
1154 var spinnerWait = succeeded ? 500 : 2000;
1155 $( 'form .spinner:not(:has(.spinner-text))' ).append( '<span class="spinner-text">' + spinnerText + '</span>' ).delay( spinnerWait ).hide( animationSpeed, function() {
1156 $( this ).remove();
1157 });
1158 $( caller ).removeAttr( 'disabled' );
1159
1160 // Disable wait cursor.
1161 $( 'html' ).removeClass( 'busy' );
1162 }).fail( function() {
1163 // Fail fires if the server doesn't respond
1164 var succeeded = false;
1165 var spinnerText = succeeded ? authL10n.saved + '.' : '<span style="color: red;">' + authL10n.failed + '.</span>';
1166 var spinnerWait = succeeded ? 500 : 2000;
1167 $( 'form .spinner:not(:has(.spinner-text))' ).append( '<span class="spinner-text">' + spinnerText + '</span>' ).delay( spinnerWait ).hide( animationSpeed, function() {
1168 $( this ).remove();
1169 });
1170 $( caller ).removeAttr( 'disabled' );
1171
1172 // Disable wait cursor.
1173 $( 'html' ).removeClass( 'busy' );
1174 });
1175 };
1176 /* eslint-enable camelcase */
1177
1178 /* ========================================================================
1179 * Portions below from Bootstrap.
1180 * ========================================================================
1181 * Bootstrap: dropdown.js v3.1.1
1182 * http://getbootstrap.com/javascript/#dropdowns
1183 * ========================================================================
1184 * Copyright 2011-2014 Twitter, Inc.
1185 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1186 * ======================================================================== */
1187
1188 // DROPDOWN CLASS DEFINITION
1189 // =========================
1190 var backdrop = '.dropdown-backdrop';
1191 var toggle = '[data-toggle=dropdown]';
1192 var Dropdown = function( element ) { // eslint-disable-line func-style
1193 $( element ).on( 'click.bs.dropdown', this.toggle );
1194 };
1195
1196 Dropdown.prototype.toggle = function( event ) {
1197 var $this = $( this );
1198
1199 if ( $this.is( '.disabled, :disabled' ) ) {
1200 return;
1201 }
1202
1203 var $parent = getParent( $this );
1204 var isActive = $parent.hasClass( 'open' );
1205
1206 clearMenus();
1207
1208 if ( ! isActive ) {
1209 if ( 'ontouchstart' in document.documentElement && ! $parent.closest( '.navbar-nav' ).length ) {
1210 // if mobile we use a backdrop because click events don't delegate
1211 $( '<div class="dropdown-backdrop"/>' ).insertAfter( $( this ) ).on( 'click', clearMenus );
1212 }
1213
1214 var relatedTarget = { relatedTarget: this };
1215 $parent.trigger( event = $.Event( 'show.bs.dropdown', relatedTarget ) );
1216
1217 if ( event.isDefaultPrevented() ) {
1218 return;
1219 }
1220
1221 $parent
1222 .toggleClass( 'open' )
1223 .trigger( 'shown.bs.dropdown', relatedTarget);
1224
1225 $this.focus();
1226 }
1227
1228 return false;
1229 };
1230
1231 Dropdown.prototype.keydown = function( event ) {
1232 if ( ! /(38|40|27)/.test( event.keyCode ) ) {
1233 return;
1234 }
1235
1236 var $this = $( this );
1237
1238 event.preventDefault();
1239 event.stopPropagation();
1240
1241 if ( $this.is( '.disabled, :disabled' ) ) {
1242 return;
1243 }
1244
1245 var $parent = getParent( $this );
1246 var isActive = $parent.hasClass( 'open' );
1247
1248 if ( ! isActive || ( isActive && event.keyCode === 27 ) ) {
1249 if ( event.which === 27 ) {
1250 $parent.find( toggle ).focus();
1251 }
1252 return $this.click();
1253 }
1254
1255 var desc = ' li:not(.divider):visible a';
1256 var $items = $parent.find( '[role=menu]' + desc + ', [role=listbox]' + desc);
1257
1258 if ( ! $items.length ) {
1259 return;
1260 }
1261
1262 var index = $items.index($items.filter( ':focus' ));
1263
1264 if ( event.keyCode === 38 && index > 0 ) {
1265 index--; // up
1266 }
1267 if ( event.keyCode === 40 && index < $items.length - 1 ) {
1268 index++; // down
1269 }
1270 if ( ! ~index ) {
1271 index = 0;
1272 }
1273
1274 $items.eq(index).focus();
1275 };
1276
1277 function clearMenus( event ) {
1278 $(backdrop).remove();
1279 $(toggle).each( function() {
1280 var $parent = getParent($( this ));
1281 var relatedTarget = { relatedTarget: this };
1282 if ( ! $parent.hasClass( 'open' ) ) {
1283 return;
1284 }
1285 $parent.trigger( event = $.Event( 'hide.bs.dropdown', relatedTarget ) );
1286 if ( event.isDefaultPrevented() ) {
1287 return;
1288 }
1289 $parent.removeClass( 'open' ).trigger( 'hidden.bs.dropdown', relatedTarget);
1290 });
1291 }
1292
1293 function getParent( $this ) {
1294 var selector = $this.attr( 'data-target' );
1295
1296 if ( ! selector ) {
1297 selector = $this.attr( 'href' );
1298 selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '' ); // strip for ie7
1299 }
1300
1301 var $parent = selector && $(selector);
1302
1303 return $parent && $parent.length ? $parent : $this.parent();
1304 }
1305
1306 // DROPDOWN PLUGIN DEFINITION
1307 // ==========================
1308 var old = $.fn.dropdown;
1309 $.fn.dropdown = function( option ) {
1310 return this.each( function() {
1311 var $this = $( this );
1312 var data = $this.data( 'bs.dropdown' );
1313
1314 if ( ! data ) {
1315 $this.data( 'bs.dropdown', ( data = new Dropdown( this ) ) );
1316 }
1317 if ( 'string' === typeof option ) {
1318 data[option].call( $this );
1319 }
1320 });
1321 };
1322 $.fn.dropdown.Constructor = Dropdown;
1323
1324 // DROPDOWN NO CONFLICT
1325 // ====================
1326 $.fn.dropdown.noConflict = function() {
1327 $.fn.dropdown = old;
1328 return this;
1329 };
1330
1331 // APPLY TO STANDARD DROPDOWN ELEMENTS
1332 // ===================================
1333 $(document)
1334 .on( 'click.bs.dropdown.data-api', clearMenus)
1335 .on( 'click.bs.dropdown.data-api', '.dropdown form', function( event ) { event.stopPropagation(); })
1336 .on( 'click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
1337 .on( 'keydown.bs.dropdown.data-api', toggle + ', [role=menu], [role=listbox]', Dropdown.prototype.keydown);
1338
1339 } )( jQuery );
1340