PluginProbe
Authorizer / 2.3.4
Authorizer v2.3.4
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.3.4, at js/authorizer.js

1,066 lines 45.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 var animation_speed = 300;
2 var shake_speed = 600;
3
4
5
6 // Switch between option tabs.
7 function choose_tab( list_name, delay ) {
8 var $ = jQuery;
9
10 // default delay is 0
11 delay = typeof delay !== 'undefined' ? delay : 0;
12
13 // default to the access list tab
14 list_name = typeof list_name !== 'undefined' ? list_name : 'access_list';
15
16 // Hide all tab content, then show selected tab content
17 $( 'div.section_info, div.section_info + table' ).hide();
18 $( '#section_info_' + list_name + ', #section_info_' + list_name + ' + table' ).show();
19
20 // Set active tab
21 $( '.nav-tab-wrapper a' ).removeClass( 'nav-tab-active' );
22 $( 'a.nav-tab-' + list_name ).addClass( 'nav-tab-active' );
23
24 // Hide site options if they are overridden by a multisite setting.
25 setTimeout( hide_multisite_overridden_options, delay );
26
27 // Hide Save Changes button if we're on the access lists page (changing
28 // access lists saves automatically via AJAX).
29 $( 'body:not(.network-admin) #submit' ).toggle( list_name !== 'access_lists' );
30
31 // Save user's active tab to sessionStorage (so we can restore it on reload).
32 // Note: session storage persists until the browser tab is closed.
33 sessionStorage.setItem( 'tab', list_name );
34 }
35
36 // Update user's usermeta field.
37 function auth_update_usermeta( caller ) {
38 var $ = jQuery,
39 $caller = $( caller ),
40 $usermeta = $caller.parent().children( '.auth-usermeta' ),
41 email = $caller.siblings( '.auth-email' ).val(),
42 usermeta = $usermeta.val(),
43 nonce_save_auth_settings = $( '#nonce_save_auth_settings' ).val();
44
45 // Remove reference to caller if it's the usermeta field itself (not a button triggering the save).
46 if ( $caller.hasClass( 'auth-usermeta' ) ) {
47 $caller = $();
48 }
49
50 // Disable inputs, show spinner.
51 $caller.attr( 'disabled', 'disabled' );
52 $usermeta.attr( 'disabled', 'disabled' );
53 $usermeta.after( '<span class="spinner is-active"></span>' );
54 $( 'html' ).addClass( 'busy' );
55
56 // Call ajax save function.
57 $.post( ajaxurl, {
58 'action': 'update_auth_usermeta',
59 'email': email,
60 'usermeta': usermeta,
61 'nonce_save_auth_settings': nonce_save_auth_settings,
62 }, function ( response ) {
63 var succeeded = response === 'success';
64 var spinner_text = succeeded ? 'Saved.' : '<span style="color: red;">Failed.</span>';
65 var spinner_wait = succeeded ? 500 : 2000;
66
67 // Enable inputs, remove spinner.
68 $caller.removeAttr( 'disabled' );
69 $usermeta.removeAttr( 'disabled' );
70 $caller.css( 'display', 'none' );
71 $( 'form .spinner:not(:has(.spinner-text))' ).animate( { width: '60px' }, 'fast' ).append( '<span class="spinner-text">' + spinner_text + '</span>' ).delay( spinner_wait ).hide( animation_speed, function() {
72 $( this ).remove();
73 });
74 $( 'html' ).removeClass( 'busy' );
75
76 }).fail( function ( response ) {
77 var succeeded = false;
78 var spinner_text = succeeded ? 'Saved.' : '<span style="color: red;">Failed.</span>';
79 var spinner_wait = succeeded ? 500 : 2000;
80
81 // Enable inputs, remove spinner.
82 $caller.removeAttr( 'disabled' );
83 $usermeta.removeAttr( 'disabled' );
84 $caller.css( 'display', 'none' );
85 $( 'form .spinner:not(:has(.spinner-text))' ).animate( { width: '60px' }, 'fast' ).append( '<span class="spinner-text">' + spinner_text + '</span>' ).delay( spinner_wait ).hide( animation_speed, function() {
86 $( this ).remove();
87 });
88 $( 'html' ).removeClass( 'busy' );
89
90 });
91
92 }
93
94 // Update user's role (multisite options page).
95 function auth_multisite_change_role( caller ) {
96 var is_multisite = true;
97 auth_change_role( caller, is_multisite );
98 }
99
100 // Update user's role.
101 function auth_change_role( caller, is_multisite ) {
102 var $ = jQuery;
103
104 // Set default for multisite flag (run different save routine if multisite)
105 is_multisite = typeof is_multisite !== 'undefined' ? is_multisite : false;
106
107 var email = $( caller ).parent().find( '.auth-email' );
108 var role = $( caller ).parent().find( '.auth-role' );
109 var date_added = $( caller ).parent().find( '.auth-date-added' );
110
111 var user = {
112 'email': email.val(),
113 'role': role.val(),
114 'date_added': date_added.val(),
115 'edit_action': 'change_role',
116 'multisite_user': is_multisite,
117 };
118
119 // Update the options in the database with this change.
120 update_auth_user( caller, 'access_users_approved', user );
121
122 return true;
123 }
124
125 // Add user to list (multisite options page).
126 function auth_multisite_add_user( caller, list, create_local_account ) {
127 var is_multisite = true;
128
129 // Default to the approved list.
130 list = typeof list !== 'undefined' ? list : 'approved';
131
132 // Default to not creating a local account.
133 create_local_account = typeof create_local_account !== 'undefined' ? create_local_account : false;
134
135 // There currently is no multisite blocked list, so do nothing.
136 if ( list === 'blocked' ) {
137 return;
138 }
139
140 auth_add_user( caller, list, create_local_account, is_multisite );
141 }
142 // Add user to list (list = blocked or approved).
143 function auth_add_user( caller, list, create_local_account, is_multisite ) {
144 var $ = jQuery;
145
146 // Skip email address validation if adding from pending list (not user-editable).
147 var skip_validation = $( caller ).parent().parent().attr( 'id' ) === 'list_auth_settings_access_users_pending';
148
149 // Skip email address validation if we're banning an existing user (since they're already in a list).
150 skip_validation = skip_validation || $( caller ).attr( 'id' ).indexOf( 'block_user' ) > -1;
151
152 // Set default for multisite flag (run different save routine if multisite)
153 is_multisite = typeof is_multisite !== 'undefined' ? is_multisite : false;
154
155 // Default to the approved list.
156 list = typeof list !== 'undefined' ? list : 'approved';
157
158 // Default to not creating a local account.
159 create_local_account = typeof create_local_account !== 'undefined' ? create_local_account : false;
160
161 var email = $( caller ).parent().find( '.auth-email' );
162 var role = $( caller ).parent().find( '.auth-role' );
163 var date_added = $( caller ).parent().find( '.auth-date-added' );
164
165 // Helper variable for disabling buttons while processing. This will be
166 // set differently if our clicked button is nested in a div (below).
167 var buttons = caller;
168
169 // Button (caller) might be nested in a div, so we need to walk up one more level
170 if ( email.length === 0 || role.length === 0 ) {
171 email = $( caller ).parent().parent().find( '.auth-email' );
172 role = $( caller ).parent().parent().find( '.auth-role' );
173 date_added = $( caller ).parent().parent().find( '.auth-date-added' );
174 buttons = $( caller ).parent().children();
175 }
176
177 var user = {
178 'email': email.val(),
179 'role': role.val(),
180 'date_added': date_added.val(),
181 'edit_action': 'add',
182 'local_user': create_local_account,
183 'multisite_user': is_multisite,
184 };
185
186 var next_id = $( '#list_auth_settings_access_users_' + list + ' li' ).length;
187 var validated = true;
188
189 if ( $.trim( email.val() ) === '' ) {
190 return false;
191 }
192
193 $( buttons ).attr( 'disabled', 'disabled' );
194
195 // Check if the name being added already exists in any list.
196 if ( ! skip_validation && validated ) {
197 $( 'li > input.auth-email' ).each( function() {
198 if ( this.value == email.val() ) {
199 validated = false;
200 email.parent().effect( 'shake', shake_speed );
201 $( this ).parent().effect( 'shake', shake_speed );
202 $( buttons ).removeAttr( 'disabled' );
203 return false;
204 }
205 });
206 }
207
208 // Check if the user being added has a valid email address.
209 if ( ! skip_validation && validated ) {
210 if ( ! valid_email( email.val() ) ) {
211 validated = false;
212 $( '#new_' + list + '_user_email' ).parent().effect( 'shake', shake_speed );
213 $( buttons ).removeAttr( 'disabled' );
214 }
215 }
216
217 if ( validated ) {
218 // Add the new item.
219 var auth_js_prefix = is_multisite ? 'auth_multisite_' : 'auth_';
220 var local_icon = create_local_account ? '&nbsp;<a title="Local WordPress user" class="auth-local-user"><span class="glyphicon glyphicon-user"></span></a>' : '';
221 var ban_button = list === 'approved' && ! is_multisite ? '<a class="button" onclick="' + auth_js_prefix + 'add_user( this, \'blocked\', false ); ' + auth_js_prefix + 'ignore_user( this, \'approved\' );" title="Block/Ban user"><span class="glyphicon glyphicon-ban-circle"></span></a>' : '';
222 $( ' \
223 <li id="new_user_' + next_id + '" style="display: none;"> \
224 <input type="text" id="auth_settings_access_users_' + list + '_' + next_id + '" name="auth_settings[access_users_' + list + '][' + next_id + '][email]" value="' + email.val() + '" readonly="true" class="auth-email" /> \
225 <select name="auth_settings[access_users_' + list + '][' + next_id + '][role]" class="auth-role" onchange="' + auth_js_prefix + 'change_role( this );"> \
226 </select> \
227 <input type="text" name="auth_settings[access_users_' + list + '][' + next_id + '][date_added]" value="' + getShortDate() + '" readonly="true" class="auth-date-added" /> \
228 ' + ban_button + ' \
229 <a class="button" onclick="' + auth_js_prefix + 'ignore_user( this, \'approved\' );" title="Remove user"><span class="glyphicon glyphicon-remove"></span></a> \
230 ' + local_icon + ' \
231 <span class="spinner is-active"></span> \
232 </li> \
233 ' ).appendTo( '#list_auth_settings_access_users_' + list + '' ).slideDown( 250 );
234
235 // Populate the role dropdown in the new element. Because clone() doesn't
236 // save selected state on select elements, set that too.
237 $( 'option', role ).clone().appendTo( '#new_user_' + next_id + ' .auth-role' );
238 $( '#new_user_' + next_id + ' .auth-role' ).val( role.val() );
239
240 // Remove the 'empty list' item if it exists.
241 $( '#list_auth_settings_access_users_' + list + ' li.auth-empty' ).remove();
242
243 // Update the options in the database with this change.
244 update_auth_user( buttons, 'access_users_' + list, user );
245
246 // Reset the new user textboxes
247 if ( email.hasClass( 'new' ) ) {
248 email.val( '' );
249 }
250
251 // Re-enable the action buttons now that we're done saving.
252 $( buttons ).removeAttr( 'disabled' );
253
254 return true;
255 }
256 }
257
258 // Remove user from list (multisite options page).
259 function auth_multisite_ignore_user( caller, list_name ) {
260 var is_multisite = true;
261
262 // Set default list if not provided.
263 list_name = typeof list_name !== 'undefined' ? list_name : '';
264
265 auth_ignore_user( caller, list_name, is_multisite );
266 }
267 // Remove user from list.
268 function auth_ignore_user( caller, list_name, is_multisite ) {
269 var $ = jQuery;
270
271 // Set default for multisite flag (run different save routine if multisite)
272 is_multisite = typeof is_multisite !== 'undefined' ? is_multisite : false;
273
274 // Set default list if not provided.
275 list_name = typeof list_name !== 'undefined' ? list_name : 'approved';
276
277 var email = $( caller ).parent().find( '.auth-email' );
278
279 var user = {
280 'email': email.val(),
281 'role': '',
282 'date_added': '',
283 'edit_action': 'remove',
284 'multisite_user': is_multisite,
285 };
286
287 // Show an 'empty list' message if we're deleting the last item
288 var list = $( caller ).closest( 'ul' );
289 if ( $( 'li', list ).length <= 1 ) {
290 $( list ).append( '<li class="auth-empty"><em>No ' + list_name + ' users</em></li>' );
291 }
292
293 $( caller ).parent().slideUp( 250, function() {
294 // Remove the list item.
295 $( this ).remove();
296
297 // Update the options in the database with this change.
298 update_auth_user( caller, 'access_users_' + list_name, user );
299 });
300 }
301
302
303 // Make changes to one of the user lists (pending, approved, blocked) via ajax.
304 function update_auth_user( caller, setting, user_to_edit ) {
305 var $ = jQuery,
306 access_users_pending = [],
307 access_users_approved = [],
308 access_users_blocked = [],
309 nonce_save_auth_settings = $( '#nonce_save_auth_settings' ).val();
310
311 // Defaults:
312 // setting = 'access_users_pending' or 'access_users_approved' or 'access_users_blocked',
313 // user_to_edit = {
314 // email: 'johndoe@example.com',
315 // role: 'subscriber',
316 // date_added: 'Jun 2014',
317 // edit_action: 'add' or 'remove' or 'change_role',
318 // local_user: true or false,
319 // multisite_user: true or false,
320 // }
321 setting = typeof setting !== 'undefined' ? setting : 'none';
322 user_to_edit = typeof user_to_edit !== 'undefined' ? user_to_edit : {};
323
324 // Enable wait cursor.
325 $( 'html' ).addClass( 'busy' );
326
327 // Enable spinner by element that triggered this event (caller).
328 $( caller ).attr( 'disabled', 'disabled' );
329 if ( $( caller ).val() === 'Save Changes' ) {
330 $( caller ).last().after( '<span class="spinner is-active"></span>' );
331 } else if ( $( caller ).hasClass( 'auth-role' ) ) {
332 $( caller ).last().next().next().after( '<span class="spinner is-active"></span>' );
333 } else {
334 $( caller ).last().next().after( '<span class="spinner is-active"></span>' );
335 }
336 $( 'form .spinner' ).show();
337
338 // Grab the value of the setting we are saving.
339 if ( setting === 'access_users_pending' ) {
340 access_users_pending.push( user_to_edit );
341 } else if ( setting === 'access_users_approved' ) {
342 access_users_approved.push( user_to_edit );
343 } else if ( setting === 'access_users_blocked' ) {
344 access_users_blocked.push( user_to_edit );
345 }
346
347 $.post( ajaxurl, {
348 'action': 'update_auth_user',
349 'setting': setting,
350 'access_users_pending': access_users_pending,
351 'access_users_approved': access_users_approved,
352 'access_users_blocked': access_users_blocked,
353 'nonce_save_auth_settings': nonce_save_auth_settings,
354 }, function( response ) {
355 // Server responded, but if response isn't 'success' it failed to save.
356 var succeeded = response === 'success';
357 var spinner_text = succeeded ? 'Saved.' : '<span style="color: red;">Failed.</span>';
358 var spinner_wait = succeeded ? 500 : 2000;
359 $( 'form .spinner:not(:has(.spinner-text))' ).append( '<span class="spinner-text">' + spinner_text + '</span>' ).delay( spinner_wait ).hide( animation_speed, function() {
360 $( this ).remove();
361 });
362 $( caller ).removeAttr( 'disabled' );
363
364 // Disable wait cursor.
365 $( 'html' ).removeClass( 'busy' );
366 }).fail( function() {
367 // Fail fires if the server doesn't respond or responds with 500 codes
368 var succeeded = false;
369 var spinner_text = succeeded ? 'Saved.' : '<span style="color: red;">Failed.</span>';
370 var spinner_wait = succeeded ? 500 : 2000;
371 $( 'form .spinner:not(:has(.spinner-text))' ).append( '<span class="spinner-text">' + spinner_text + '</span>' ).delay( spinner_wait ).hide( animation_speed, function() {
372 $( this ).remove();
373 });
374 $( caller ).removeAttr( 'disabled' );
375
376 // Disable wait cursor.
377 $( 'html' ).removeClass( 'busy' );
378 });
379 }
380
381
382 // Multisite functions
383 function save_auth_multisite_settings( caller ) {
384 var $ = jQuery;
385
386 // Enable wait cursor.
387 $( 'html' ).addClass( 'busy' );
388
389 $( caller ).attr( 'disabled', 'disabled' );
390 if ( $( caller ).val() === 'Save Changes' ) {
391 $( caller ).last().after( '<span class="spinner is-active"></span>' );
392 } else if ( $( caller ).hasClass( 'auth-role' ) ) {
393 $( caller ).last().next().next().after( '<span class="spinner is-active"></span>' );
394 } else {
395 $( caller ).last().next().after( '<span class="spinner is-active"></span>' );
396 }
397 $( 'form .spinner' ).show();
398
399 // Get form elements to save
400
401 var nonce_save_auth_settings = $( '#nonce_save_auth_settings' ).val();
402
403 var multisite_override = $( '#auth_settings_multisite_override' ).is( ':checked' ) ? '1' : '';
404
405 var access_who_can_login = $( 'form input[name="auth_settings[access_who_can_login]"]:checked' ).val();
406
407 var access_who_can_view = $( 'form input[name="auth_settings[access_who_can_view]"]:checked' ).val();
408
409 var access_users_approved = {};
410 $( '#list_auth_settings_access_users_approved li' ).each( function( index ) {
411 var user = {};
412 user.email = $( '.auth-email', this ).val();
413 user.role = $( '.auth-role', this ).val();
414 user.date_added = $( '.auth-date-added', this ).val();
415 user.local_user = $( '.auth-local-user', this ).length !== 0;
416 access_users_approved[index] = user;
417 });
418
419 var access_default_role = $( '#auth_settings_access_default_role' ).val();
420
421 var google = $( '#auth_settings_google' ).is( ':checked' ) ? '1' : '';
422 var google_clientid = $( '#auth_settings_google_clientid' ).val();
423 var google_clientsecret = $( '#auth_settings_google_clientsecret' ).val();
424
425 var cas = $( '#auth_settings_cas' ).is( ':checked' ) ? '1' : '';
426 var cas_custom_label = $( '#auth_settings_cas_custom_label' ).val();
427 var cas_host = $( '#auth_settings_cas_host' ).val();
428 var cas_port = $( '#auth_settings_cas_port' ).val();
429 var cas_path = $( '#auth_settings_cas_path' ).val();
430 var cas_attr_email = $( '#auth_settings_cas_attr_email' ).val();
431 var cas_attr_first_name = $( '#auth_settings_cas_attr_first_name' ).val();
432 var cas_attr_last_name = $( '#auth_settings_cas_attr_last_name' ).val();
433 var cas_attr_update_on_login = $( '#auth_settings_cas_attr_update_on_login' ).is( ':checked' ) ? '1' : '';
434
435 var ldap = $( '#auth_settings_ldap' ).is( ':checked' ) ? '1' : '';
436 var ldap_host = $( '#auth_settings_ldap_host' ).val();
437 var ldap_port = $( '#auth_settings_ldap_port' ).val();
438 var ldap_search_base = $( '#auth_settings_ldap_search_base' ).val();
439 var ldap_uid = $( '#auth_settings_ldap_uid' ).val();
440 var ldap_attr_email = $( '#auth_settings_ldap_attr_email' ).val();
441 var ldap_user = $( '#auth_settings_ldap_user' ).val();
442 var ldap_password = $( '#auth_settings_ldap_password' ).val();
443 var ldap_tls = $( '#auth_settings_ldap_tls' ).is( ':checked' ) ? '1' : '';
444 var ldap_lostpassword_url = $( '#auth_settings_ldap_lostpassword_url' ).val();
445 var ldap_attr_first_name = $( '#auth_settings_ldap_attr_first_name' ).val();
446 var ldap_attr_last_name = $( '#auth_settings_ldap_attr_last_name' ).val();
447 var ldap_attr_update_on_login = $( '#auth_settings_ldap_attr_update_on_login' ).is( ':checked' ) ? '1' : '';
448
449 var advanced_lockouts = {
450 'attempts_1': $( '#auth_settings_advanced_lockouts_attempts_1' ).val(),
451 'duration_1': $( '#auth_settings_advanced_lockouts_duration_1' ).val(),
452 'attempts_2': $( '#auth_settings_advanced_lockouts_attempts_2' ).val(),
453 'duration_2': $( '#auth_settings_advanced_lockouts_duration_2' ).val(),
454 'reset_duration': $( '#auth_settings_advanced_lockouts_reset_duration' ).val()
455 };
456 var advanced_hide_wp_login = $( '#auth_settings_advanced_hide_wp_login' ).is( ':checked' ) ? '1' : '';
457
458 $.post( ajaxurl, {
459 action: 'save_auth_multisite_settings',
460 'nonce_save_auth_settings': nonce_save_auth_settings,
461 'multisite_override': multisite_override,
462 'access_who_can_login': access_who_can_login,
463 'access_who_can_view': access_who_can_view,
464 'access_users_approved': access_users_approved,
465 'access_default_role': access_default_role,
466 'google': google,
467 'google_clientid': google_clientid,
468 'google_clientsecret': google_clientsecret,
469 'cas': cas,
470 'cas_custom_label': cas_custom_label,
471 'cas_host': cas_host,
472 'cas_port': cas_port,
473 'cas_path': cas_path,
474 'cas_attr_email': cas_attr_email,
475 'cas_attr_first_name': cas_attr_first_name,
476 'cas_attr_last_name': cas_attr_last_name,
477 'cas_attr_update_on_login': cas_attr_update_on_login,
478 'ldap': ldap,
479 'ldap_host': ldap_host,
480 'ldap_port': ldap_port,
481 'ldap_search_base': ldap_search_base,
482 'ldap_uid': ldap_uid,
483 'ldap_attr_email': ldap_attr_email,
484 'ldap_user': ldap_user,
485 'ldap_password': ldap_password,
486 'ldap_tls': ldap_tls,
487 'ldap_lostpassword_url': ldap_lostpassword_url,
488 'ldap_attr_first_name': ldap_attr_first_name,
489 'ldap_attr_last_name': ldap_attr_last_name,
490 'ldap_attr_update_on_login': ldap_attr_update_on_login,
491 'advanced_lockouts': advanced_lockouts,
492 'advanced_hide_wp_login': advanced_hide_wp_login,
493 }, function( response ) {
494 var succeeded = response === 'success';
495 var spinner_text = succeeded ? 'Saved.' : '<span style="color: red;">Failed.</span>';
496 var spinner_wait = succeeded ? 500 : 2000;
497 $( 'form .spinner:not(:has(.spinner-text))' ).append( '<span class="spinner-text">' + spinner_text + '</span>' ).delay( spinner_wait ).hide( animation_speed, function() {
498 $( this ).remove();
499 });
500 $( caller ).removeAttr( 'disabled' );
501
502 // Disable wait cursor.
503 $( 'html' ).removeClass( 'busy' );
504 }).fail( function() {
505 // Fail fires if the server doesn't respond
506 var succeeded = false;
507 var spinner_text = succeeded ? 'Saved.' : '<span style="color: red;">Failed.</span>';
508 var spinner_wait = succeeded ? 500 : 2000;
509 $( 'form .spinner:not(:has(.spinner-text))' ).append( '<span class="spinner-text">' + spinner_text + '</span>' ).delay( spinner_wait ).hide( animation_speed, function() {
510 $( this ).remove();
511 });
512 $( caller ).removeAttr( 'disabled' );
513
514 // Disable wait cursor.
515 $( 'html' ).removeClass( 'busy' );
516 });
517 }
518
519 // Hide or show (with overlay) the multisite settings based on the "multisite override" setting.
520 function hide_multisite_settings_if_disabled() {
521 var $ = jQuery;
522
523 if ( $( '#auth_settings_multisite_override' ).length === 0 )
524 return;
525
526 var settings = $( '#auth_multisite_settings' );
527 var overlay = $( '#auth_multisite_settings_disabled_overlay' );
528
529 if ( $( '#auth_settings_multisite_override' ).is( ':checked' ) ) {
530 overlay.hide( animation_speed );
531 } else {
532 overlay.css({
533 'background-color': '#f1f1f1',
534 'z-index': 1,
535 'opacity': 0.8,
536 'position': 'absolute',
537 'top': settings.position().top,
538 'left': settings.position().left - 20,
539 'width': '100%',
540 'height': settings.height() + 35,
541 'padding-left': 20,
542 });
543 overlay.show();
544 }
545 }
546
547 // Hide (with overlay) site options if overridden by a multisite option.
548 function hide_multisite_overridden_options() {
549 var $ = jQuery;
550
551 $( '.auth_multisite_override_overlay' ).each( function() {
552 // Option to hide is stored in the overlay's id with 'overlay-hide-' prefix.
553 var option_container_to_hide = $( this ).closest( 'tr' );
554 if ( option_container_to_hide.length > 0 ) {
555 $( this ).css({
556 'background-color': '#f1f1f1',
557 'z-index': 1,
558 'opacity': 0.8,
559 'position': 'absolute',
560 'top': option_container_to_hide.position().top,
561 'left': option_container_to_hide.position().left,
562 'width': '100%',
563 'height': option_container_to_hide.height(),
564 });
565 $( this ).show();
566 }
567 });
568 }
569
570
571
572 // Helper function to hide/show wordpress option
573 function animate_option( action, option ) {
574 var $ = jQuery;
575 if ( action === 'show' ) {
576 $( 'div.animated_wrapper', option ).slideDown( animation_speed );
577 $( 'th', option ).animate({ padding: '20px 10px 20px 0' }, { duration: animation_speed });
578 $( 'td', option ).animate({ padding: '15px 10px' }, { duration: animation_speed });
579 } else if ( action === 'hide' ) {
580 $( 'div.animated_wrapper', option ).slideUp( animation_speed );
581 $( 'td, th', option ).animate({ padding: '0px' }, { duration: animation_speed });
582 } else if ( action === 'hide_immediately' ) {
583 $( 'div.animated_wrapper', option ).hide();
584 $( 'td, th', option ).css({ padding: '0px' });
585 }
586 }
587
588 // Helper function to grab a querystring param value by name
589 function getParameterByName( needle, haystack ) {
590 needle = needle.replace( /[\[]/, "\\\[").replace(/[\]]/, "\\\]" );
591 var regex = new RegExp( "[\\?&]" + needle + "=([^&#]*)" );
592 var results = regex.exec( haystack );
593 if( results === null )
594 return '';
595 else
596 return decodeURIComponent( results[1].replace( /\+/g, " " ) );
597 }
598
599 // Helper function to generate a random string
600 function getRandomId() {
601 var text = "";
602 var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
603 for ( var i=0; i < 5; i++ )
604 text += possible.charAt( Math.floor( Math.random() * possible.length ) );
605 return text;
606 }
607
608 // Helper function to return a short date (e.g., Jul 2013) for today's date
609 function getShortDate( date ) {
610 date = typeof date !== 'undefined' ? date : new Date();
611 var month = '';
612 switch ( date.getMonth() ) {
613 case 0: month = 'Jan'; break;
614 case 1: month = 'Feb'; break;
615 case 2: month = 'Mar'; break;
616 case 3: month = 'Apr'; break;
617 case 4: month = 'May'; break;
618 case 5: month = 'Jun'; break;
619 case 6: month = 'Jul'; break;
620 case 7: month = 'Aug'; break;
621 case 8: month = 'Sep'; break;
622 case 9: month = 'Oct'; break;
623 case 10: month = 'Nov'; break;
624 case 11: month = 'Dec'; break;
625 }
626 return month + ' ' + date.getFullYear();
627 }
628
629 // Helper function to grab a querystring value
630 function querystring( key ) {
631 var re = new RegExp( '(?:\\?|&)'+key+'=(.*?)(?=&|$)', 'gi' );
632 var r = [], m;
633 while ( ( m = re.exec( document.location.search ) ) !== null )
634 r.push( m[1] );
635 return r;
636 }
637
638 // Helper function to check if an email address is valid.
639 function valid_email( email ) {
640 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,}))$/;
641 return re.test( email );
642 }
643
644
645 jQuery( document ).ready( function( $ ) {
646 // Grab references to form elements that we will show/hide on page load
647 var auth_settings_access_users_pending = $( '#list_auth_settings_access_users_pending' ).closest( 'tr' );
648 var auth_settings_access_users_approved = $( '#list_auth_settings_access_users_approved' ).closest( 'tr' );
649 var auth_settings_access_users_blocked = $( '#list_auth_settings_access_users_blocked' ).closest( 'tr' );
650 var auth_settings_access_role_receive_pending_emails = $( '#auth_settings_access_role_receive_pending_emails' ).closest( 'tr' );
651 var auth_settings_access_pending_redirect_to_message = $( '#wp-auth_settings_access_pending_redirect_to_message-wrap' ).closest( 'tr' );
652 var auth_settings_access_blocked_redirect_to_message = $( '#wp-auth_settings_access_blocked_redirect_to_message-wrap' ).closest( 'tr' );
653 var auth_settings_access_should_email_approved_users = $( '#auth_settings_access_should_email_approved_users' ).closest( 'tr' );
654 var auth_settings_access_email_approved_users_subject = $( '#auth_settings_access_email_approved_users_subject' ).closest( 'tr' );
655 var auth_settings_access_email_approved_users_body = $( '#wp-auth_settings_access_email_approved_users_body-wrap' ).closest( 'tr' );
656 var auth_settings_access_public_pages = $( '#auth_settings_access_public_pages' ).closest( 'tr' );
657 var auth_settings_access_redirect_to_login = $( '#radio_auth_settings_access_redirect_to_login' ).closest( 'tr' );
658 var auth_settings_access_public_warning = $( '#radio_auth_settings_access_public_warning' ).closest( 'tr' );
659 var auth_settings_access_redirect_to_message = $( '#wp-auth_settings_access_redirect_to_message-wrap' ).closest( 'tr' );
660 var auth_settings_external_settings_table = $( '#auth_settings_google' ).closest( 'table' );
661 var auth_settings_external_google = $( '#auth_settings_google' ).closest( 'tr' );
662 var auth_settings_external_google_clientid = $( '#auth_settings_google_clientid' ).closest( 'tr' );
663 var auth_settings_external_google_clientsecret = $( '#auth_settings_google_clientsecret' ).closest( 'tr' );
664 var auth_settings_external_cas = $( '#auth_settings_cas' ).closest( 'tr' );
665 var auth_settings_external_cas_custom_label = $( '#auth_settings_cas_custom_label' ).closest( 'tr' );
666 var auth_settings_external_cas_host = $( '#auth_settings_cas_host' ).closest( 'tr' );
667 var auth_settings_external_cas_port = $( '#auth_settings_cas_port' ).closest( 'tr' );
668 var auth_settings_external_cas_path = $( '#auth_settings_cas_path' ).closest( 'tr' );
669 var auth_settings_external_cas_attr_email = $( '#auth_settings_cas_attr_email' ).closest( 'tr' );
670 var auth_settings_external_cas_attr_first_name = $( '#auth_settings_cas_attr_first_name' ).closest( 'tr' );
671 var auth_settings_external_cas_attr_last_name = $( '#auth_settings_cas_attr_last_name' ).closest( 'tr' );
672 var auth_settings_external_cas_attr_update_on_login = $( '#auth_settings_cas_attr_update_on_login' ).closest( 'tr' );
673 var auth_settings_external_ldap = $( '#auth_settings_ldap' ).closest( 'tr' );
674 var auth_settings_external_ldap_host = $( '#auth_settings_ldap_host' ).closest( 'tr' );
675 var auth_settings_external_ldap_port = $( '#auth_settings_ldap_port' ).closest( 'tr' );
676 var auth_settings_external_ldap_search_base = $( '#auth_settings_ldap_search_base' ).closest( 'tr' );
677 var auth_settings_external_ldap_uid = $( '#auth_settings_ldap_uid' ).closest( 'tr' );
678 var auth_settings_external_ldap_attr_email = $( '#auth_settings_ldap_attr_email' ).closest( 'tr' );
679 var auth_settings_external_ldap_user = $( '#auth_settings_ldap_user' ).closest( 'tr' );
680 var auth_settings_external_ldap_password = $( '#auth_settings_ldap_password' ).closest( 'tr' );
681 var auth_settings_external_ldap_tls = $( '#auth_settings_ldap_tls' ).closest( 'tr' );
682 var auth_settings_external_ldap_lostpassword_url = $( '#auth_settings_ldap_lostpassword_url' ).closest( 'tr' );
683 var auth_settings_external_ldap_attr_first_name = $( '#auth_settings_ldap_attr_first_name' ).closest( 'tr' );
684 var auth_settings_external_ldap_attr_last_name = $( '#auth_settings_ldap_attr_last_name' ).closest( 'tr' );
685 var auth_settings_external_ldap_attr_update_on_login = $( '#auth_settings_ldap_attr_update_on_login' ).closest( 'tr' );
686
687 // Wrap the th and td in the rows above so we can animate their heights (can't animate tr heights with jquery)
688 $( 'th, td', auth_settings_access_users_pending ).wrapInner( '<div class="animated_wrapper" />' );
689 $( 'th, td', auth_settings_access_users_approved ).wrapInner( '<div class="animated_wrapper" />' );
690 $( 'th, td', auth_settings_access_users_blocked ).wrapInner( '<div class="animated_wrapper" />' );
691 $( 'th, td', auth_settings_access_role_receive_pending_emails ).wrapInner( '<div class="animated_wrapper" />' );
692 $( 'th, td', auth_settings_access_pending_redirect_to_message ).wrapInner( '<div class="animated_wrapper" />' );
693 $( 'th, td', auth_settings_access_blocked_redirect_to_message ).wrapInner( '<div class="animated_wrapper" />' );
694 $( 'th, td', auth_settings_access_should_email_approved_users ).wrapInner( '<div class="animated_wrapper" />' );
695 $( 'th, td', auth_settings_access_email_approved_users_subject ).wrapInner( '<div class="animated_wrapper" />' );
696 $( 'th, td', auth_settings_access_email_approved_users_body ).wrapInner( '<div class="animated_wrapper" />' );
697 $( 'th, td', auth_settings_access_public_pages ).wrapInner( '<div class="animated_wrapper" />' );
698 $( 'th, td', auth_settings_access_redirect_to_login ).wrapInner( '<div class="animated_wrapper" />' );
699 $( 'th, td', auth_settings_access_public_warning ).wrapInner( '<div class="animated_wrapper" />' );
700 $( 'th, td', auth_settings_access_redirect_to_message ).wrapInner( '<div class="animated_wrapper" />' );
701 $( 'th, td', auth_settings_external_google_clientid ).wrapInner( '<div class="animated_wrapper" />' );
702 $( 'th, td', auth_settings_external_google_clientsecret ).wrapInner( '<div class="animated_wrapper" />' );
703 $( 'th, td', auth_settings_external_cas_custom_label ).wrapInner( '<div class="animated_wrapper" />' );
704 $( 'th, td', auth_settings_external_cas_host ).wrapInner( '<div class="animated_wrapper" />' );
705 $( 'th, td', auth_settings_external_cas_port ).wrapInner( '<div class="animated_wrapper" />' );
706 $( 'th, td', auth_settings_external_cas_path ).wrapInner( '<div class="animated_wrapper" />' );
707 $( 'th, td', auth_settings_external_cas_attr_email ).wrapInner( '<div class="animated_wrapper" />' );
708 $( 'th, td', auth_settings_external_cas_attr_first_name ).wrapInner( '<div class="animated_wrapper" />' );
709 $( 'th, td', auth_settings_external_cas_attr_last_name ).wrapInner( '<div class="animated_wrapper" />' );
710 $( 'th, td', auth_settings_external_cas_attr_update_on_login ).wrapInner( '<div class="animated_wrapper" />' );
711 $( 'th, td', auth_settings_external_ldap_host ).wrapInner( '<div class="animated_wrapper" />' );
712 $( 'th, td', auth_settings_external_ldap_port ).wrapInner( '<div class="animated_wrapper" />' );
713 $( 'th, td', auth_settings_external_ldap_search_base ).wrapInner( '<div class="animated_wrapper" />' );
714 $( 'th, td', auth_settings_external_ldap_uid ).wrapInner( '<div class="animated_wrapper" />' );
715 $( 'th, td', auth_settings_external_ldap_attr_email ).wrapInner( '<div class="animated_wrapper" />' );
716 $( 'th, td', auth_settings_external_ldap_user ).wrapInner( '<div class="animated_wrapper" />' );
717 $( 'th, td', auth_settings_external_ldap_password ).wrapInner( '<div class="animated_wrapper" />' );
718 $( 'th, td', auth_settings_external_ldap_tls ).wrapInner( '<div class="animated_wrapper" />' );
719 $( 'th, td', auth_settings_external_ldap_lostpassword_url ).wrapInner( '<div class="animated_wrapper" />' );
720 $( 'th, td', auth_settings_external_ldap_attr_first_name ).wrapInner( '<div class="animated_wrapper" />' );
721 $( 'th, td', auth_settings_external_ldap_attr_last_name ).wrapInner( '<div class="animated_wrapper" />' );
722 $( 'th, td', auth_settings_external_ldap_attr_update_on_login ).wrapInner( '<div class="animated_wrapper" />' );
723
724 // If we're viewing the dashboard widget, reset a couple of the relevant
725 // option variables (since they're aren't nested in table rows).
726 if ( $( '#auth_dashboard_widget' ).length ) {
727 auth_settings_access_users_pending = $( '#list_auth_settings_access_users_pending' ).closest( 'div' );
728 auth_settings_access_users_approved = $( '#list_auth_settings_access_users_approved' ).closest( 'div' );
729 auth_settings_access_users_blocked = $( '#list_auth_settings_access_users_blocked' ).closest( 'div' );
730 $( auth_settings_access_users_pending ).wrapInner( '<div class="animated_wrapper" />' );
731 $( auth_settings_access_users_approved ).wrapInner( '<div class="animated_wrapper" />' );
732 $( auth_settings_access_users_blocked ).wrapInner( '<div class="animated_wrapper" />' );
733
734 // Remove the helper link, since there are no tabs on the dashboard widget
735 $( '#dashboard_link_approved_users' ).contents().unwrap();
736 }
737
738 // Hide Welcome email body/subject options if "Send welcome email" is off.
739 if ( ! $( '#auth_settings_access_should_email_approved_users' ).is( ':checked' ) ) {
740 animate_option( 'hide_immediately', auth_settings_access_email_approved_users_subject );
741 animate_option( 'hide_immediately', auth_settings_access_email_approved_users_body );
742 }
743
744 // On load: Show/hide public access options if everyone can see site
745 if ( ! $( '#radio_auth_settings_access_who_can_view_logged_in_users' ).is( ':checked' ) ) {
746 animate_option( 'hide_immediately', auth_settings_access_public_pages );
747 animate_option( 'hide_immediately', auth_settings_access_redirect_to_login );
748 animate_option( 'hide_immediately', auth_settings_access_public_warning );
749 animate_option( 'hide_immediately', auth_settings_access_redirect_to_message );
750 }
751
752 // Hide Google options if unchecked
753 if ( ! $( '#auth_settings_google' ).is( ':checked' ) ) {
754 animate_option( 'hide_immediately', auth_settings_external_google_clientid );
755 animate_option( 'hide_immediately', auth_settings_external_google_clientsecret );
756 }
757
758 // Hide CAS options if unchecked
759 if ( ! $( '#auth_settings_cas' ).is( ':checked' ) ) {
760 animate_option( 'hide_immediately', auth_settings_external_cas_custom_label );
761 animate_option( 'hide_immediately', auth_settings_external_cas_host );
762 animate_option( 'hide_immediately', auth_settings_external_cas_port );
763 animate_option( 'hide_immediately', auth_settings_external_cas_path );
764 animate_option( 'hide_immediately', auth_settings_external_cas_attr_email );
765 animate_option( 'hide_immediately', auth_settings_external_cas_attr_first_name );
766 animate_option( 'hide_immediately', auth_settings_external_cas_attr_last_name );
767 animate_option( 'hide_immediately', auth_settings_external_cas_attr_update_on_login );
768 }
769
770 // Hide LDAP options if unchecked
771 if ( ! $( '#auth_settings_ldap' ).is( ':checked' ) ) {
772 animate_option( 'hide_immediately', auth_settings_external_ldap_host );
773 animate_option( 'hide_immediately', auth_settings_external_ldap_port );
774 animate_option( 'hide_immediately', auth_settings_external_ldap_search_base );
775 animate_option( 'hide_immediately', auth_settings_external_ldap_uid );
776 animate_option( 'hide_immediately', auth_settings_external_ldap_attr_email );
777 animate_option( 'hide_immediately', auth_settings_external_ldap_user );
778 animate_option( 'hide_immediately', auth_settings_external_ldap_password );
779 animate_option( 'hide_immediately', auth_settings_external_ldap_tls );
780 animate_option( 'hide_immediately', auth_settings_external_ldap_lostpassword_url );
781 animate_option( 'hide_immediately', auth_settings_external_ldap_attr_first_name );
782 animate_option( 'hide_immediately', auth_settings_external_ldap_attr_last_name );
783 animate_option( 'hide_immediately', auth_settings_external_ldap_attr_update_on_login );
784 }
785
786 // Event handler: Hide "Handle unauthorized visitors" option if access is granted to "Everyone"
787 $( 'input[name="auth_settings[access_who_can_login]"]' ).change( function() {
788 // Hide user whitelist unless "Only specific students below" is checked
789 var action = $( '#radio_auth_settings_access_who_can_login_approved_users' ).is( ':checked' ) ? 'show' : 'hide';
790 animate_option( action, auth_settings_access_role_receive_pending_emails );
791 animate_option( action, auth_settings_access_pending_redirect_to_message );
792 animate_option( action, auth_settings_access_blocked_redirect_to_message );
793 animate_option( action, auth_settings_access_should_email_approved_users );
794 animate_option( action, auth_settings_access_email_approved_users_subject );
795 animate_option( action, auth_settings_access_email_approved_users_body );
796 });
797
798 // Event handler: Hide Welcome email body/subject options if "Send welcome email" is off.
799 $( 'input[name="auth_settings[access_should_email_approved_users]"]' ).change( function() {
800 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
801 animate_option( action, auth_settings_access_email_approved_users_subject );
802 animate_option( action, auth_settings_access_email_approved_users_body );
803 });
804
805 // Event handler: Hide "Handle unauthorized visitors" option if access is granted to "Everyone"
806 $( 'input[name="auth_settings[access_who_can_view]"]' ).change( function() {
807 var action = $( '#radio_auth_settings_access_who_can_view_everyone' ).is( ':checked' ) ? 'hide' : 'show';
808 animate_option( action, auth_settings_access_redirect_to_login );
809 animate_option( action, auth_settings_access_redirect_to_message );
810 animate_option( action, auth_settings_access_public_pages );
811 animate_option( action, auth_settings_access_public_warning );
812 });
813
814 // Event handler: Show/hide Google options based on checkbox
815 $( 'input[name="auth_settings[google]"]' ).change( function() {
816 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
817 animate_option( action, auth_settings_external_google_clientid );
818 animate_option( action, auth_settings_external_google_clientsecret );
819 });
820
821 // Event handler: Show/hide CAS options based on checkbox
822 $( 'input[name="auth_settings[cas]"]' ).change( function() {
823 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
824 animate_option( action, auth_settings_external_cas_custom_label );
825 animate_option( action, auth_settings_external_cas_host );
826 animate_option( action, auth_settings_external_cas_port );
827 animate_option( action, auth_settings_external_cas_path );
828 animate_option( action, auth_settings_external_cas_attr_email );
829 animate_option( action, auth_settings_external_cas_attr_first_name );
830 animate_option( action, auth_settings_external_cas_attr_last_name );
831 animate_option( action, auth_settings_external_cas_attr_update_on_login );
832 });
833
834 // Event handler: Show/hide LDAP options based on checkbox
835 $( 'input[name="auth_settings[ldap]"]' ).change( function() {
836 var action = $( this ).is( ':checked' ) ? 'show' : 'hide';
837 animate_option( action, auth_settings_external_ldap_host );
838 animate_option( action, auth_settings_external_ldap_port );
839 animate_option( action, auth_settings_external_ldap_search_base );
840 animate_option( action, auth_settings_external_ldap_uid );
841 animate_option( action, auth_settings_external_ldap_attr_email );
842 animate_option( action, auth_settings_external_ldap_user );
843 animate_option( action, auth_settings_external_ldap_password );
844 animate_option( action, auth_settings_external_ldap_tls );
845 animate_option( action, auth_settings_external_ldap_lostpassword_url );
846 animate_option( action, auth_settings_external_ldap_attr_first_name );
847 animate_option( action, auth_settings_external_ldap_attr_last_name );
848 animate_option( action, auth_settings_external_ldap_attr_update_on_login );
849 });
850
851 // Show save button if usermeta field is modified.
852 $( 'form input.auth-usermeta' ).bind( 'keyup', function ( event ) {
853 // Don't do anything if tab or arrow keys were pressed.
854 if ( event.which === 9 || event.which === 37 || event.which === 38 || event.which === 39 || event.which === 40 ) {
855 return;
856 }
857 $( this ).siblings( '.button' ).css( 'display', 'inline-block' );
858 });
859
860 // List management function: pressing enter in the new approved or new
861 // blocked user (email or role field) adds the user to the list.
862 $( '#new_approved_user_email, #new_approved_user_role, #new_blocked_user_email' ).bind( 'keyup', function( e ) {
863 if ( e.which == 13 ) { // Enter key
864 $( this ).parent().find( 'a' ).trigger( 'click' );
865 return false;
866 }
867 });
868
869 // Don't submit form (i.e., save options) when hitting enter in any user list field.
870 $( 'input.auth-email, select.auth-role, input.auth-date-added, input.auth-usermeta' ).bind( 'keydown', function( e ) {
871 if ( e.which == 13 ) { // Enter key
872 e.preventDefault();
873 return false;
874 }
875 });
876
877 // Enable the user-friendly multiselect form element on the options page.
878 $( '#auth_settings_access_public_pages' ).multiSelect({
879 selectableOptgroup: true,
880 selectableHeader: '<div class="custom-header">Private Pages</div>',
881 selectionHeader: '<div class="custom-header">Public Pages</div>',
882 });
883
884 // Switch to the first tab (or the tab indicated in sessionStorage, or the querystring).
885 var tab = '';
886 if ( querystring( 'tab' ).length > 0 ) {
887 tab = querystring( 'tab' )[0];
888 } else if ( sessionStorage.getItem( 'tab' ) ) {
889 tab = sessionStorage.getItem( 'tab' );
890 }
891 if ( $.inArray( tab, [ 'access_lists', 'access_login', 'access_public', 'external', 'advanced' ] ) < 0 ) {
892 tab = 'access_lists';
893 }
894 choose_tab( tab, animation_speed );
895
896 // Hide/show multisite settings based on override checkbox.
897 $( 'input[name="auth_settings[multisite_override]"]' ).change( function() {
898 hide_multisite_settings_if_disabled();
899 });
900 hide_multisite_settings_if_disabled();
901
902 });
903
904
905 /**
906 * Portions below from Bootstrap
907 * http://getbootstrap.com/getting-started/#download
908 */
909
910
911 /*!
912 * Bootstrap v3.1.1 (http://getbootstrap.com)
913 * Copyright 2011-2014 Twitter, Inc.
914 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
915 */
916
917 if ( typeof jQuery === 'undefined' ) { throw new Error( 'Bootstrap\'s JavaScript requires jQuery' ) }
918
919 /* ========================================================================
920 * Bootstrap: dropdown.js v3.1.1
921 * http://getbootstrap.com/javascript/#dropdowns
922 * ========================================================================
923 * Copyright 2011-2014 Twitter, Inc.
924 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
925 * ======================================================================== */
926
927
928 +function ($) {
929 'use strict';
930
931 // DROPDOWN CLASS DEFINITION
932 // =========================
933
934 var backdrop = '.dropdown-backdrop'
935 var toggle = '[data-toggle=dropdown]'
936 var Dropdown = function ( element ) {
937 $( element ).on( 'click.bs.dropdown', this.toggle)
938 }
939
940 Dropdown.prototype.toggle = function ( e ) {
941 var $this = $( this )
942
943 if ($this.is( '.disabled, :disabled' )) return
944
945 var $parent = getParent($this)
946 var isActive = $parent.hasClass( 'open' )
947
948 clearMenus()
949
950 if (!isActive) {
951 if ( 'ontouchstart' in document.documentElement && !$parent.closest( '.navbar-nav' ).length) {
952 // if mobile we use a backdrop because click events don't delegate
953 $( '<div class="dropdown-backdrop"/>' ).insertAfter($( this )).on( 'click', clearMenus)
954 }
955
956 var relatedTarget = { relatedTarget: this }
957 $parent.trigger( e = $.Event( 'show.bs.dropdown', relatedTarget ) )
958
959 if (e.isDefaultPrevented()) return
960
961 $parent
962 .toggleClass( 'open' )
963 .trigger( 'shown.bs.dropdown', relatedTarget)
964
965 $this.focus()
966 }
967
968 return false
969 }
970
971 Dropdown.prototype.keydown = function (e) {
972 if (!/(38|40|27)/.test(e.keyCode)) return
973
974 var $this = $( this )
975
976 e.preventDefault()
977 e.stopPropagation()
978
979 if ($this.is( '.disabled, :disabled' )) return
980
981 var $parent = getParent($this)
982 var isActive = $parent.hasClass( 'open' )
983
984 if (!isActive || (isActive && e.keyCode == 27)) {
985 if (e.which == 27) $parent.find(toggle).focus()
986 return $this.click()
987 }
988
989 var desc = ' li:not(.divider):visible a'
990 var $items = $parent.find( '[role=menu]' + desc + ', [role=listbox]' + desc)
991
992 if (!$items.length) return
993
994 var index = $items.index($items.filter( ':focus' ))
995
996 if (e.keyCode == 38 && index > 0) index-- // up
997 if (e.keyCode == 40 && index < $items.length - 1) index++ // down
998 if (!~index) index = 0
999
1000 $items.eq(index).focus()
1001 }
1002
1003 function clearMenus(e) {
1004 $(backdrop).remove()
1005 $(toggle).each(function () {
1006 var $parent = getParent($( this ))
1007 var relatedTarget = { relatedTarget: this }
1008 if (!$parent.hasClass( 'open' )) return
1009 $parent.trigger(e = $.Event( 'hide.bs.dropdown', relatedTarget))
1010 if (e.isDefaultPrevented()) return
1011 $parent.removeClass( 'open' ).trigger( 'hidden.bs.dropdown', relatedTarget)
1012 })
1013 }
1014
1015 function getParent($this) {
1016 var selector = $this.attr( 'data-target' )
1017
1018 if (!selector) {
1019 selector = $this.attr( 'href' )
1020 selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '' ) //strip for ie7
1021 }
1022
1023 var $parent = selector && $(selector)
1024
1025 return $parent && $parent.length ? $parent : $this.parent()
1026 }
1027
1028
1029 // DROPDOWN PLUGIN DEFINITION
1030 // ==========================
1031
1032 var old = $.fn.dropdown
1033
1034 $.fn.dropdown = function (option) {
1035 return this.each(function () {
1036 var $this = $( this )
1037 var data = $this.data( 'bs.dropdown' )
1038
1039 if (!data) $this.data( 'bs.dropdown', (data = new Dropdown( this )))
1040 if (typeof option == 'string' ) data[option].call($this)
1041 })
1042 }
1043
1044 $.fn.dropdown.Constructor = Dropdown
1045
1046
1047 // DROPDOWN NO CONFLICT
1048 // ====================
1049
1050 $.fn.dropdown.noConflict = function () {
1051 $.fn.dropdown = old
1052 return this
1053 }
1054
1055
1056 // APPLY TO STANDARD DROPDOWN ELEMENTS
1057 // ===================================
1058
1059 $(document)
1060 .on( 'click.bs.dropdown.data-api', clearMenus)
1061 .on( 'click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
1062 .on( 'click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
1063 .on( 'keydown.bs.dropdown.data-api', toggle + ', [role=menu], [role=listbox]', Dropdown.prototype.keydown)
1064
1065 }(jQuery);
1066