Changeset 13164
- Timestamp:
- 12/10/2021 01:29:52 AM (2 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/.jshintignore
r13005 r13164 14 14 src/**/js/dynamic-widget-block.js 15 15 src/**/js/sitewide-notices.js 16 src/**/bp-core/admin/js/dismissible-admin-notices.js 17 src/**/bp-members/admin/js/admin.js -
trunk/Gruntfile.js
r13113 r13164 28 28 '!**/js/dynamic-groups.js', 29 29 '!**/js/dynamic-widget-block.js', 30 '!**/js/sitewide-notices.js' 30 '!**/js/sitewide-notices.js', 31 '!**/bp-core/admin/js/dismissible-admin-notices.js', 32 '!**/bp-members/admin/js/admin.js' 31 33 ], 32 34 -
trunk/package.json
r13113 r13164 44 44 "scripts": { 45 45 "start": "npm run dev:components && npm run dev:assets && parcel watch src/js/bp-*/*s/blocks/*.js --out-dir src --no-source-maps", 46 "dev": "npm run dev:components && npm run dev:assets && npm run dev:scripts && parcel build src/js/bp-*/*s/blocks/*.js --out-dir src --no-source-maps --no-minify",47 "build": "npm run build:components && npm run build:assets && npm run build:scripts && parcel build src/js/bp-*/*s/blocks/*.js --out-dir build",46 "dev": "npm run dev:components && npm run dev:assets && npm run dev:scripts && npm run dev:admin-scripts && parcel build src/js/bp-*/*s/blocks/*.js --out-dir src --no-source-maps --no-minify", 47 "build": "npm run build:components && npm run build:assets && npm run build:scripts && npm run build:admin-scripts && parcel build src/js/bp-*/*s/blocks/*.js --out-dir build", 48 48 "watch:components": "parcel watch src/js/bp-core/js/block-components/block-components.js --out-dir src/bp-core/js --out-file block-components.js --no-source-maps --global bpBlock", 49 49 "dev:components": "parcel build src/js/bp-core/js/block-components/block-components.js --out-dir src/bp-core/js --out-file block-components.js --no-source-maps --no-minify --global bpBlock", … … 54 54 "dev:scripts": "parcel build src/js/bp-*/*s/* --out-dir src --no-source-maps --no-minify", 55 55 "build:scripts": "parcel build src/js/bp-*/*s/* --out-dir build", 56 "dev:admin-scripts": "parcel build src/js/bp-*/admin/*s/* --out-dir src --no-source-maps --no-minify", 57 "build:admin-scripts": "parcel build src/js/bp-*/admin/*s/* --out-dir build", 56 58 "wp-env": "wp-env", 57 59 "test-php": "npm run wp-env run phpunit 'php /var/www/html/wp-content/plugins/buddypress/vendor/phpunit/phpunit/phpunit -c /var/www/html/wp-content/plugins/buddypress/tests/phpunit/env.xml'", -
trunk/src/bp-core/admin/bp-core-admin-functions.php
r13137 r13164 1417 1417 } 1418 1418 1419 if ( empty( $_POST['nonce'] ) || empty( $_POST['notice_id'] ) ) { 1419 $nonce_data = array(); 1420 if ( isset( $_SERVER['HTTP_X_BP_NONCE'] ) ) { 1421 $nonce_data = array( 1422 'nonce' => $_SERVER['HTTP_X_BP_NONCE'], 1423 'action' => 'bp_dismiss_admin_notice', 1424 ); 1425 } elseif ( isset( $_POST['nonce'] ) ) { 1426 $nonce_data['nonce'] = $_POST['nonce']; 1427 } 1428 1429 if ( empty( $nonce_data['nonce'] ) || empty( $_POST['notice_id'] ) ) { 1420 1430 wp_send_json_error(); 1421 1431 } 1422 1432 1423 1433 $notice_id = wp_unslash( $_POST['notice_id'] ); 1424 1425 if ( ! wp_verify_nonce( $_POST['nonce'], 'bp-dismissible-notice-' . $notice_id ) ) { 1434 if ( ! isset( $nonce_data['action'] ) ) { 1435 $nonce_data['action'] = 'bp-dismissible-notice-' . $notice_id; 1436 } 1437 1438 if ( ! wp_verify_nonce( $nonce_data['nonce'], $nonce_data['action'] ) ) { 1426 1439 wp_send_json_error(); 1427 1440 } 1428 1441 1429 bp_update_option( "bp-dismissed-notice- $notice_id", 1);1442 bp_update_option( "bp-dismissed-notice-{$notice_id}", true ); 1430 1443 1431 1444 wp_send_json_success(); -
trunk/src/bp-core/admin/css/common-rtl.css
r13163 r13164 603 603 .buddypress .welcome-panel-content p { 604 604 padding-bottom: 23px; 605 font-size: 14px; 605 606 } 606 607 -
trunk/src/bp-core/admin/js/dismissible-admin-notices.js
r11175 r13164 1 (function($){ 2 $(document).ready(function() { 3 $( '.bp-is-dismissible .notice-dismiss' ).click( function() { 4 var $notice = $( this ).closest( '.notice' ); 5 var notice_id = $notice.data( 'noticeid' ); 6 $.post( { 7 url: ajaxurl, 8 data: { 9 action: 'bp_dismiss_notice', 10 nonce: $( '#bp-dismissible-nonce-' + notice_id ).val(), 11 notice_id: $notice.data( 'noticeid' ) 12 } 13 } ); 14 } ); 15 }); 16 }(jQuery)); 1 // modules are defined as an array 2 // [ module function, map of requires ] 3 // 4 // map of requires is short require name -> numeric require 5 // 6 // anything defined in a previous bundle is accessed via the 7 // orig method which is the require for previous bundles 8 parcelRequire = (function (modules, cache, entry, globalName) { 9 // Save the require from previous bundle to this closure if any 10 var previousRequire = typeof parcelRequire === 'function' && parcelRequire; 11 var nodeRequire = typeof require === 'function' && require; 12 13 function newRequire(name, jumped) { 14 if (!cache[name]) { 15 if (!modules[name]) { 16 // if we cannot find the module within our internal map or 17 // cache jump to the current global require ie. the last bundle 18 // that was added to the page. 19 var currentRequire = typeof parcelRequire === 'function' && parcelRequire; 20 if (!jumped && currentRequire) { 21 return currentRequire(name, true); 22 } 23 24 // If there are other bundles on this page the require from the 25 // previous one is saved to 'previousRequire'. Repeat this as 26 // many times as there are bundles until the module is found or 27 // we exhaust the require chain. 28 if (previousRequire) { 29 return previousRequire(name, true); 30 } 31 32 // Try the node require function if it exists. 33 if (nodeRequire && typeof name === 'string') { 34 return nodeRequire(name); 35 } 36 37 var err = new Error('Cannot find module \'' + name + '\''); 38 err.code = 'MODULE_NOT_FOUND'; 39 throw err; 40 } 41 42 localRequire.resolve = resolve; 43 localRequire.cache = {}; 44 45 var module = cache[name] = new newRequire.Module(name); 46 47 modules[name][0].call(module.exports, localRequire, module, module.exports, this); 48 } 49 50 return cache[name].exports; 51 52 function localRequire(x){ 53 return newRequire(localRequire.resolve(x)); 54 } 55 56 function resolve(x){ 57 return modules[name][1][x] || x; 58 } 59 } 60 61 function Module(moduleName) { 62 this.id = moduleName; 63 this.bundle = newRequire; 64 this.exports = {}; 65 } 66 67 newRequire.isParcelRequire = true; 68 newRequire.Module = Module; 69 newRequire.modules = modules; 70 newRequire.cache = cache; 71 newRequire.parent = previousRequire; 72 newRequire.register = function (id, exports) { 73 modules[id] = [function (require, module) { 74 module.exports = exports; 75 }, {}]; 76 }; 77 78 var error; 79 for (var i = 0; i < entry.length; i++) { 80 try { 81 newRequire(entry[i]); 82 } catch (e) { 83 // Save first error but execute all entries 84 if (!error) { 85 error = e; 86 } 87 } 88 } 89 90 if (entry.length) { 91 // Expose entry point to Node, AMD or browser globals 92 // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js 93 var mainExports = newRequire(entry[entry.length - 1]); 94 95 // CommonJS 96 if (typeof exports === "object" && typeof module !== "undefined") { 97 module.exports = mainExports; 98 99 // RequireJS 100 } else if (typeof define === "function" && define.amd) { 101 define(function () { 102 return mainExports; 103 }); 104 105 // <script> 106 } else if (globalName) { 107 this[globalName] = mainExports; 108 } 109 } 110 111 // Override the current require with this new one 112 parcelRequire = newRequire; 113 114 if (error) { 115 // throw error from earlier, _after updating parcelRequire_ 116 throw error; 117 } 118 119 return newRequire; 120 })({"XBG5":[function(require,module,exports) { 121 // Use the bp global. 122 window.bp = window.bp || {}; 123 /** 124 * Use an XHR request to dismiss admin notices. 125 * 126 * @since 10.0.0 127 */ 128 129 bp.DismissibleAdminNotices = class { 130 constructor(settings) { 131 this.settings = settings || {}; 132 } 133 134 start() { 135 const { 136 url, 137 nonce 138 } = this.settings; 139 140 if (!url || !nonce) { 141 return; 142 } 143 144 document.querySelectorAll('.bp-is-dismissible').forEach(notice => { 145 notice.addEventListener('click', event => { 146 event.preventDefault(); 147 const noticeLink = event.target; 148 149 if (noticeLink.classList.contains('loading')) { 150 return; 151 } // Prevent multiple clicks. 152 153 154 noticeLink.classList.add('loading'); // Set the notice ID & notice container. 155 156 const { 157 notice_id 158 } = noticeLink.dataset; 159 const noticeContainer = noticeLink.closest('.bp-notice-container'); // Set notice headers. 160 161 const noticeHeaders = new Headers({ 162 'X-BP-Nonce': nonce 163 }); // Set notice data. 164 165 const noticeData = new FormData(); 166 noticeData.append('action', 'bp_dismiss_notice'); 167 noticeData.append('notice_id', notice_id); 168 fetch(url, { 169 method: 'POST', 170 headers: noticeHeaders, 171 body: noticeData 172 }).then(response => { 173 return response.json(); 174 }).then(data => { 175 const { 176 success 177 } = data; 178 179 if (success) { 180 noticeContainer.remove(); 181 } else { 182 noticeLink.classList.remove('loading'); 183 } 184 }); 185 }); 186 }); 187 } 188 189 }; 190 const settings = window.bpDismissibleAdminNoticesSettings || {}; 191 const bpDismissibleAdminNotices = new bp.DismissibleAdminNotices(settings); 192 193 if ('loading' === document.readyState) { 194 document.addEventListener('DOMContentLoaded', bpDismissibleAdminNotices.start()); 195 } else { 196 bpDismissibleAdminNotices.start(); 197 } 198 },{}]},{},["XBG5"], null) -
trunk/src/bp-core/classes/class-bp-admin.php
r13163 r13164 1296 1296 'footer' => true, 1297 1297 ), 1298 1299 // 10.0 1300 'bp-dismissible-admin-notices' => array( 1301 'file' => "{$url}dismissible-admin-notices.js", 1302 'dependencies' => array(), 1303 'footer' => true, 1304 'extra' => array( 1305 'name' => 'bpDismissibleAdminNoticesSettings', 1306 'data' => array( 1307 'url' => bp_core_ajax_url(), 1308 'nonce' => wp_create_nonce( 'bp_dismiss_admin_notice' ), 1309 ), 1310 ), 1311 ), 1298 1312 ) ); 1299 1313 … … 1302 1316 foreach ( $scripts as $id => $script ) { 1303 1317 wp_register_script( $id, $script['file'], $script['dependencies'], $version, $script['footer'] ); 1318 1319 if ( isset( $script['extra'] ) ) { 1320 // List the block specific props. 1321 wp_add_inline_script( 1322 $id, 1323 sprintf( 'var %1$s = %2$s;', $script['extra']['name'], wp_json_encode( $script['extra']['data'] ) ), 1324 'before' 1325 ); 1326 } 1304 1327 } 1305 1328 } … … 1415 1438 * Displays the list of "BuddyPress Add-ons". 1416 1439 * 1417 * @todo we should have a page on the BuddyPress codex to explain feature plugins like this one:1418 * https://make.wordpress.org/core/features/1419 *1420 1440 * @since 10.0.0 1421 1441 */ 1422 1442 public function display_addons_table() { 1423 ?> 1424 <div id="welcome-panel" class="welcome-panel"> 1425 <a class="welcome-panel-close" href="#" aria-label="Dismiss the welcome panel"><?php esc_html_e( 'Dismiss', 'buddypress' ); ?></a> 1426 <div class="welcome-panel-content"> 1427 <h2><span class="bp-badge"></span> <?php esc_html_e( 'Hello BuddyPress Add-ons!', 'buddypress' ); ?></h2> 1428 <p class="about-description"> 1429 <?php esc_html_e( 'Add-ons are features as Plugins or Blocks maintained by the BuddyPress development team & hosted on the WordPress.org plugins directory.', 'buddypress' ); ?> 1430 <?php esc_html_e( 'Thanks to this new tab inside your Dashboard screen to add plugins, you’ll be able to find them faster and eventually contribute to beta features early to give the BuddyPress development team your feedbacks.', 'buddypress' ); ?> 1431 </p> 1443 $notice_id = 'bp100-welcome-addons'; 1444 $dismissed = bp_get_option( "bp-dismissed-notice-{$notice_id}", false ); 1445 1446 if ( ! $dismissed ) { 1447 // Enqueue the Script to Ajax Dismiss an Admin notice. 1448 wp_enqueue_script( 'bp-dismissible-admin-notices' ); 1449 1450 ?> 1451 <div id="welcome-panel" class="welcome-panel bp-notice-container"> 1452 <a class="welcome-panel-close bp-is-dismissible" href="#" data-notice_id="<?php echo esc_attr( $notice_id ); ?>" aria-label="<?php esc_attr_e( 'Dismiss the welcome panel', 'buddypress' ); ?>"><?php esc_html_e( 'Dismiss', 'buddypress' ); ?></a> 1453 <div class="welcome-panel-content"> 1454 <h2><span class="bp-badge"></span> <?php esc_html_e( 'Hello BuddyPress Add-ons!', 'buddypress' ); ?></h2> 1455 <p class="about-description"> 1456 <?php esc_html_e( 'Add-ons are features as Plugins or Blocks maintained by the BuddyPress development team & hosted on the WordPress.org plugins directory.', 'buddypress' ); ?> 1457 <?php esc_html_e( 'Thanks to this new tab inside your Dashboard screen to add plugins, you’ll be able to find them faster and eventually contribute to beta features early to give the BuddyPress development team your feedbacks.', 'buddypress' ); ?> 1458 </p> 1459 </div> 1432 1460 </div> 1433 </div> 1434 <?php 1435 // Display the "buddypress" favorites ;) 1461 <?php 1462 } 1463 1464 // Display the "buddypress" favorites. 1436 1465 display_plugins_table(); 1437 1466 } -
trunk/src/bp-members/admin/js/admin.js
r13017 r13164 1 /* exported clear */ 1 // modules are defined as an array 2 // [ module function, map of requires ] 3 // 4 // map of requires is short require name -> numeric require 5 // 6 // anything defined in a previous bundle is accessed via the 7 // orig method which is the require for previous bundles 8 parcelRequire = (function (modules, cache, entry, globalName) { 9 // Save the require from previous bundle to this closure if any 10 var previousRequire = typeof parcelRequire === 'function' && parcelRequire; 11 var nodeRequire = typeof require === 'function' && require; 2 12 3 ( function( $ ) { 4 // Profile Visibility Settings 5 $( '.visibility-toggle-link' ).on( 'click', function( event ) { 6 event.preventDefault(); 13 function newRequire(name, jumped) { 14 if (!cache[name]) { 15 if (!modules[name]) { 16 // if we cannot find the module within our internal map or 17 // cache jump to the current global require ie. the last bundle 18 // that was added to the page. 19 var currentRequire = typeof parcelRequire === 'function' && parcelRequire; 20 if (!jumped && currentRequire) { 21 return currentRequire(name, true); 22 } 7 23 8 $( this ).attr( 'aria-expanded', 'true' ).parent().hide() 9 .siblings( '.field-visibility-settings' ).show(); 10 } ); 24 // If there are other bundles on this page the require from the 25 // previous one is saved to 'previousRequire'. Repeat this as 26 // many times as there are bundles until the module is found or 27 // we exhaust the require chain. 28 if (previousRequire) { 29 return previousRequire(name, true); 30 } 11 31 12 $( '.field-visibility-settings-close' ).on( 'click', function( event ) { 13 event.preventDefault(); 32 // Try the node require function if it exists. 33 if (nodeRequire && typeof name === 'string') { 34 return nodeRequire(name); 35 } 14 36 15 $( '.visibility-toggle-link' ).attr( 'aria-expanded', 'false' ); 37 var err = new Error('Cannot find module \'' + name + '\''); 38 err.code = 'MODULE_NOT_FOUND'; 39 throw err; 40 } 16 41 17 var settings_div = $( this ).parent(), 18 vis_setting_text = settings_div.find( 'input:checked' ).parent().text();42 localRequire.resolve = resolve; 43 localRequire.cache = {}; 19 44 20 settings_div.hide() 21 .siblings( '.field-visibility-settings-toggle' ) 22 .find( '.current-visibility-level' ).text( vis_setting_text ).end() 23 .show(); 24 } ); 45 var module = cache[name] = new newRequire.Module(name); 25 46 26 } )( jQuery ); 47 modules[name][0].call(module.exports, localRequire, module, module.exports, this); 48 } 27 49 50 return cache[name].exports; 28 51 52 function localRequire(x){ 53 return newRequire(localRequire.resolve(x)); 54 } 55 56 function resolve(x){ 57 return modules[name][1][x] || x; 58 } 59 } 60 61 function Module(moduleName) { 62 this.id = moduleName; 63 this.bundle = newRequire; 64 this.exports = {}; 65 } 66 67 newRequire.isParcelRequire = true; 68 newRequire.Module = Module; 69 newRequire.modules = modules; 70 newRequire.cache = cache; 71 newRequire.parent = previousRequire; 72 newRequire.register = function (id, exports) { 73 modules[id] = [function (require, module) { 74 module.exports = exports; 75 }, {}]; 76 }; 77 78 var error; 79 for (var i = 0; i < entry.length; i++) { 80 try { 81 newRequire(entry[i]); 82 } catch (e) { 83 // Save first error but execute all entries 84 if (!error) { 85 error = e; 86 } 87 } 88 } 89 90 if (entry.length) { 91 // Expose entry point to Node, AMD or browser globals 92 // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js 93 var mainExports = newRequire(entry[entry.length - 1]); 94 95 // CommonJS 96 if (typeof exports === "object" && typeof module !== "undefined") { 97 module.exports = mainExports; 98 99 // RequireJS 100 } else if (typeof define === "function" && define.amd) { 101 define(function () { 102 return mainExports; 103 }); 104 105 // <script> 106 } else if (globalName) { 107 this[globalName] = mainExports; 108 } 109 } 110 111 // Override the current require with this new one 112 parcelRequire = newRequire; 113 114 if (error) { 115 // throw error from earlier, _after updating parcelRequire_ 116 throw error; 117 } 118 119 return newRequire; 120 })({"wb1e":[function(require,module,exports) { 121 // Use the bp global. 122 window.bp = window.bp || {}; 29 123 /** 30 * Deselects any select options or input options for the specified field element.124 * Clears the checked/selected options of a radio button or a multiple select. 31 125 * 32 * @param {String} container HTML ID of the field 33 * @since 1.0.0 126 * @since 10.0.0 127 * @param {HTMLElement} container The HTMLElement containing the options to clear. 128 * @returns {void} 34 129 */ 35 function clear( container ) {36 container = document.getElementById( container );37 if ( ! container ) {38 return;39 }40 130 41 var radioButtons = container.getElementsByTagName( 'INPUT' ), 42 options = container.getElementsByTagName( 'OPTION' ), 43 i = 0; 131 bp.clear = container => { 132 const optionsContainer = document.getElementById(container); 44 133 45 if ( radioButtons ) { 46 for ( i = 0; i < radioButtons.length; i++ ) { 47 radioButtons[i].checked = ''; 48 } 49 } 134 if (!optionsContainer) { 135 return; 136 } 50 137 51 if ( options ) { 52 for ( i = 0; i < options.length; i++ ) { 53 options[i].selected = false; 54 } 55 } 56 } 138 const checkedRadio = optionsContainer.querySelector('input:checked'); 139 const allOptions = optionsContainer.querySelectorAll('option'); 140 141 if (checkedRadio) { 142 checkedRadio.checked = ''; 143 } 144 145 if (allOptions) { 146 allOptions.forEach(option => { 147 option.selected = false; 148 }); 149 } 150 }; 151 152 document.querySelectorAll('.visibility-toggle-link').forEach(button => { 153 button.addEventListener('click', event => { 154 event.preventDefault(); 155 const changeButton = event.target; 156 const changeButtonContainer = changeButton.closest('.field-visibility-settings-toggle'); 157 const settingsContainer = changeButtonContainer.nextElementSibling; // Hides the "Change" button. 158 159 changeButton.setAttribute('aria-expanded', true); 160 changeButtonContainer.style.display = 'none'; // Displays the settings visibility container. 161 162 settingsContainer.style.display = 'block'; 163 }); 164 }); 165 document.querySelectorAll('.field-visibility-settings-close').forEach(button => { 166 button.addEventListener('click', event => { 167 event.preventDefault(); 168 const closeButton = event.target; 169 const settingsContainer = closeButton.closest('.field-visibility-settings'); 170 const changeButtonContainer = settingsContainer.previousElementSibling; 171 const currentVisibility = settingsContainer.querySelector('input:checked').nextElementSibling.innerHTML; // Closes the visibility settings options. 172 173 settingsContainer.style.display = 'none'; // Displays the current visibility. 174 175 changeButtonContainer.querySelector('.visibility-toggle-link').setAttribute('aria-expanded', false); 176 changeButtonContainer.querySelector('.current-visibility-level').innerHTML = currentVisibility; 177 changeButtonContainer.style.display = 'block'; 178 }); 179 }); 180 },{}]},{},["wb1e"], null) -
trunk/src/bp-members/classes/class-bp-members-admin.php
r13161 r13164 711 711 */ 712 712 $js = apply_filters( 'bp_members_admin_js', $js ); 713 wp_enqueue_script( 'bp-members-js', $js, array( 'jquery'), bp_get_version(), true );713 wp_enqueue_script( 'bp-members-js', $js, array(), bp_get_version(), true ); 714 714 715 715 if ( ! bp_core_get_root_option( 'bp-disable-avatar-uploads' ) && buddypress()->avatar->show_avatars ) { -
trunk/src/bp-xprofile/classes/class-bp-xprofile-field-type-multiselectbox.php
r13108 r13164 98 98 <?php endif; ?> 99 99 100 <?php if ( ! bp_get_the_profile_field_is_required() ) : ?> 101 102 <a class="clear-value" href="javascript:clear( '<?php echo esc_js( bp_get_the_profile_field_input_name() ); ?>[]' );"> 100 <?php if ( ! bp_get_the_profile_field_is_required() ) : 101 102 $clear = 'clear'; 103 if ( is_admin() && ! wp_doing_ajax() ) { 104 $clear = 'bp.clear'; 105 } 106 107 $js_clear = sprintf( 'javascript:%1$s( \'%2$s[]\' );', $clear, esc_js( bp_get_the_profile_field_input_name() ) ); 108 ?> 109 110 <a class="clear-value" href="<?php echo $js_clear; ?>"> 103 111 <?php esc_html_e( 'Clear', 'buddypress' ); ?> 104 112 </a> -
trunk/src/bp-xprofile/classes/class-bp-xprofile-field-type-radiobutton.php
r11618 r13164 82 82 <?php bp_the_profile_field_options( array( 'user_id' => $user_id ) ); 83 83 84 if ( ! bp_get_the_profile_field_is_required() ) : ?> 85 86 <a class="clear-value" href="javascript:clear( '<?php echo esc_js( bp_get_the_profile_field_input_name() ); ?>' );"> 84 if ( ! bp_get_the_profile_field_is_required() ) : 85 86 $clear = 'clear'; 87 if ( is_admin() && ! wp_doing_ajax() ) { 88 $clear = 'bp.clear'; 89 } 90 91 $js_clear = sprintf( 'javascript:%1$s( \'%2$s\' );', $clear, esc_js( bp_get_the_profile_field_input_name() ) ); 92 ?> 93 94 <a class="clear-value" href="<?php echo $js_clear; ?>"> 87 95 <?php esc_html_e( 'Clear', 'buddypress' ); ?> 88 96 </a>
Note: See TracChangeset
for help on using the changeset viewer.