Ticket #8048: 8048.patch
| File 8048.patch, 102.9 KB (added by , 6 years ago) |
|---|
-
.gitignore
diff --git .gitignore .gitignore index 769dc445e..f26f47fbd 100644
1 1 .DS_Store 2 2 phpunit.xml 3 3 .idea 4 .cache 4 5 5 6 lib-cov 6 7 *.seed -
.jshintignore
diff --git .jshintignore .jshintignore index c7593c293..a5c26e46a 100644
1 1 // 3rd party libraries 2 2 src/bp-core/js/vendor/**/* 3 3 src/bp-messages/js/autocomplete/* 4 5 // Blocks Scripts 6 src/**/js/blocks/*.js -
Gruntfile.js
diff --git Gruntfile.js Gruntfile.js index 590b38872..dc0160aa2 100644
module.exports = function( grunt ) { 17 17 '**/*.js' 18 18 ], 19 19 20 BP_EXCLUDED_JS = [ 21 '!js/**/*.js', 22 '!**/js/blocks/*.js' 23 ], 24 20 25 BP_EXCLUDED_MISC = [ 21 26 ], 22 27 … … module.exports = function( grunt ) { 164 169 expand: true 165 170 } 166 171 }, 167 makepot: {168 target: {169 options: {170 cwd: BUILD_DIR,171 domainPath: '.',172 mainFile: 'bp-loader.php',173 potFilename: 'buddypress.pot',174 processPot: function( pot ) {175 pot.headers['report-msgid-bugs-to'] = 'https://buddypress.trac.wordpress.org';176 pot.headers['last-translator'] = 'JOHN JAMES JACOBY <jjj@buddypress.org>';177 pot.headers['language-team'] = 'ENGLISH <jjj@buddypress.org>';178 return pot;179 },180 type: 'wp-plugin'181 }182 }183 },184 172 imagemin: { 185 173 core: { 186 174 expand: true, … … module.exports = function( grunt ) { 201 189 dest: BUILD_DIR, 202 190 dot: true, 203 191 expand: true, 204 src: ['**', '!**/.{svn,git }/**'].concat( BP_EXCLUDED_MISC )192 src: ['**', '!**/.{svn,git,cache}/**', '!js/**'].concat( BP_EXCLUDED_MISC ) 205 193 }, 206 194 { 207 195 dest: BUILD_DIR, … … module.exports = function( grunt ) { 245 233 extDot: 'last', 246 234 expand: true, 247 235 ext: '.min.js', 248 src: BP_JS 236 src: BP_JS.concat( BP_EXCLUDED_JS, BP_EXCLUDED_MISC ) 249 237 } 250 238 }, 251 239 stylelint: { … … module.exports = function( grunt ) { 332 320 command: 'svn export --force https://github.com/buddypress/BP-REST.git/trunk bp-rest', 333 321 cwd: BUILD_DIR, 334 322 stdout: false 323 }, 324 makepot: { 325 command: 'wp i18n make-pot build build/buddypress.pot --headers=\'{"Project-Id-Version": "BuddyPress", "Report-Msgid-Bugs-To": "https://buddypress.trac.wordpress.org", "Last-Translator": "JOHN JAMES JACOBY <jjj@buddypress.org>", "Language-Team": "ENGLISH <jjj@buddypress.org>"}\'', 326 stdout: true 327 }, 328 blocks_build: { 329 command: 'npm run build', 330 cwd: SOURCE_DIR, 331 stdout: true 332 }, 333 blocks_minify: { 334 command: 'npm run minify', 335 cwd: SOURCE_DIR, 336 stdout: true 335 337 } 336 338 }, 337 339 jsvalidate:{ … … module.exports = function( grunt ) { 342 344 }, 343 345 build: { 344 346 files: { 345 src: [BUILD_DIR + '/**/*.js'] 347 src: [BUILD_DIR + '/**/*.js'].concat( BP_EXCLUDED_JS, BP_EXCLUDED_MISC ) 346 348 } 347 349 }, 348 350 src: { 349 351 files: { 350 src: [SOURCE_DIR + '/**/*.js'].concat( BP_EXCLUDED_ MISC )352 src: [SOURCE_DIR + '/**/*.js'].concat( BP_EXCLUDED_JS, BP_EXCLUDED_MISC ) 351 353 } 352 354 } 353 355 }, … … module.exports = function( grunt ) { 367 369 * Register tasks. 368 370 */ 369 371 grunt.registerTask( 'src', ['checkDependencies', 'jsvalidate:src', 'jshint', 'stylelint', 'sass', 'postcss', 'rtlcss'] ); 372 grunt.registerTask( 'makepot', ['exec:makepot'] ); 370 373 grunt.registerTask( 'commit', ['src', 'checktextdomain', 'imagemin', 'phplint', 'exec:phpcompat'] ); 371 374 grunt.registerTask( 'bp_rest', [ 'exec:rest_api', 'copy:bp_rest_components', 'copy:bp_rest_core', 'clean:bp_rest' ] ); 372 grunt.registerTask( 'build', ['commit', 'clean:all', 'copy:files', 'uglify ', 'jsvalidate:build', 'cssmin', 'bp_rest', 'makepot', 'exec:bpdefault', 'exec:cli'] );375 grunt.registerTask( 'build', ['commit', 'clean:all', 'copy:files', 'uglify:core', 'jsvalidate:build', 'exec:blocks_build', 'cssmin', 'bp_rest', 'makepot', 'exec:blocks_minify', 'exec:bpdefault', 'exec:cli'] ); 373 376 grunt.registerTask( 'release', ['build'] ); 374 377 375 378 // Testing tasks. -
composer.json
diff --git composer.json composer.json index df0c4dbdd..216b1d8a6 100644
31 31 "php": ">=5.3.0" 32 32 }, 33 33 "require-dev": { 34 "phpcompatibility/phpcompatibility-wp": "*",34 "phpcompatibility/phpcompatibility-wp": "*", 35 35 "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3" 36 36 } 37 37 } -
package.json
diff --git package.json package.json index 5e26d7be7..e54217bee 100644
5 5 }, 6 6 "description": "BuddyPress adds community features to WordPress. Member Profiles, Activity Streams, Direct Messaging, Notifications, and more!", 7 7 "devDependencies": { 8 "@babel/core": "~7.8.7", 9 "@wordpress/babel-preset-default": "~4.10.0", 8 10 "@wordpress/browserslist-config": "~2.1.4", 9 11 "autoprefixer": "~8.5.2", 10 12 "grunt": "~1.0.3", … … 26 28 "grunt-rtlcss": "~2.0.1", 27 29 "grunt-sass": "~2.0.0", 28 30 "grunt-stylelint": "~0.8.0", 29 "grunt-wp-i18n": "~1.0.2",30 31 "matchdep": "~1.0.1", 32 "parcel-bundler": "~1.12.4", 31 33 "postcss-scss": "~1.0.6", 32 34 "stylelint": "~7.10.1", 33 35 "stylelint-config-wordpress": "~11.0.0" … … 35 37 "engines": { 36 38 "node": ">=6.9.1" 37 39 }, 40 "scripts": { 41 "start": "parcel watch src/js/bp-*/*s/blocks/*.js --out-dir src --no-source-maps", 42 "build": "parcel build src/js/bp-*/*s/blocks/*.js --out-dir src --no-source-maps --no-minify", 43 "minify": "parcel build src/js/bp-*/*s/blocks/*.js --out-dir build --no-source-maps" 44 }, 38 45 "keywords": [ 39 46 "activity", 40 47 "community", … … 53 60 "url": "https://buddypress.svn.wordpress.org/trunk/" 54 61 }, 55 62 "version": "6.0.0-alpha", 56 "dependencies": {},57 63 "browserslist": [ 58 64 "extends @wordpress/browserslist-config" 59 65 ] -
src/bp-core/bp-core-actions.php
diff --git src/bp-core/bp-core-actions.php src/bp-core/bp-core-actions.php index fe50c8a58..89296dd79 100644
add_action( 'bp_init', 'bp_setup_globals', 4 ); 75 75 add_action( 'bp_init', 'bp_setup_canonical_stack', 5 ); 76 76 add_action( 'bp_init', 'bp_setup_nav', 6 ); 77 77 add_action( 'bp_init', 'bp_setup_title', 8 ); 78 add_action( 'bp_init', 'bp_blocks_init', 10 ); 78 79 add_action( 'bp_init', 'bp_core_load_admin_bar_css', 12 ); 79 80 add_action( 'bp_init', 'bp_add_rewrite_tags', 20 ); 80 81 add_action( 'bp_init', 'bp_add_rewrite_rules', 30 ); -
new file src/bp-core/bp-core-blocks.php
diff --git src/bp-core/bp-core-blocks.php src/bp-core/bp-core-blocks.php new file mode 100644 index 000000000..65b4bb3b8
- + 1 <?php 2 /** 3 * Core BP Blocks functions. 4 * 5 * @package BuddyPress 6 * @subpackage Core 7 * @since 6.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 /** 14 * Filters the Block Editor settings to gather BuddyPress ones into a `bp` key. 15 * 16 * @since 6.0.0 17 * 18 * @param array $editor_settings Default editor settings. 19 * @return array The editor settings including BP blocks specific ones. 20 */ 21 function bp_blocks_editor_settings( $editor_settings = array() ) { 22 /** 23 * Filter here to include your BP Blocks specific settings. 24 * 25 * @since 6.0.0 26 * 27 * @param array $bp_editor_settings BP blocks specific editor settings. 28 */ 29 $bp_editor_settings = (array) apply_filters( 'bp_blocks_editor_settings', array() ); 30 31 if ( $bp_editor_settings ) { 32 $editor_settings['bp'] = $bp_editor_settings; 33 } 34 35 return $editor_settings; 36 } 37 add_filter( 'block_editor_settings', 'bp_blocks_editor_settings' ); 38 39 /** 40 * Register a BuddyPress block type. 41 * 42 * @since 6.0.0 43 * 44 * @param array $args The registration arguments for the block type. 45 * @return BP_Block The BuddyPress block type object. 46 */ 47 function bp_register_block( $args = array() ) { 48 return new BP_Block( $args ); 49 } -
src/bp-core/bp-core-dependency.php
diff --git src/bp-core/bp-core-dependency.php src/bp-core/bp-core-dependency.php index 6ea67ed85..cb3a3f4f5 100644
function bp_rest_api_init() { 267 267 do_action( 'bp_rest_api_init' ); 268 268 } 269 269 270 /** 271 * BP Blocks Init hook. 272 * 273 * @since 6.0.0 274 */ 275 function bp_blocks_init() { 276 /** 277 * Hook here to register your BuddyPress blocks. 278 * 279 * @since 6.0.0 280 */ 281 do_action( 'bp_blocks_init' ); 282 } 283 270 284 /** 271 285 * Fire the 'bp_customize_register' action when the Customizer has loaded, 272 286 * allowing scripts and styles to be initialized. -
new file src/bp-core/classes/class-bp-block.php
diff --git src/bp-core/classes/class-bp-block.php src/bp-core/classes/class-bp-block.php new file mode 100644 index 000000000..722974c80
- + 1 <?php 2 /** 3 * BP Block class. 4 * 5 * @package bp-blocks 6 * @subpackage \inc\classes\class-bp-block 7 * 8 * @since 6.0.0 9 */ 10 11 // Exit if accessed directly. 12 if ( ! defined( 'ABSPATH' ) ) { 13 exit; 14 } 15 16 /** 17 * BP Block Class. 18 * 19 * @since 6.0.0 20 */ 21 class BP_Block { 22 /** 23 * WP Block Type object. 24 * 25 * @since 6.0.0 26 * @var WP_Block_Type|WP_Error 27 */ 28 public $block; 29 30 /** 31 * The script types registered. 32 * 33 * @since 6.0.0 34 * @var array 35 */ 36 private $registered_scripts; 37 38 /** 39 * The style types registered. 40 * 41 * @since 6.0.0 42 * @var array 43 */ 44 private $registered_styles; 45 46 /** 47 * Construct the BuddyPress Block. 48 * 49 * @since 6.0.0 50 * 51 * @param array $args The registration arguments for the BP Block. 52 */ 53 public function __construct( $args ) { 54 if ( ! did_action( 'bp_blocks_init' ) ) { 55 _doing_it_wrong( __METHOD__, esc_html__( 'BP Blocks needs to be registered hooking `bp_blocks_init`', 'buddypress' ), '6.0.0' ); 56 } 57 58 $min = bp_core_get_minified_asset_suffix(); 59 $wp_args = array_intersect_key( 60 $args, 61 array( 62 'name' => '', 63 'render_callback' => '', 64 'attributes' => '', 65 'editor_script' => '', 66 'script' => '', 67 'editor_style' => '', 68 'style' => '', 69 ) 70 ); 71 72 if ( ! isset( $wp_args['name'] ) || ! $wp_args['name'] || ! isset( $wp_args['editor_script'] ) || ! $wp_args['editor_script'] ) { 73 $this->block = new WP_Error( 'missing_parameters', __( 'The `name` or `editor_script` required keys are missing.', 'buddypress' ) ); 74 } else { 75 // Get specific BP Blocks arguments. 76 $bp_args = array_intersect_key( 77 $args, 78 array( 79 'editor_script_url' => '', 80 'editor_script_deps' => array(), 81 'script_url' => '', 82 'script_deps' => array(), 83 'editor_style_url' => '', 84 'editor_style_deps' => array(), 85 'style_url' => '', 86 'style_deps' => array(), 87 ) 88 ); 89 90 // Register the scripts. 91 $version = bp_get_version(); 92 $this->registered_scripts = array(); 93 94 foreach ( array( 'editor_script', 'script' ) as $script_handle_key ) { 95 if ( ! isset( $wp_args[ $script_handle_key ] ) || ! $wp_args[ $script_handle_key ] ) { 96 continue; 97 } 98 99 if ( ! isset( $bp_args[ $script_handle_key . '_url' ] ) || ! $bp_args[ $script_handle_key . '_url' ] ) { 100 continue; 101 } 102 103 $deps = array(); 104 if ( isset( $bp_args[ $script_handle_key . '_deps' ] ) && is_array( $bp_args[ $script_handle_key . '_deps' ] ) ) { 105 $deps = $bp_args[ $script_handle_key . '_deps' ]; 106 } 107 108 $this->registered_scripts[ $script_handle_key ] = wp_register_script( 109 $wp_args[ $script_handle_key ], 110 $bp_args[ $script_handle_key . '_url' ], 111 $deps, 112 $version, 113 true 114 ); 115 } 116 117 if ( ! isset( $this->registered_scripts['editor_script'] ) || ! $this->registered_scripts['editor_script'] ) { 118 $this->block = new WP_Error( 'script_registration_error', __( 'The required `editor_script` could not be registered.', 'buddypress' ) ); 119 } else { 120 // Register the styles. 121 $registered_styles = array(); 122 123 foreach ( array( 'editor_style', 'style' ) as $style_handle_key ) { 124 if ( ! isset( $wp_args[ $style_handle_key ] ) || ! $wp_args[ $style_handle_key ] ) { 125 continue; 126 } 127 128 if ( ! isset( $bp_args[ $style_handle_key . '_url' ] ) || ! $bp_args[ $style_handle_key . '_url' ] ) { 129 continue; 130 } 131 132 if ( $min ) { 133 $minified_css = str_replace( '.css', $min . '.css', $bp_args[ $style_handle_key . '_url' ] ); 134 $css_file_path = str_replace( content_url(), WP_CONTENT_DIR, $minified_css ); 135 136 if ( file_exists( $css_file_path ) ) { 137 $bp_args[ $style_handle_key . '_url' ] = $minified_css; 138 } 139 } 140 141 $deps = array(); 142 if ( isset( $bp_args[ $style_handle_key . '_deps' ] ) && is_array( $bp_args[ $style_handle_key . '_deps' ] ) ) { 143 $deps = $bp_args[ $style_handle_key . '_deps' ]; 144 } 145 146 $this->registered_styles[ $style_handle_key ] = wp_register_style( 147 $wp_args[ $style_handle_key ], 148 $bp_args[ $style_handle_key . '_url' ], 149 $deps, 150 $version 151 ); 152 153 wp_style_add_data( $wp_args[ $style_handle_key ], 'rtl', 'replace' ); 154 if ( $min ) { 155 wp_style_add_data( $wp_args[ $style_handle_key ], 'suffix', $min ); 156 } 157 } 158 159 $name = $wp_args['name']; 160 unset( $wp_args['name'] ); 161 162 // Set the Block Type. 163 $this->block = new WP_Block_Type( $name, $wp_args ); 164 165 // Register the Block Type. 166 register_block_type( $this->block ); 167 168 // Load Block translations if found. 169 if ( $this->block->editor_script ) { 170 /** 171 * Filter here to use a custom directory to look for the JSON translation file into. 172 * 173 * @since 6.0.0 174 * 175 * @param string $value Absolute path to the directory to look for the JSON translation file into. 176 * @param string $editor_script The editor's script handle. 177 * @param string $name The block's name. 178 */ 179 $translation_dir = apply_filters( 'bp_block_translation_dir', null, $this->block->editor_script, $name ); 180 181 /** 182 * Filter here to use a custom domain for the JSON translation file. 183 * 184 * @since 6.0.0 185 * 186 * @param string $value The custom domain for the JSON translation file. 187 * @param string $editor_script The editor's script handle. 188 * @param string $name The block's name. 189 */ 190 $domain = apply_filters( 'bp_block_translation_dir', 'buddypress', $this->block->editor_script, $name ); 191 192 // Try to load the translation. 193 $translated = wp_set_script_translations( $this->block->editor_script, $domain, $translation_dir ); 194 } 195 } 196 } 197 } 198 } -
new file src/bp-core/js/blocks/bp-autocompleter.js
diff --git src/bp-core/js/blocks/bp-autocompleter.js src/bp-core/js/blocks/bp-autocompleter.js new file mode 100644 index 000000000..89b3e9c54
- + 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 })({"kUj2":[function(require,module,exports) { 121 function _classCallCheck(instance, Constructor) { 122 if (!(instance instanceof Constructor)) { 123 throw new TypeError("Cannot call a class as a function"); 124 } 125 } 126 127 module.exports = _classCallCheck; 128 },{}],"dMjH":[function(require,module,exports) { 129 function _defineProperties(target, props) { 130 for (var i = 0; i < props.length; i++) { 131 var descriptor = props[i]; 132 descriptor.enumerable = descriptor.enumerable || false; 133 descriptor.configurable = true; 134 if ("value" in descriptor) descriptor.writable = true; 135 Object.defineProperty(target, descriptor.key, descriptor); 136 } 137 } 138 139 function _createClass(Constructor, protoProps, staticProps) { 140 if (protoProps) _defineProperties(Constructor.prototype, protoProps); 141 if (staticProps) _defineProperties(Constructor, staticProps); 142 return Constructor; 143 } 144 145 module.exports = _createClass; 146 },{}],"FlpK":[function(require,module,exports) { 147 function _typeof(obj) { 148 "@babel/helpers - typeof"; 149 150 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 151 module.exports = _typeof = function _typeof(obj) { 152 return typeof obj; 153 }; 154 } else { 155 module.exports = _typeof = function _typeof(obj) { 156 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 157 }; 158 } 159 160 return _typeof(obj); 161 } 162 163 module.exports = _typeof; 164 },{}],"oXBW":[function(require,module,exports) { 165 function _assertThisInitialized(self) { 166 if (self === void 0) { 167 throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 168 } 169 170 return self; 171 } 172 173 module.exports = _assertThisInitialized; 174 },{}],"cbGp":[function(require,module,exports) { 175 var _typeof = require("../helpers/typeof"); 176 177 var assertThisInitialized = require("./assertThisInitialized"); 178 179 function _possibleConstructorReturn(self, call) { 180 if (call && (_typeof(call) === "object" || typeof call === "function")) { 181 return call; 182 } 183 184 return assertThisInitialized(self); 185 } 186 187 module.exports = _possibleConstructorReturn; 188 },{"../helpers/typeof":"FlpK","./assertThisInitialized":"oXBW"}],"XApn":[function(require,module,exports) { 189 function _getPrototypeOf(o) { 190 module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 191 return o.__proto__ || Object.getPrototypeOf(o); 192 }; 193 return _getPrototypeOf(o); 194 } 195 196 module.exports = _getPrototypeOf; 197 },{}],"Omxx":[function(require,module,exports) { 198 function _setPrototypeOf(o, p) { 199 module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 200 o.__proto__ = p; 201 return o; 202 }; 203 204 return _setPrototypeOf(o, p); 205 } 206 207 module.exports = _setPrototypeOf; 208 },{}],"PhTw":[function(require,module,exports) { 209 var setPrototypeOf = require("./setPrototypeOf"); 210 211 function _inherits(subClass, superClass) { 212 if (typeof superClass !== "function" && superClass !== null) { 213 throw new TypeError("Super expression must either be null or a function"); 214 } 215 216 subClass.prototype = Object.create(superClass && superClass.prototype, { 217 constructor: { 218 value: subClass, 219 writable: true, 220 configurable: true 221 } 222 }); 223 if (superClass) setPrototypeOf(subClass, superClass); 224 } 225 226 module.exports = _inherits; 227 },{"./setPrototypeOf":"Omxx"}],"xHsb":[function(require,module,exports) { 228 "use strict"; 229 230 Object.defineProperty(exports, "__esModule", { 231 value: true 232 }); 233 exports.default = void 0; 234 235 var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); 236 237 var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); 238 239 var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); 240 241 var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); 242 243 var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); 244 245 var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); 246 247 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 248 249 /** 250 * WordPress dependencies. 251 */ 252 var _wp$element = wp.element, 253 Component = _wp$element.Component, 254 Fragment = _wp$element.Fragment, 255 createElement = _wp$element.createElement; 256 var Popover = wp.components.Popover; 257 var _wp = wp, 258 apiFetch = _wp.apiFetch; 259 var __ = wp.i18n.__; 260 261 var BPAutocompleter = /*#__PURE__*/function (_Component) { 262 (0, _inherits2.default)(BPAutocompleter, _Component); 263 264 function BPAutocompleter() { 265 var _this; 266 267 (0, _classCallCheck2.default)(this, BPAutocompleter); 268 _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(BPAutocompleter).apply(this, arguments)); 269 _this.state = { 270 search: '', 271 items: [], 272 error: '' 273 }; 274 _this.searchItemName = _this.searchItemName.bind((0, _assertThisInitialized2.default)(_this)); 275 _this.selectItemName = _this.selectItemName.bind((0, _assertThisInitialized2.default)(_this)); 276 return _this; 277 } 278 279 (0, _createClass2.default)(BPAutocompleter, [{ 280 key: "searchItemName", 281 value: function searchItemName(value) { 282 var _this2 = this; 283 284 var search = this.state.search; 285 var _this$props = this.props, 286 component = _this$props.component, 287 objectStatus = _this$props.objectStatus; 288 this.setState({ 289 search: value 290 }); 291 292 if (value.length < search.length) { 293 this.setState({ 294 items: [] 295 }); 296 } 297 298 var path = '/buddypress/v1/' + component; 299 300 if (value) { 301 path += '?search=' + encodeURIComponent(value); 302 } 303 304 if (objectStatus) { 305 path += '&status=' + objectStatus; 306 } 307 308 apiFetch({ 309 path: path 310 }).then(function (items) { 311 _this2.setState({ 312 items: items 313 }); 314 }, function (error) { 315 _this2.setState({ 316 error: error.message 317 }); 318 }); 319 } 320 }, { 321 key: "selectItemName", 322 value: function selectItemName(event, itemID) { 323 var onSelectItem = this.props.onSelectItem; 324 event.preventDefault(); 325 this.setState({ 326 search: '', 327 items: [], 328 error: '' 329 }); 330 return onSelectItem({ 331 itemID: itemID 332 }); 333 } 334 }, { 335 key: "render", 336 value: function render() { 337 var _this3 = this; 338 339 var _this$state = this.state, 340 search = _this$state.search, 341 items = _this$state.items; 342 var _this$props2 = this.props, 343 ariaLabel = _this$props2.ariaLabel, 344 placeholder = _this$props2.placeholder, 345 useAvatar = _this$props2.useAvatar; 346 var itemsList; 347 348 if (!ariaLabel) { 349 ariaLabel = __('Item\'s name', 'buddypress'); 350 } 351 352 if (!placeholder) { 353 placeholder = __('Enter Item\'s name here…', 'buddypress'); 354 } 355 356 if (items.length) { 357 itemsList = items.map(function (item) { 358 return createElement("button", { 359 type: "button", 360 key: 'editor-autocompleters__item-item-' + item.id, 361 role: "option", 362 "aria-selected": "true", 363 className: "components-button components-autocomplete__result editor-autocompleters__user", 364 onClick: function onClick(event) { 365 return _this3.selectItemName(event, item.id); 366 } 367 }, useAvatar && createElement("img", { 368 key: "avatar", 369 className: "editor-autocompleters__user-avatar", 370 alt: "", 371 src: item.avatar_urls.thumb 372 }), createElement("span", { 373 key: "name", 374 className: "editor-autocompleters__user-name" 375 }, item.name), item.mention_name && createElement("span", { 376 key: "slug", 377 className: "editor-autocompleters__user-slug" 378 }, item.mention_name)); 379 }); 380 } 381 382 return createElement(Fragment, null, createElement("input", { 383 type: "text", 384 value: search, 385 className: "components-placeholder__input", 386 "aria-label": ariaLabel, 387 placeholder: placeholder, 388 onChange: function onChange(event) { 389 return _this3.searchItemName(event.target.value); 390 } 391 }), 0 !== items.length && createElement(Popover, { 392 className: "components-autocomplete__popover", 393 focusOnMount: false, 394 position: "bottom left" 395 }, createElement("div", { 396 className: "components-autocomplete__results" 397 }, itemsList))); 398 } 399 }]); 400 return BPAutocompleter; 401 }(Component); 402 403 var _default = BPAutocompleter; 404 exports.default = _default; 405 },{"@babel/runtime/helpers/classCallCheck":"kUj2","@babel/runtime/helpers/createClass":"dMjH","@babel/runtime/helpers/possibleConstructorReturn":"cbGp","@babel/runtime/helpers/getPrototypeOf":"XApn","@babel/runtime/helpers/assertThisInitialized":"oXBW","@babel/runtime/helpers/inherits":"PhTw"}]},{},["xHsb"], null) 406 No newline at end of file -
new file src/bp-groups/bp-groups-blocks.php
diff --git src/bp-groups/bp-groups-blocks.php src/bp-groups/bp-groups-blocks.php new file mode 100644 index 000000000..4f40e384e
- + 1 <?php 2 /** 3 * BP Groups Blocks Functions. 4 * 5 * @package bp-blocks 6 * @subpackage \inc\bp-groups\bp-groups-blocks 7 */ 8 9 // Exit if accessed directly. 10 if ( ! defined( 'ABSPATH' ) ) { 11 exit; 12 } 13 14 /** 15 * Register Groups Blocks. 16 * 17 * @since 6.0.0 18 */ 19 function bp_groups_register_blocks() { 20 bp_register_block( 21 array( 22 'name' => 'bp/group', 23 'editor_script' => 'bp-group-block', 24 'editor_script_url' => plugins_url( 'js/blocks/group.js', __FILE__ ), 25 'editor_script_deps' => array( 26 'wp-blocks', 27 'wp-element', 28 'wp-components', 29 'wp-i18n', 30 'wp-api-fetch', 31 'wp-editor', 32 'wp-compose', 33 'wp-data', 34 'wp-block-editor', 35 ), 36 'style' => 'bp-group-block', 37 'style_url' => plugins_url( 'css/blocks/group.css', __FILE__ ), 38 'render_callback' => 'bp_groups_render_group_block', 39 'attributes' => array( 40 'itemID' => array( 41 'type' => 'integer', 42 'default' => 0, 43 ), 44 'avatarSize' => array( 45 'type' => 'string', 46 'default' => 'full', 47 ), 48 'displayDescription' => array( 49 'type' => 'boolean', 50 'default' => true, 51 ), 52 'displayActionButton' => array( 53 'type' => 'boolean', 54 'default' => true, 55 ), 56 'displayCoverImage' => array( 57 'type' => 'boolean', 58 'default' => true, 59 ), 60 ), 61 ) 62 ); 63 } 64 add_action( 'bp_blocks_init', 'bp_groups_register_blocks', 10 ); 65 66 /** 67 * Add BP Groups blocks specific settings to the BP Blocks Editor ones. 68 * 69 * @since 6.0.0 70 * 71 * @param array $bp_editor_settings BP blocks editor settings. 72 * @return array BP Groups blocks editor settings. 73 */ 74 function bp_groups_editor_settings( $bp_editor_settings = array() ) { 75 $bp = buddypress(); 76 77 return array_merge( 78 $bp_editor_settings, 79 array( 80 'groups' => array( 81 'isAvatarEnabled' => $bp->avatar && $bp->avatar->show_avatars && ! bp_disable_group_avatar_uploads(), 82 'isCoverImageEnabled' => bp_is_active( 'groups', 'cover_image' ), 83 ), 84 ) 85 ); 86 } 87 add_filter( 'bp_blocks_editor_settings', 'bp_groups_editor_settings' ); 88 89 /** 90 * Callback function to render the BP Group Block. 91 * 92 * @since 6.0.0 93 * 94 * @param array $attributes The block attributes. 95 * @return string HTML output. 96 */ 97 function bp_groups_render_group_block( $attributes = array() ) { 98 $bp = buddypress(); 99 100 $block_args = wp_parse_args( 101 $attributes, 102 array( 103 'itemID' => 0, 104 'avatarSize' => 'full', 105 'displayDescription' => true, 106 'displayActionButton' => true, 107 'displayCoverImage' => true, 108 ) 109 ); 110 111 if ( ! $block_args['itemID'] ) { 112 return; 113 } 114 115 // Set the group ID and container classes. 116 $group_id = (int) $block_args['itemID']; 117 $container_classes = array( 'bp-block-group' ); 118 119 // Group object. 120 $group = groups_get_group( $group_id ); 121 122 if ( ! $group->id ) { 123 return; 124 } 125 126 // Avatar variables. 127 $avatar = ''; 128 $avatar_container = ''; 129 130 // Cover image variable. 131 $cover_image = ''; 132 $cover_style = ''; 133 $cover_container = ''; 134 135 // Group name/link/description variables. 136 $group_name = bp_get_group_name( $group ); 137 $group_link = bp_get_group_permalink( $group ); 138 $group_description = ''; 139 $group_content = ''; 140 141 // Group action button. 142 $action_button = ''; 143 $display_action_button = (bool) $block_args['displayActionButton']; 144 145 if ( $bp->avatar && $bp->avatar->show_avatars && ! bp_disable_group_avatar_uploads() && in_array( $block_args['avatarSize'], array( 'thumb', 'full' ), true ) ) { 146 $avatar = bp_core_fetch_avatar( 147 array( 148 'item_id' => $group->id, 149 'object' => 'group', 150 'type' => $block_args['avatarSize'], 151 'html' => false, 152 ) 153 ); 154 155 $container_classes[] = 'avatar-' . $block_args['avatarSize']; 156 } else { 157 $container_classes[] = 'avatar-none'; 158 } 159 160 if ( $avatar ) { 161 $avatar_container = sprintf( 162 '<div class="item-header-avatar"> 163 <a href="%1$s"> 164 <img src="%2$s" alt="%3$s" class="avatar"> 165 </a> 166 </div>', 167 esc_url( $group_link ), 168 esc_url( $avatar ), 169 // Translators: %s is the group's name. 170 sprintf( esc_html__( 'Group Profile photo of %s', 'buddypress' ), $group_name ) 171 ); 172 } 173 174 $display_cover_image = (bool) $block_args['displayCoverImage']; 175 if ( bp_is_active( 'groups', 'cover_image' ) && $display_cover_image ) { 176 $cover_image = bp_attachments_get_attachment( 177 'url', 178 array( 179 'item_id' => $group->id, 180 'object_dir' => 'groups', 181 ) 182 ); 183 184 if ( $cover_image ) { 185 $cover_style = sprintf( 186 ' style="background-image: url( %s );"', 187 esc_url( $cover_image ) 188 ); 189 } 190 191 $cover_container = sprintf( 192 '<div class="bp-group-cover-image"%s></div>', 193 $cover_style 194 ); 195 196 $container_classes[] = 'has-cover'; 197 } 198 199 $display_description = (bool) $block_args['displayDescription']; 200 if ( $display_description ) { 201 $group_description = bp_get_group_description( $group ); 202 $group_content = sprintf( 203 '<div class="group-description-content">%s</div>', 204 $group_description 205 ); 206 207 $container_classes[] = 'has-description'; 208 } 209 210 if ( $display_action_button ) { 211 $action_button = sprintf( 212 '<div class="bp-profile-button"> 213 <a href="%1$s" class="button large primary button-primary" role="button">%2$s</a> 214 </div>', 215 esc_url( $group_link ), 216 esc_html__( 'Visit Group', 'buddypress' ) 217 ); 218 } 219 220 $output = sprintf( 221 '<div class="%1$s"> 222 %2$s 223 <div class="group-content"> 224 %3$s 225 <div class="group-description"> 226 <strong><a href="%4$s">%5$s</a></strong> 227 %6$s 228 %7$s 229 </div> 230 </div> 231 </div>', 232 implode( ' ', array_map( 'sanitize_html_class', $container_classes ) ), 233 $cover_container, 234 $avatar_container, 235 esc_url( $group_link ), 236 esc_html( $group_name ), 237 $group_content, 238 $action_button 239 ); 240 241 // Compact all interesting parameters. 242 $params = array_merge( $block_args, compact( 'group_name', 'group_link', 'group_description', 'avatar', 'cover_image' ) ); 243 244 /** 245 * Filter here to edit the output of the single group block. 246 * 247 * @since 6.0.0 248 * 249 * @param string $output The HTML output of the block. 250 * @param BP_Groups_Group $group The group object. 251 * @param array $params The block extended parameters. 252 */ 253 return apply_filters( 'bp_groups_render_group_block_output', $output, $group, $params ); 254 } -
src/bp-groups/classes/class-bp-groups-component.php
diff --git src/bp-groups/classes/class-bp-groups-component.php src/bp-groups/classes/class-bp-groups-component.php index b53835ea0..644e1a612 100644
class BP_Groups_Component extends BP_Component { 130 130 'functions', 131 131 'notifications', 132 132 'cssjs', 133 'blocks', 133 134 ); 134 135 135 136 // Conditional includes. -
new file src/bp-groups/css/blocks/group-rtl.css
diff --git src/bp-groups/css/blocks/group-rtl.css src/bp-groups/css/blocks/group-rtl.css new file mode 100644 index 000000000..dce932ac8
- + 1 /* CSS for the bp/group block */ 2 .bp-block-group { 3 position: relative; 4 } 5 6 .bp-block-group .group-content { 7 display: flex; 8 } 9 10 .bp-block-group.has-cover .group-content, 11 .bp-block-group.has-cover .item-header-avatar, 12 .bp-block-group.has-cover .group-description { 13 z-index: 2; 14 } 15 16 .bp-block-group .group-description { 17 width: 100%; 18 } 19 20 .bp-block-group.has-cover .group-description { 21 padding-top: 75px; 22 } 23 24 .bp-block-group.avatar-full .group-description { 25 padding-right: 35px; 26 } 27 28 .bp-block-group.has-cover .bp-group-cover-image { 29 background-color: #c5c5c5; 30 background-position: center top; 31 background-repeat: no-repeat; 32 background-size: cover; 33 border: 0; 34 display: block; 35 right: 0; 36 margin: 0; 37 padding: 0; 38 position: absolute; 39 top: 0; 40 width: 100%; 41 z-index: 1; 42 height: 150px; 43 } 44 45 .bp-block-group img.avatar { 46 width: auto; 47 height: auto; 48 } 49 50 .bp-block-group.avatar-none .item-header-avatar { 51 display: none; 52 } 53 54 .bp-block-group.avatar-none.has-cover { 55 min-height: 200px; 56 } 57 58 .bp-block-group.avatar-full { 59 min-height: 150px; 60 } 61 62 .bp-block-group.avatar-full.has-cover { 63 min-height: 300px; 64 } 65 66 .bp-block-group.avatar-full .item-header-avatar { 67 width: 180px; 68 } 69 70 .bp-block-group.has-cover.avatar-full .item-header-avatar { 71 width: 200px; 72 } 73 74 .bp-block-group.has-cover.avatar-full img.avatar { 75 border: solid 2px #fff; 76 background: rgba(255, 255, 255, 0.8); 77 margin-right: 20px; 78 } 79 80 .bp-block-group.has-cover .group-content { 81 padding-top: 75px; 82 } 83 84 .bp-block-group.avatar-thumb .item-header-avatar img.avatar { 85 margin-top: 15px; 86 } 87 88 .bp-block-group.avatar-thumb:not(.has-description) .group-content { 89 min-height: 50px; 90 align-items: center; 91 } 92 93 .bp-block-group .group-description-content { 94 width: 100%; 95 margin-bottom: 18px; 96 } 97 98 .bp-block-group.avatar-thumb .item-header-avatar { 99 width: 70px; 100 } 101 102 .bp-block-group.avatar-thumb.has-cover .item-header-avatar { 103 padding-top: 75px; 104 } 105 106 .bp-block-group .bp-profile-button { 107 width: 100%; 108 overflow: hidden; 109 } 110 111 .bp-block-group .bp-profile-button a.button { 112 margin: 18px 0 0; 113 } 114 115 .bp-block-group.has-description .bp-profile-button a.button { 116 display: block; 117 float: left; 118 } -
new file src/bp-groups/css/blocks/group.css
diff --git src/bp-groups/css/blocks/group.css src/bp-groups/css/blocks/group.css new file mode 100644 index 000000000..502b70b69
- + 1 /* CSS for the bp/group block */ 2 .bp-block-group { 3 position: relative; 4 } 5 6 .bp-block-group .group-content { 7 display: flex; 8 } 9 10 .bp-block-group.has-cover .group-content, 11 .bp-block-group.has-cover .item-header-avatar, 12 .bp-block-group.has-cover .group-description { 13 z-index: 2; 14 } 15 16 .bp-block-group .group-description { 17 width: 100%; 18 } 19 20 .bp-block-group.has-cover .group-description { 21 padding-top: 75px; 22 } 23 24 .bp-block-group.avatar-full .group-description { 25 padding-left: 35px; 26 } 27 28 .bp-block-group.has-cover .bp-group-cover-image { 29 background-color: #c5c5c5; 30 background-position: center top; 31 background-repeat: no-repeat; 32 background-size: cover; 33 border: 0; 34 display: block; 35 left: 0; 36 margin: 0; 37 padding: 0; 38 position: absolute; 39 top: 0; 40 width: 100%; 41 z-index: 1; 42 height: 150px; 43 } 44 45 .bp-block-group img.avatar { 46 width: auto; 47 height: auto; 48 } 49 50 .bp-block-group.avatar-none .item-header-avatar { 51 display: none; 52 } 53 54 .bp-block-group.avatar-none.has-cover { 55 min-height: 200px; 56 } 57 58 .bp-block-group.avatar-full { 59 min-height: 150px; 60 } 61 62 .bp-block-group.avatar-full.has-cover { 63 min-height: 300px; 64 } 65 66 .bp-block-group.avatar-full .item-header-avatar { 67 width: 180px; 68 } 69 70 .bp-block-group.has-cover.avatar-full .item-header-avatar { 71 width: 200px; 72 } 73 74 .bp-block-group.has-cover.avatar-full img.avatar { 75 border: solid 2px #fff; 76 background: rgba(255, 255, 255, 0.8); 77 margin-left: 20px; 78 } 79 80 .bp-block-group.has-cover .group-content { 81 padding-top: 75px; 82 } 83 84 .bp-block-group.avatar-thumb .item-header-avatar img.avatar { 85 margin-top: 15px; 86 } 87 88 .bp-block-group.avatar-thumb:not(.has-description) .group-content { 89 min-height: 50px; 90 align-items: center; 91 } 92 93 .bp-block-group .group-description-content { 94 width: 100%; 95 margin-bottom: 18px; 96 } 97 98 .bp-block-group.avatar-thumb .item-header-avatar { 99 width: 70px; 100 } 101 102 .bp-block-group.avatar-thumb.has-cover .item-header-avatar { 103 padding-top: 75px; 104 } 105 106 .bp-block-group .bp-profile-button { 107 width: 100%; 108 overflow: hidden; 109 } 110 111 .bp-block-group .bp-profile-button a.button { 112 margin: 18px 0 0; 113 } 114 115 .bp-block-group.has-description .bp-profile-button a.button { 116 display: block; 117 float: right; 118 } -
new file src/bp-groups/js/blocks/group.js
diff --git src/bp-groups/js/blocks/group.js src/bp-groups/js/blocks/group.js new file mode 100644 index 000000000..6a3718555
- + 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 })({"kUj2":[function(require,module,exports) { 121 function _classCallCheck(instance, Constructor) { 122 if (!(instance instanceof Constructor)) { 123 throw new TypeError("Cannot call a class as a function"); 124 } 125 } 126 127 module.exports = _classCallCheck; 128 },{}],"dMjH":[function(require,module,exports) { 129 function _defineProperties(target, props) { 130 for (var i = 0; i < props.length; i++) { 131 var descriptor = props[i]; 132 descriptor.enumerable = descriptor.enumerable || false; 133 descriptor.configurable = true; 134 if ("value" in descriptor) descriptor.writable = true; 135 Object.defineProperty(target, descriptor.key, descriptor); 136 } 137 } 138 139 function _createClass(Constructor, protoProps, staticProps) { 140 if (protoProps) _defineProperties(Constructor.prototype, protoProps); 141 if (staticProps) _defineProperties(Constructor, staticProps); 142 return Constructor; 143 } 144 145 module.exports = _createClass; 146 },{}],"FlpK":[function(require,module,exports) { 147 function _typeof(obj) { 148 "@babel/helpers - typeof"; 149 150 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 151 module.exports = _typeof = function _typeof(obj) { 152 return typeof obj; 153 }; 154 } else { 155 module.exports = _typeof = function _typeof(obj) { 156 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 157 }; 158 } 159 160 return _typeof(obj); 161 } 162 163 module.exports = _typeof; 164 },{}],"oXBW":[function(require,module,exports) { 165 function _assertThisInitialized(self) { 166 if (self === void 0) { 167 throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 168 } 169 170 return self; 171 } 172 173 module.exports = _assertThisInitialized; 174 },{}],"cbGp":[function(require,module,exports) { 175 var _typeof = require("../helpers/typeof"); 176 177 var assertThisInitialized = require("./assertThisInitialized"); 178 179 function _possibleConstructorReturn(self, call) { 180 if (call && (_typeof(call) === "object" || typeof call === "function")) { 181 return call; 182 } 183 184 return assertThisInitialized(self); 185 } 186 187 module.exports = _possibleConstructorReturn; 188 },{"../helpers/typeof":"FlpK","./assertThisInitialized":"oXBW"}],"XApn":[function(require,module,exports) { 189 function _getPrototypeOf(o) { 190 module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 191 return o.__proto__ || Object.getPrototypeOf(o); 192 }; 193 return _getPrototypeOf(o); 194 } 195 196 module.exports = _getPrototypeOf; 197 },{}],"Omxx":[function(require,module,exports) { 198 function _setPrototypeOf(o, p) { 199 module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 200 o.__proto__ = p; 201 return o; 202 }; 203 204 return _setPrototypeOf(o, p); 205 } 206 207 module.exports = _setPrototypeOf; 208 },{}],"PhTw":[function(require,module,exports) { 209 var setPrototypeOf = require("./setPrototypeOf"); 210 211 function _inherits(subClass, superClass) { 212 if (typeof superClass !== "function" && superClass !== null) { 213 throw new TypeError("Super expression must either be null or a function"); 214 } 215 216 subClass.prototype = Object.create(superClass && superClass.prototype, { 217 constructor: { 218 value: subClass, 219 writable: true, 220 configurable: true 221 } 222 }); 223 if (superClass) setPrototypeOf(subClass, superClass); 224 } 225 226 module.exports = _inherits; 227 },{"./setPrototypeOf":"Omxx"}],"xHsb":[function(require,module,exports) { 228 "use strict"; 229 230 Object.defineProperty(exports, "__esModule", { 231 value: true 232 }); 233 exports.default = void 0; 234 235 var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); 236 237 var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); 238 239 var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); 240 241 var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); 242 243 var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); 244 245 var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); 246 247 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 248 249 /** 250 * WordPress dependencies. 251 */ 252 var _wp$element = wp.element, 253 Component = _wp$element.Component, 254 Fragment = _wp$element.Fragment, 255 createElement = _wp$element.createElement; 256 var Popover = wp.components.Popover; 257 var _wp = wp, 258 apiFetch = _wp.apiFetch; 259 var __ = wp.i18n.__; 260 261 var BPAutocompleter = /*#__PURE__*/function (_Component) { 262 (0, _inherits2.default)(BPAutocompleter, _Component); 263 264 function BPAutocompleter() { 265 var _this; 266 267 (0, _classCallCheck2.default)(this, BPAutocompleter); 268 _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(BPAutocompleter).apply(this, arguments)); 269 _this.state = { 270 search: '', 271 items: [], 272 error: '' 273 }; 274 _this.searchItemName = _this.searchItemName.bind((0, _assertThisInitialized2.default)(_this)); 275 _this.selectItemName = _this.selectItemName.bind((0, _assertThisInitialized2.default)(_this)); 276 return _this; 277 } 278 279 (0, _createClass2.default)(BPAutocompleter, [{ 280 key: "searchItemName", 281 value: function searchItemName(value) { 282 var _this2 = this; 283 284 var search = this.state.search; 285 var _this$props = this.props, 286 component = _this$props.component, 287 objectStatus = _this$props.objectStatus; 288 this.setState({ 289 search: value 290 }); 291 292 if (value.length < search.length) { 293 this.setState({ 294 items: [] 295 }); 296 } 297 298 var path = '/buddypress/v1/' + component; 299 300 if (value) { 301 path += '?search=' + encodeURIComponent(value); 302 } 303 304 if (objectStatus) { 305 path += '&status=' + objectStatus; 306 } 307 308 apiFetch({ 309 path: path 310 }).then(function (items) { 311 _this2.setState({ 312 items: items 313 }); 314 }, function (error) { 315 _this2.setState({ 316 error: error.message 317 }); 318 }); 319 } 320 }, { 321 key: "selectItemName", 322 value: function selectItemName(event, itemID) { 323 var onSelectItem = this.props.onSelectItem; 324 event.preventDefault(); 325 this.setState({ 326 search: '', 327 items: [], 328 error: '' 329 }); 330 return onSelectItem({ 331 itemID: itemID 332 }); 333 } 334 }, { 335 key: "render", 336 value: function render() { 337 var _this3 = this; 338 339 var _this$state = this.state, 340 search = _this$state.search, 341 items = _this$state.items; 342 var _this$props2 = this.props, 343 ariaLabel = _this$props2.ariaLabel, 344 placeholder = _this$props2.placeholder, 345 useAvatar = _this$props2.useAvatar; 346 var itemsList; 347 348 if (!ariaLabel) { 349 ariaLabel = __('Item\'s name', 'buddypress'); 350 } 351 352 if (!placeholder) { 353 placeholder = __('Enter Item\'s name here…', 'buddypress'); 354 } 355 356 if (items.length) { 357 itemsList = items.map(function (item) { 358 return createElement("button", { 359 type: "button", 360 key: 'editor-autocompleters__item-item-' + item.id, 361 role: "option", 362 "aria-selected": "true", 363 className: "components-button components-autocomplete__result editor-autocompleters__user", 364 onClick: function onClick(event) { 365 return _this3.selectItemName(event, item.id); 366 } 367 }, useAvatar && createElement("img", { 368 key: "avatar", 369 className: "editor-autocompleters__user-avatar", 370 alt: "", 371 src: item.avatar_urls.thumb 372 }), createElement("span", { 373 key: "name", 374 className: "editor-autocompleters__user-name" 375 }, item.name), item.mention_name && createElement("span", { 376 key: "slug", 377 className: "editor-autocompleters__user-slug" 378 }, item.mention_name)); 379 }); 380 } 381 382 return createElement(Fragment, null, createElement("input", { 383 type: "text", 384 value: search, 385 className: "components-placeholder__input", 386 "aria-label": ariaLabel, 387 placeholder: placeholder, 388 onChange: function onChange(event) { 389 return _this3.searchItemName(event.target.value); 390 } 391 }), 0 !== items.length && createElement(Popover, { 392 className: "components-autocomplete__popover", 393 focusOnMount: false, 394 position: "bottom left" 395 }, createElement("div", { 396 className: "components-autocomplete__results" 397 }, itemsList))); 398 } 399 }]); 400 return BPAutocompleter; 401 }(Component); 402 403 var _default = BPAutocompleter; 404 exports.default = _default; 405 },{"@babel/runtime/helpers/classCallCheck":"kUj2","@babel/runtime/helpers/createClass":"dMjH","@babel/runtime/helpers/possibleConstructorReturn":"cbGp","@babel/runtime/helpers/getPrototypeOf":"XApn","@babel/runtime/helpers/assertThisInitialized":"oXBW","@babel/runtime/helpers/inherits":"PhTw"}],"pvse":[function(require,module,exports) { 406 "use strict"; 407 408 var _bpAutocompleter = _interopRequireDefault(require("../../../bp-core/js/blocks/bp-autocompleter")); 409 410 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 411 412 /** 413 * WordPress dependencies. 414 */ 415 var registerBlockType = wp.blocks.registerBlockType; 416 var _wp$element = wp.element, 417 createElement = _wp$element.createElement, 418 Fragment = _wp$element.Fragment; 419 var _wp$components = wp.components, 420 Placeholder = _wp$components.Placeholder, 421 Disabled = _wp$components.Disabled, 422 PanelBody = _wp$components.PanelBody, 423 SelectControl = _wp$components.SelectControl, 424 ToggleControl = _wp$components.ToggleControl, 425 Toolbar = _wp$components.Toolbar, 426 ToolbarButton = _wp$components.ToolbarButton; 427 var _wp$blockEditor = wp.blockEditor, 428 InspectorControls = _wp$blockEditor.InspectorControls, 429 BlockControls = _wp$blockEditor.BlockControls; 430 var withSelect = wp.data.withSelect; 431 var compose = wp.compose.compose; 432 var ServerSideRender = wp.editor.ServerSideRender; 433 var __ = wp.i18n.__; 434 /** 435 * Internal dependencies. 436 */ 437 438 var AVATAR_SIZES = [{ 439 label: __('None', 'buddypress'), 440 value: 'none' 441 }, { 442 label: __('Thumb', 'buddypress'), 443 value: 'thumb' 444 }, { 445 label: __('Full', 'buddypress'), 446 value: 'full' 447 }]; 448 449 var editGroup = function editGroup(_ref) { 450 var attributes = _ref.attributes, 451 setAttributes = _ref.setAttributes, 452 bpSettings = _ref.bpSettings; 453 var isAvatarEnabled = bpSettings.isAvatarEnabled, 454 isCoverImageEnabled = bpSettings.isCoverImageEnabled; 455 var avatarSize = attributes.avatarSize, 456 displayDescription = attributes.displayDescription, 457 displayActionButton = attributes.displayActionButton, 458 displayCoverImage = attributes.displayCoverImage; 459 460 if (!attributes.itemID) { 461 return createElement(Placeholder, { 462 icon: "buddicons-groups", 463 label: __('BuddyPress Group', 'buddypress'), 464 instructions: __('Start typing the name of the group you want to feature into this post.', 'buddypress') 465 }, createElement(_bpAutocompleter.default, { 466 component: "groups", 467 objectStatus: "public", 468 ariaLabel: __('Group\'s name', 'buddypress'), 469 placeholder: __('Enter Group\'s name here…', 'buddypress'), 470 onSelectItem: setAttributes, 471 useAvatar: isAvatarEnabled 472 })); 473 } 474 475 return createElement(Fragment, null, createElement(BlockControls, null, createElement(Toolbar, null, createElement(ToolbarButton, { 476 icon: "edit", 477 title: __('Select another group', 'buddypress'), 478 onClick: function onClick() { 479 setAttributes({ 480 itemID: 0 481 }); 482 } 483 }))), createElement(InspectorControls, null, createElement(PanelBody, { 484 title: __('Group\'s home button settings', 'buddypress'), 485 initialOpen: true 486 }, createElement(ToggleControl, { 487 label: __('Display Group\'s home button', 'buddypress'), 488 checked: !!displayActionButton, 489 onChange: function onChange() { 490 setAttributes({ 491 displayActionButton: !displayActionButton 492 }); 493 }, 494 help: displayActionButton ? __('Include a link to the group\'s home page under their name.', 'buddypress') : __('Toggle to display a link to the group\'s home page under their name.', 'buddypress') 495 })), createElement(PanelBody, { 496 title: __('Description settings', 'buddypress'), 497 initialOpen: false 498 }, createElement(ToggleControl, { 499 label: __('Display group\'s description', 'buddypress'), 500 checked: !!displayDescription, 501 onChange: function onChange() { 502 setAttributes({ 503 displayDescription: !displayDescription 504 }); 505 }, 506 help: displayDescription ? __('Include the group\'s description under their name.', 'buddypress') : __('Toggle to display the group\'s description under their name.', 'buddypress') 507 })), isAvatarEnabled && createElement(PanelBody, { 508 title: __('Avatar settings', 'buddypress'), 509 initialOpen: false 510 }, createElement(SelectControl, { 511 label: __('Size', 'buddypress'), 512 value: avatarSize, 513 options: AVATAR_SIZES, 514 onChange: function onChange(option) { 515 setAttributes({ 516 avatarSize: option 517 }); 518 } 519 })), isCoverImageEnabled && createElement(PanelBody, { 520 title: __('Cover image settings', 'buddypress'), 521 initialOpen: false 522 }, createElement(ToggleControl, { 523 label: __('Display Cover Image', 'buddypress'), 524 checked: !!displayCoverImage, 525 onChange: function onChange() { 526 setAttributes({ 527 displayCoverImage: !displayCoverImage 528 }); 529 }, 530 help: displayCoverImage ? __('Include the group\'s cover image over their name.', 'buddypress') : __('Toggle to display the group\'s cover image over their name.', 'buddypress') 531 }))), createElement(Disabled, null, createElement(ServerSideRender, { 532 block: "bp/group", 533 attributes: attributes 534 }))); 535 }; 536 537 var editGroupBlock = compose([withSelect(function (select) { 538 var editorSettings = select('core/editor').getEditorSettings(); 539 return { 540 bpSettings: editorSettings.bp.groups || {} 541 }; 542 })])(editGroup); 543 registerBlockType('bp/group', { 544 title: __('Group', 'buddypress'), 545 description: __('BuddyPress Group.', 'buddypress'), 546 icon: 'buddicons-groups', 547 category: 'buddypress', 548 attributes: { 549 itemID: { 550 type: 'integer', 551 default: 0 552 }, 553 avatarSize: { 554 type: 'string', 555 default: 'full' 556 }, 557 displayDescription: { 558 type: 'boolean', 559 default: true 560 }, 561 displayActionButton: { 562 type: 'boolean', 563 default: true 564 }, 565 displayCoverImage: { 566 type: 'boolean', 567 default: true 568 } 569 }, 570 edit: editGroupBlock 571 }); 572 },{"../../../bp-core/js/blocks/bp-autocompleter":"xHsb"}]},{},["pvse"], null) 573 No newline at end of file -
new file src/bp-members/bp-members-blocks.php
diff --git src/bp-members/bp-members-blocks.php src/bp-members/bp-members-blocks.php new file mode 100644 index 000000000..1c2d2fb27
- + 1 <?php 2 /** 3 * BP Members Blocks Functions. 4 * 5 * @package bp-blocks 6 * @subpackage \inc\bp-members\bp-members-blocks 7 */ 8 9 // Exit if accessed directly. 10 if ( ! defined( 'ABSPATH' ) ) { 11 exit; 12 } 13 14 /** 15 * Register Members Blocks. 16 * 17 * @since 6.0.0 18 */ 19 function bp_members_register_blocks() { 20 bp_register_block( 21 array( 22 'name' => 'bp/member', 23 'editor_script' => 'bp-member-block', 24 'editor_script_url' => plugins_url( 'js/blocks/member.js', __FILE__ ), 25 'editor_script_deps' => array( 26 'wp-blocks', 27 'wp-element', 28 'wp-components', 29 'wp-i18n', 30 'wp-api-fetch', 31 'wp-editor', 32 'wp-compose', 33 'wp-data', 34 'wp-block-editor', 35 ), 36 'style' => 'bp-member-block', 37 'style_url' => plugins_url( 'css/blocks/member.css', __FILE__ ), 38 'render_callback' => 'bp_members_render_member_block', 39 'attributes' => array( 40 'itemID' => array( 41 'type' => 'integer', 42 'default' => 0, 43 ), 44 'avatarSize' => array( 45 'type' => 'string', 46 'default' => 'full', 47 ), 48 'displayMentionSlug' => array( 49 'type' => 'boolean', 50 'default' => true, 51 ), 52 'displayActionButton' => array( 53 'type' => 'boolean', 54 'default' => true, 55 ), 56 'displayCoverImage' => array( 57 'type' => 'boolean', 58 'default' => true, 59 ), 60 ), 61 ) 62 ); 63 } 64 add_action( 'bp_blocks_init', 'bp_members_register_blocks', 10 ); 65 66 /** 67 * Add BP Members blocks specific settings to the BP Blocks Editor ones. 68 * 69 * @since 6.0.0 70 * 71 * @param array $bp_editor_settings BP blocks editor settings. 72 * @return array BP Members blocks editor settings. 73 */ 74 function bp_members_editor_settings( $bp_editor_settings = array() ) { 75 $bp = buddypress(); 76 77 return array_merge( 78 $bp_editor_settings, 79 array( 80 'members' => array( 81 'isMentionEnabled' => bp_is_active( 'activity' ) && bp_activity_do_mentions(), 82 'isAvatarEnabled' => $bp->avatar && $bp->avatar->show_avatars, 83 'isCoverImageEnabled' => bp_is_active( 'members', 'cover_image' ), 84 ), 85 ) 86 ); 87 } 88 add_filter( 'bp_blocks_editor_settings', 'bp_members_editor_settings' ); 89 90 /** 91 * Callback function to render the BP Member Block. 92 * 93 * @since 6.0.0 94 * 95 * @param array $attributes The block attributes. 96 * @return string HTML output. 97 */ 98 function bp_members_render_member_block( $attributes = array() ) { 99 $bp = buddypress(); 100 101 $block_args = wp_parse_args( 102 $attributes, 103 array( 104 'itemID' => 0, 105 'avatarSize' => 'full', 106 'displayMentionSlug' => true, 107 'displayActionButton' => true, 108 'displayCoverImage' => true, 109 ) 110 ); 111 112 if ( ! $block_args['itemID'] ) { 113 return; 114 } 115 116 // Set the member ID and container classes. 117 $member_id = (int) $block_args['itemID']; 118 $container_classes = array( 'bp-block-member' ); 119 120 // Mention variables. 121 $username = bp_core_get_username( $member_id ); 122 $at_mention = ''; 123 124 // Avatar variables. 125 $avatar = ''; 126 $avatar_container = ''; 127 128 // Cover image variable. 129 $cover_image = ''; 130 $cover_style = ''; 131 $cover_container = ''; 132 133 // Member name variables. 134 $display_name = bp_core_get_user_displayname( $member_id ); 135 $member_link = bp_core_get_user_domain( $member_id ); 136 137 // Member action button. 138 $action_button = ''; 139 $display_action_button = (bool) $block_args['displayActionButton']; 140 141 if ( $bp->avatar && $bp->avatar->show_avatars && in_array( $block_args['avatarSize'], array( 'thumb', 'full' ), true ) ) { 142 $avatar = bp_core_fetch_avatar( 143 array( 144 'item_id' => $member_id, 145 'object' => 'user', 146 'type' => $block_args['avatarSize'], 147 'html' => false, 148 ) 149 ); 150 151 $container_classes[] = 'avatar-' . $block_args['avatarSize']; 152 } else { 153 $container_classes[] = 'avatar-none'; 154 } 155 156 if ( $avatar ) { 157 $avatar_container = sprintf( 158 '<div class="item-header-avatar"> 159 <a href="%1$s"> 160 <img src="%2$s" alt="%3$s" class="avatar"> 161 </a> 162 </div>', 163 esc_url( $member_link ), 164 esc_url( $avatar ), 165 // Translators: %s is the member's display name. 166 sprintf( esc_html__( 'Profile photo of %s', 'buddypress' ), $display_name ) 167 ); 168 } 169 170 $display_cover_image = (bool) $block_args['displayCoverImage']; 171 if ( bp_is_active( 'members', 'cover_image' ) && $display_cover_image ) { 172 $cover_image = bp_attachments_get_attachment( 173 'url', 174 array( 175 'item_id' => $member_id, 176 ) 177 ); 178 179 if ( $cover_image ) { 180 $cover_style = sprintf( 181 ' style="background-image: url( %s );"', 182 esc_url( $cover_image ) 183 ); 184 } 185 186 $cover_container = sprintf( 187 '<div class="bp-member-cover-image"%s></div>', 188 $cover_style 189 ); 190 191 $container_classes[] = 'has-cover'; 192 } 193 194 $display_mention_slug = (bool) $block_args['displayMentionSlug']; 195 if ( bp_is_active( 'activity' ) && bp_activity_do_mentions() && $display_mention_slug ) { 196 $at_mention = sprintf( 197 '<span class="user-nicename">@%s</span>', 198 esc_html( $username ) 199 ); 200 } 201 202 if ( $display_action_button ) { 203 $action_button = sprintf( 204 '<div class="bp-profile-button"> 205 <a href="%1$s" class="button large primary button-primary" role="button">%2$s</a> 206 </div>', 207 esc_url( $member_link ), 208 esc_html__( 'View Profile', 'buddypress' ) 209 ); 210 } 211 212 $output = sprintf( 213 '<div class="%1$s"> 214 %2$s 215 <div class="member-content"> 216 %3$s 217 <div class="member-description"> 218 <strong><a href="%4$s">%5$s</a></strong> 219 %6$s 220 %7$s 221 </div> 222 </div> 223 </div>', 224 implode( ' ', array_map( 'sanitize_html_class', $container_classes ) ), 225 $cover_container, 226 $avatar_container, 227 esc_url( $member_link ), 228 esc_html( $display_name ), 229 $at_mention, 230 $action_button 231 ); 232 233 // Compact all interesting parameters. 234 $params = array_merge( $block_args, compact( 'username', 'display_name', 'member_link', 'avatar', 'cover_image' ) ); 235 236 /** 237 * Filter here to edit the output of the single member block. 238 * 239 * @since 6.0.0 240 * 241 * @param string $output The HTML output of the block. 242 * @param array $params The block extended parameters. 243 */ 244 return apply_filters( 'bp_members_render_member_block_output', $output, $params ); 245 } -
src/bp-members/classes/class-bp-members-component.php
diff --git src/bp-members/classes/class-bp-members-component.php src/bp-members/classes/class-bp-members-component.php index 29576b52f..af46a4689 100644
class BP_Members_Component extends BP_Component { 61 61 'template', 62 62 'adminbar', 63 63 'functions', 64 'blocks', 64 65 'widgets', 65 66 'cache', 66 67 ); -
new file src/bp-members/css/blocks/member-rtl.css
diff --git src/bp-members/css/blocks/member-rtl.css src/bp-members/css/blocks/member-rtl.css new file mode 100644 index 000000000..ff9de024c
- + 1 /* CSS for the bp/member block */ 2 .bp-block-member { 3 position: relative; 4 } 5 6 .bp-block-member .member-content { 7 display: flex; 8 } 9 10 .bp-block-member.has-cover .member-content, 11 .bp-block-member.has-cover .item-header-avatar, 12 .bp-block-member.has-cover .member-description { 13 z-index: 2; 14 } 15 16 .bp-block-member.has-cover .member-description { 17 padding-top: 75px; 18 } 19 20 .bp-block-member.has-cover .bp-member-cover-image { 21 background-color: #c5c5c5; 22 background-position: center top; 23 background-repeat: no-repeat; 24 background-size: cover; 25 border: 0; 26 display: block; 27 right: 0; 28 margin: 0; 29 padding: 0; 30 position: absolute; 31 top: 0; 32 width: 100%; 33 z-index: 1; 34 height: 150px; 35 } 36 37 .bp-block-member img.avatar { 38 width: auto; 39 height: auto; 40 } 41 42 .bp-block-member.avatar-none .item-header-avatar { 43 display: none; 44 } 45 46 .bp-block-member.avatar-none.has-cover { 47 min-height: 200px; 48 } 49 50 .bp-block-member.avatar-full { 51 min-height: 150px; 52 } 53 54 .bp-block-member.avatar-full.has-cover { 55 min-height: 300px; 56 } 57 58 .bp-block-member.avatar-full .item-header-avatar { 59 width: 180px; 60 } 61 62 .bp-block-member.has-cover.avatar-full .item-header-avatar { 63 width: 200px; 64 } 65 66 .bp-block-member.has-cover.avatar-full img.avatar { 67 border: solid 2px #fff; 68 background: rgba(255, 255, 255, 0.8); 69 margin-right: 20px; 70 } 71 72 .bp-block-member.has-cover .member-content { 73 padding-top: 75px; 74 } 75 76 .bp-block-member.avatar-thumb .member-content { 77 min-height: 50px; 78 align-items: center; 79 } 80 81 .bp-block-member.avatar-thumb .item-header-avatar { 82 width: 70px; 83 } 84 85 .bp-block-member.avatar-thumb.has-cover .item-header-avatar { 86 padding-top: 75px; 87 } 88 89 .bp-block-member .user-nicename { 90 display: block; 91 } 92 93 .bp-block-member .user-nicename a, 94 .entry .entry-content .bp-block-member .user-nicename a { 95 color: currentColor; 96 text-decoration: none; 97 border: none; 98 } 99 100 .bp-block-member .bp-profile-button { 101 width: 100%; 102 } 103 104 .bp-block-member .bp-profile-button a.button { 105 position: absolute; 106 bottom: 10px; 107 left: 0; 108 display: inline-block; 109 margin: 18px 0 0; 110 } -
new file src/bp-members/css/blocks/member.css
diff --git src/bp-members/css/blocks/member.css src/bp-members/css/blocks/member.css new file mode 100644 index 000000000..b03ea8687
- + 1 /* CSS for the bp/member block */ 2 .bp-block-member { 3 position: relative; 4 } 5 6 .bp-block-member .member-content { 7 display: flex; 8 } 9 10 .bp-block-member.has-cover .member-content, 11 .bp-block-member.has-cover .item-header-avatar, 12 .bp-block-member.has-cover .member-description { 13 z-index: 2; 14 } 15 16 .bp-block-member.has-cover .member-description { 17 padding-top: 75px; 18 } 19 20 .bp-block-member.has-cover .bp-member-cover-image { 21 background-color: #c5c5c5; 22 background-position: center top; 23 background-repeat: no-repeat; 24 background-size: cover; 25 border: 0; 26 display: block; 27 left: 0; 28 margin: 0; 29 padding: 0; 30 position: absolute; 31 top: 0; 32 width: 100%; 33 z-index: 1; 34 height: 150px; 35 } 36 37 .bp-block-member img.avatar { 38 width: auto; 39 height: auto; 40 } 41 42 .bp-block-member.avatar-none .item-header-avatar { 43 display: none; 44 } 45 46 .bp-block-member.avatar-none.has-cover { 47 min-height: 200px; 48 } 49 50 .bp-block-member.avatar-full { 51 min-height: 150px; 52 } 53 54 .bp-block-member.avatar-full.has-cover { 55 min-height: 300px; 56 } 57 58 .bp-block-member.avatar-full .item-header-avatar { 59 width: 180px; 60 } 61 62 .bp-block-member.has-cover.avatar-full .item-header-avatar { 63 width: 200px; 64 } 65 66 .bp-block-member.has-cover.avatar-full img.avatar { 67 border: solid 2px #fff; 68 background: rgba(255, 255, 255, 0.8); 69 margin-left: 20px; 70 } 71 72 .bp-block-member.has-cover .member-content { 73 padding-top: 75px; 74 } 75 76 .bp-block-member.avatar-thumb .member-content { 77 min-height: 50px; 78 align-items: center; 79 } 80 81 .bp-block-member.avatar-thumb .item-header-avatar { 82 width: 70px; 83 } 84 85 .bp-block-member.avatar-thumb.has-cover .item-header-avatar { 86 padding-top: 75px; 87 } 88 89 .bp-block-member .user-nicename { 90 display: block; 91 } 92 93 .bp-block-member .user-nicename a, 94 .entry .entry-content .bp-block-member .user-nicename a { 95 color: currentColor; 96 text-decoration: none; 97 border: none; 98 } 99 100 .bp-block-member .bp-profile-button { 101 width: 100%; 102 } 103 104 .bp-block-member .bp-profile-button a.button { 105 position: absolute; 106 bottom: 10px; 107 right: 0; 108 display: inline-block; 109 margin: 18px 0 0; 110 } -
new file src/bp-members/js/blocks/member.js
diff --git src/bp-members/js/blocks/member.js src/bp-members/js/blocks/member.js new file mode 100644 index 000000000..2bbb30326
- + 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 })({"kUj2":[function(require,module,exports) { 121 function _classCallCheck(instance, Constructor) { 122 if (!(instance instanceof Constructor)) { 123 throw new TypeError("Cannot call a class as a function"); 124 } 125 } 126 127 module.exports = _classCallCheck; 128 },{}],"dMjH":[function(require,module,exports) { 129 function _defineProperties(target, props) { 130 for (var i = 0; i < props.length; i++) { 131 var descriptor = props[i]; 132 descriptor.enumerable = descriptor.enumerable || false; 133 descriptor.configurable = true; 134 if ("value" in descriptor) descriptor.writable = true; 135 Object.defineProperty(target, descriptor.key, descriptor); 136 } 137 } 138 139 function _createClass(Constructor, protoProps, staticProps) { 140 if (protoProps) _defineProperties(Constructor.prototype, protoProps); 141 if (staticProps) _defineProperties(Constructor, staticProps); 142 return Constructor; 143 } 144 145 module.exports = _createClass; 146 },{}],"FlpK":[function(require,module,exports) { 147 function _typeof(obj) { 148 "@babel/helpers - typeof"; 149 150 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 151 module.exports = _typeof = function _typeof(obj) { 152 return typeof obj; 153 }; 154 } else { 155 module.exports = _typeof = function _typeof(obj) { 156 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 157 }; 158 } 159 160 return _typeof(obj); 161 } 162 163 module.exports = _typeof; 164 },{}],"oXBW":[function(require,module,exports) { 165 function _assertThisInitialized(self) { 166 if (self === void 0) { 167 throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 168 } 169 170 return self; 171 } 172 173 module.exports = _assertThisInitialized; 174 },{}],"cbGp":[function(require,module,exports) { 175 var _typeof = require("../helpers/typeof"); 176 177 var assertThisInitialized = require("./assertThisInitialized"); 178 179 function _possibleConstructorReturn(self, call) { 180 if (call && (_typeof(call) === "object" || typeof call === "function")) { 181 return call; 182 } 183 184 return assertThisInitialized(self); 185 } 186 187 module.exports = _possibleConstructorReturn; 188 },{"../helpers/typeof":"FlpK","./assertThisInitialized":"oXBW"}],"XApn":[function(require,module,exports) { 189 function _getPrototypeOf(o) { 190 module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { 191 return o.__proto__ || Object.getPrototypeOf(o); 192 }; 193 return _getPrototypeOf(o); 194 } 195 196 module.exports = _getPrototypeOf; 197 },{}],"Omxx":[function(require,module,exports) { 198 function _setPrototypeOf(o, p) { 199 module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { 200 o.__proto__ = p; 201 return o; 202 }; 203 204 return _setPrototypeOf(o, p); 205 } 206 207 module.exports = _setPrototypeOf; 208 },{}],"PhTw":[function(require,module,exports) { 209 var setPrototypeOf = require("./setPrototypeOf"); 210 211 function _inherits(subClass, superClass) { 212 if (typeof superClass !== "function" && superClass !== null) { 213 throw new TypeError("Super expression must either be null or a function"); 214 } 215 216 subClass.prototype = Object.create(superClass && superClass.prototype, { 217 constructor: { 218 value: subClass, 219 writable: true, 220 configurable: true 221 } 222 }); 223 if (superClass) setPrototypeOf(subClass, superClass); 224 } 225 226 module.exports = _inherits; 227 },{"./setPrototypeOf":"Omxx"}],"xHsb":[function(require,module,exports) { 228 "use strict"; 229 230 Object.defineProperty(exports, "__esModule", { 231 value: true 232 }); 233 exports.default = void 0; 234 235 var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); 236 237 var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); 238 239 var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); 240 241 var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); 242 243 var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); 244 245 var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); 246 247 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 248 249 /** 250 * WordPress dependencies. 251 */ 252 var _wp$element = wp.element, 253 Component = _wp$element.Component, 254 Fragment = _wp$element.Fragment, 255 createElement = _wp$element.createElement; 256 var Popover = wp.components.Popover; 257 var _wp = wp, 258 apiFetch = _wp.apiFetch; 259 var __ = wp.i18n.__; 260 261 var BPAutocompleter = /*#__PURE__*/function (_Component) { 262 (0, _inherits2.default)(BPAutocompleter, _Component); 263 264 function BPAutocompleter() { 265 var _this; 266 267 (0, _classCallCheck2.default)(this, BPAutocompleter); 268 _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(BPAutocompleter).apply(this, arguments)); 269 _this.state = { 270 search: '', 271 items: [], 272 error: '' 273 }; 274 _this.searchItemName = _this.searchItemName.bind((0, _assertThisInitialized2.default)(_this)); 275 _this.selectItemName = _this.selectItemName.bind((0, _assertThisInitialized2.default)(_this)); 276 return _this; 277 } 278 279 (0, _createClass2.default)(BPAutocompleter, [{ 280 key: "searchItemName", 281 value: function searchItemName(value) { 282 var _this2 = this; 283 284 var search = this.state.search; 285 var _this$props = this.props, 286 component = _this$props.component, 287 objectStatus = _this$props.objectStatus; 288 this.setState({ 289 search: value 290 }); 291 292 if (value.length < search.length) { 293 this.setState({ 294 items: [] 295 }); 296 } 297 298 var path = '/buddypress/v1/' + component; 299 300 if (value) { 301 path += '?search=' + encodeURIComponent(value); 302 } 303 304 if (objectStatus) { 305 path += '&status=' + objectStatus; 306 } 307 308 apiFetch({ 309 path: path 310 }).then(function (items) { 311 _this2.setState({ 312 items: items 313 }); 314 }, function (error) { 315 _this2.setState({ 316 error: error.message 317 }); 318 }); 319 } 320 }, { 321 key: "selectItemName", 322 value: function selectItemName(event, itemID) { 323 var onSelectItem = this.props.onSelectItem; 324 event.preventDefault(); 325 this.setState({ 326 search: '', 327 items: [], 328 error: '' 329 }); 330 return onSelectItem({ 331 itemID: itemID 332 }); 333 } 334 }, { 335 key: "render", 336 value: function render() { 337 var _this3 = this; 338 339 var _this$state = this.state, 340 search = _this$state.search, 341 items = _this$state.items; 342 var _this$props2 = this.props, 343 ariaLabel = _this$props2.ariaLabel, 344 placeholder = _this$props2.placeholder, 345 useAvatar = _this$props2.useAvatar; 346 var itemsList; 347 348 if (!ariaLabel) { 349 ariaLabel = __('Item\'s name', 'buddypress'); 350 } 351 352 if (!placeholder) { 353 placeholder = __('Enter Item\'s name here…', 'buddypress'); 354 } 355 356 if (items.length) { 357 itemsList = items.map(function (item) { 358 return createElement("button", { 359 type: "button", 360 key: 'editor-autocompleters__item-item-' + item.id, 361 role: "option", 362 "aria-selected": "true", 363 className: "components-button components-autocomplete__result editor-autocompleters__user", 364 onClick: function onClick(event) { 365 return _this3.selectItemName(event, item.id); 366 } 367 }, useAvatar && createElement("img", { 368 key: "avatar", 369 className: "editor-autocompleters__user-avatar", 370 alt: "", 371 src: item.avatar_urls.thumb 372 }), createElement("span", { 373 key: "name", 374 className: "editor-autocompleters__user-name" 375 }, item.name), item.mention_name && createElement("span", { 376 key: "slug", 377 className: "editor-autocompleters__user-slug" 378 }, item.mention_name)); 379 }); 380 } 381 382 return createElement(Fragment, null, createElement("input", { 383 type: "text", 384 value: search, 385 className: "components-placeholder__input", 386 "aria-label": ariaLabel, 387 placeholder: placeholder, 388 onChange: function onChange(event) { 389 return _this3.searchItemName(event.target.value); 390 } 391 }), 0 !== items.length && createElement(Popover, { 392 className: "components-autocomplete__popover", 393 focusOnMount: false, 394 position: "bottom left" 395 }, createElement("div", { 396 className: "components-autocomplete__results" 397 }, itemsList))); 398 } 399 }]); 400 return BPAutocompleter; 401 }(Component); 402 403 var _default = BPAutocompleter; 404 exports.default = _default; 405 },{"@babel/runtime/helpers/classCallCheck":"kUj2","@babel/runtime/helpers/createClass":"dMjH","@babel/runtime/helpers/possibleConstructorReturn":"cbGp","@babel/runtime/helpers/getPrototypeOf":"XApn","@babel/runtime/helpers/assertThisInitialized":"oXBW","@babel/runtime/helpers/inherits":"PhTw"}],"TmUL":[function(require,module,exports) { 406 "use strict"; 407 408 var _bpAutocompleter = _interopRequireDefault(require("../../../bp-core/js/blocks/bp-autocompleter")); 409 410 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 411 412 /** 413 * WordPress dependencies. 414 */ 415 var registerBlockType = wp.blocks.registerBlockType; 416 var _wp$element = wp.element, 417 createElement = _wp$element.createElement, 418 Fragment = _wp$element.Fragment; 419 var _wp$components = wp.components, 420 Placeholder = _wp$components.Placeholder, 421 Disabled = _wp$components.Disabled, 422 PanelBody = _wp$components.PanelBody, 423 SelectControl = _wp$components.SelectControl, 424 ToggleControl = _wp$components.ToggleControl, 425 Toolbar = _wp$components.Toolbar, 426 ToolbarButton = _wp$components.ToolbarButton; 427 var _wp$blockEditor = wp.blockEditor, 428 InspectorControls = _wp$blockEditor.InspectorControls, 429 BlockControls = _wp$blockEditor.BlockControls; 430 var withSelect = wp.data.withSelect; 431 var compose = wp.compose.compose; 432 var ServerSideRender = wp.editor.ServerSideRender; 433 var __ = wp.i18n.__; 434 /** 435 * Internal dependencies. 436 */ 437 438 var AVATAR_SIZES = [{ 439 label: __('None', 'buddypress'), 440 value: 'none' 441 }, { 442 label: __('Thumb', 'buddypress'), 443 value: 'thumb' 444 }, { 445 label: __('Full', 'buddypress'), 446 value: 'full' 447 }]; 448 449 var editMember = function editMember(_ref) { 450 var attributes = _ref.attributes, 451 setAttributes = _ref.setAttributes, 452 bpSettings = _ref.bpSettings; 453 var isAvatarEnabled = bpSettings.isAvatarEnabled, 454 isMentionEnabled = bpSettings.isMentionEnabled, 455 isCoverImageEnabled = bpSettings.isCoverImageEnabled; 456 var avatarSize = attributes.avatarSize, 457 displayMentionSlug = attributes.displayMentionSlug, 458 displayActionButton = attributes.displayActionButton, 459 displayCoverImage = attributes.displayCoverImage; 460 461 if (!attributes.itemID) { 462 return createElement(Placeholder, { 463 icon: "admin-users", 464 label: __('BuddyPress Member', 'buddypress'), 465 instructions: __('Start typing the name of the member you want to feature into this post.', 'buddypress') 466 }, createElement(_bpAutocompleter.default, { 467 component: "members", 468 ariaLabel: __('Member\'s username', 'buddypress'), 469 placeholder: __('Enter Member\'s username here…', 'buddypress'), 470 onSelectItem: setAttributes, 471 useAvatar: isAvatarEnabled 472 })); 473 } 474 475 return createElement(Fragment, null, createElement(BlockControls, null, createElement(Toolbar, null, createElement(ToolbarButton, { 476 icon: "edit", 477 title: __('Select another member', 'buddypress'), 478 onClick: function onClick() { 479 setAttributes({ 480 itemID: 0 481 }); 482 } 483 }))), createElement(InspectorControls, null, createElement(PanelBody, { 484 title: __('Profile button settings', 'buddypress'), 485 initialOpen: true 486 }, createElement(ToggleControl, { 487 label: __('Display Profile button', 'buddypress'), 488 checked: !!displayActionButton, 489 onChange: function onChange() { 490 setAttributes({ 491 displayActionButton: !displayActionButton 492 }); 493 }, 494 help: displayActionButton ? __('Include a link to the user\'s profile page under their display name.', 'buddypress') : __('Toggle to display a link to the user\'s profile page under their display name.', 'buddypress') 495 })), isAvatarEnabled && createElement(PanelBody, { 496 title: __('Avatar settings', 'buddypress'), 497 initialOpen: false 498 }, createElement(SelectControl, { 499 label: __('Size', 'buddypress'), 500 value: avatarSize, 501 options: AVATAR_SIZES, 502 onChange: function onChange(option) { 503 setAttributes({ 504 avatarSize: option 505 }); 506 } 507 })), isCoverImageEnabled && createElement(PanelBody, { 508 title: __('Cover image settings', 'buddypress'), 509 initialOpen: false 510 }, createElement(ToggleControl, { 511 label: __('Display Cover Image', 'buddypress'), 512 checked: !!displayCoverImage, 513 onChange: function onChange() { 514 setAttributes({ 515 displayCoverImage: !displayCoverImage 516 }); 517 }, 518 help: displayCoverImage ? __('Include the user\'s cover image over their display name.', 'buddypress') : __('Toggle to display the user\'s cover image over their display name.', 'buddypress') 519 })), isMentionEnabled && createElement(PanelBody, { 520 title: __('Mention settings', 'buddypress'), 521 initialOpen: false 522 }, createElement(ToggleControl, { 523 label: __('Display Mention slug', 'buddypress'), 524 checked: !!displayMentionSlug, 525 onChange: function onChange() { 526 setAttributes({ 527 displayMentionSlug: !displayMentionSlug 528 }); 529 }, 530 help: displayMentionSlug ? __('Include the user\'s mention name under their display name.', 'buddypress') : __('Toggle to display the user\'s mention name under their display name.', 'buddypress') 531 }))), createElement(Disabled, null, createElement(ServerSideRender, { 532 block: "bp/member", 533 attributes: attributes 534 }))); 535 }; 536 537 var editMemberBlock = compose([withSelect(function (select) { 538 var editorSettings = select('core/editor').getEditorSettings(); 539 return { 540 bpSettings: editorSettings.bp.members || {} 541 }; 542 })])(editMember); 543 registerBlockType('bp/member', { 544 title: __('Member', 'buddypress'), 545 description: __('BuddyPress Member.', 'buddypress'), 546 icon: 'admin-users', 547 category: 'buddypress', 548 attributes: { 549 itemID: { 550 type: 'integer', 551 default: 0 552 }, 553 avatarSize: { 554 type: 'string', 555 default: 'full' 556 }, 557 displayMentionSlug: { 558 type: 'boolean', 559 default: true 560 }, 561 displayActionButton: { 562 type: 'boolean', 563 default: true 564 }, 565 displayCoverImage: { 566 type: 'boolean', 567 default: true 568 } 569 }, 570 edit: editMemberBlock 571 }); 572 },{"../../../bp-core/js/blocks/bp-autocompleter":"xHsb"}]},{},["TmUL"], null) 573 No newline at end of file -
src/class-buddypress.php
diff --git src/class-buddypress.php src/class-buddypress.php index a5d449ebd..e4e559eae 100644
class BuddyPress { 488 488 require( $this->plugin_dir . 'bp-core/bp-core-loader.php' ); 489 489 require( $this->plugin_dir . 'bp-core/bp-core-customizer-email.php' ); 490 490 require( $this->plugin_dir . 'bp-core/bp-core-rest-api.php' ); 491 require( $this->plugin_dir . 'bp-core/bp-core-blocks.php' ); 491 492 492 493 // Maybe load deprecated functionality (this double negative is proof positive!). 493 494 if ( ! bp_get_option( '_bp_ignore_deprecated_code', ! $this->load_deprecated ) ) { … … class BuddyPress { 554 555 'BP_Attachment_Cover_Image' => 'core', 555 556 'BP_Attachment' => 'core', 556 557 'BP_Button' => 'core', 558 'BP_Block' => 'core', 557 559 'BP_Component' => 'core', 558 560 'BP_Customizer_Control_Range' => 'core', 559 561 'BP_Date_Query' => 'core', -
new file src/js/bp-core/js/blocks/.babelrc
diff --git src/js/bp-core/js/blocks/.babelrc src/js/bp-core/js/blocks/.babelrc new file mode 100644 index 000000000..ab258a69c
- + 1 { 2 "presets": ["@wordpress/default"] 3 } -
new file src/js/bp-core/js/blocks/bp-autocompleter.js
diff --git src/js/bp-core/js/blocks/bp-autocompleter.js src/js/bp-core/js/blocks/bp-autocompleter.js new file mode 100644 index 000000000..6c8ca3d04
- + 1 /** 2 * WordPress dependencies. 3 */ 4 const { Component, Fragment, createElement } = wp.element; 5 const { Popover } = wp.components; 6 const { apiFetch } = wp; 7 const { __ } = wp.i18n; 8 9 class BPAutocompleter extends Component { 10 constructor() { 11 super( ...arguments ); 12 13 this.state = { 14 search: '', 15 items: [], 16 error: '', 17 }; 18 19 this.searchItemName = this.searchItemName.bind( this ); 20 this.selectItemName = this.selectItemName.bind( this ); 21 } 22 23 searchItemName( value ) { 24 const { search } = this.state; 25 const { component, objectStatus } = this.props; 26 this.setState( { search: value } ); 27 28 if ( value.length < search.length ) { 29 this.setState( { items: [] } ); 30 } 31 32 let path= '/buddypress/v1/' + component; 33 34 if ( value ) { 35 path += '?search=' + encodeURIComponent( value ); 36 } 37 38 if ( objectStatus ) { 39 path += '&status=' + objectStatus; 40 } 41 42 apiFetch( { path: path } ).then( items => { 43 this.setState( { items: items } ); 44 }, error => { 45 this.setState( { error: error.message } ); 46 } ); 47 } 48 49 selectItemName( event, itemID ) { 50 const { onSelectItem } = this.props; 51 event.preventDefault(); 52 53 this.setState( { 54 search: '', 55 items: [], 56 error: '', 57 } ); 58 59 return onSelectItem( { itemID: itemID } ); 60 } 61 62 render() { 63 const { search, items } = this.state; 64 let { ariaLabel, placeholder, useAvatar } = this.props; 65 let itemsList; 66 67 if ( ! ariaLabel ) { 68 ariaLabel = __( 'Item\'s name', 'buddypress' ); 69 } 70 71 if ( ! placeholder ) { 72 placeholder = __( 'Enter Item\'s name here…', 'buddypress' ); 73 } 74 75 if ( items.length ) { 76 itemsList = items.map( ( item ) => { 77 return ( 78 <button 79 type="button" key={ 'editor-autocompleters__item-item-' + item.id } 80 role="option" 81 aria-selected="true" 82 className="components-button components-autocomplete__result editor-autocompleters__user" 83 onClick={ ( event ) => this.selectItemName( event, item.id ) } 84 > 85 { useAvatar && ( 86 <img key="avatar" className="editor-autocompleters__user-avatar" alt="" src={ item.avatar_urls.thumb } /> 87 ) } 88 <span key="name" className="editor-autocompleters__user-name">{ item.name }</span> 89 90 { item.mention_name && ( 91 <span key="slug" className="editor-autocompleters__user-slug">{ item.mention_name }</span> 92 ) } 93 </button> 94 ); 95 } ); 96 } 97 98 return ( 99 <Fragment> 100 <input 101 type="text" 102 value={ search } 103 className="components-placeholder__input" 104 aria-label={ ariaLabel } 105 placeholder={ placeholder } 106 onChange={ ( event ) => this.searchItemName( event.target.value ) } 107 /> 108 { 0 !== items.length && 109 <Popover 110 className="components-autocomplete__popover" 111 focusOnMount={ false } 112 position="bottom left" 113 > 114 <div className="components-autocomplete__results"> 115 { itemsList } 116 </div> 117 </Popover> 118 } 119 </Fragment> 120 ); 121 } 122 } 123 124 export default BPAutocompleter; -
new file src/js/bp-groups/js/blocks/.babelrc
diff --git src/js/bp-groups/js/blocks/.babelrc src/js/bp-groups/js/blocks/.babelrc new file mode 100644 index 000000000..ab258a69c
- + 1 { 2 "presets": ["@wordpress/default"] 3 } -
new file src/js/bp-groups/js/blocks/group.js
diff --git src/js/bp-groups/js/blocks/group.js src/js/bp-groups/js/blocks/group.js new file mode 100644 index 000000000..5fa40674e
- + 1 /** 2 * WordPress dependencies. 3 */ 4 const { registerBlockType } = wp.blocks; 5 const { createElement, Fragment } = wp.element; 6 const { Placeholder, Disabled, PanelBody, SelectControl, ToggleControl, Toolbar, ToolbarButton } = wp.components; 7 const { InspectorControls, BlockControls } = wp.blockEditor; 8 const { withSelect } = wp.data; 9 const { compose } = wp.compose; 10 const { ServerSideRender } = wp.editor; 11 const { __ } = wp.i18n; 12 13 /** 14 * Internal dependencies. 15 */ 16 import BPAutocompleter from '../../../bp-core/js/blocks/bp-autocompleter'; 17 18 const AVATAR_SIZES = [ 19 { 20 label: __( 'None', 'buddypress' ), 21 value: 'none', 22 }, 23 { 24 label: __( 'Thumb', 'buddypress' ), 25 value: 'thumb', 26 }, 27 { 28 label: __( 'Full', 'buddypress' ), 29 value: 'full', 30 }, 31 ]; 32 33 const editGroup = ( { attributes, setAttributes, bpSettings } ) => { 34 const { isAvatarEnabled, isCoverImageEnabled } = bpSettings; 35 const { avatarSize, displayDescription, displayActionButton, displayCoverImage } = attributes; 36 37 if ( ! attributes.itemID ) { 38 return ( 39 <Placeholder 40 icon="buddicons-groups" 41 label={ __( 'BuddyPress Group', 'buddypress' ) } 42 instructions={ __( 'Start typing the name of the group you want to feature into this post.', 'buddypress' ) } 43 > 44 <BPAutocompleter 45 component="groups" 46 objectStatus="public" 47 ariaLabel={ __( 'Group\'s name', 'buddypress' ) } 48 placeholder={ __( 'Enter Group\'s name here…', 'buddypress' ) } 49 onSelectItem={ setAttributes } 50 useAvatar={ isAvatarEnabled } 51 /> 52 </Placeholder> 53 ); 54 } 55 56 return ( 57 <Fragment> 58 <BlockControls> 59 <Toolbar> 60 <ToolbarButton 61 icon="edit" 62 title={ __( 'Select another group', 'buddypress' ) } 63 onClick={ () =>{ 64 setAttributes( { itemID: 0 } ); 65 } } 66 /> 67 </Toolbar> 68 </BlockControls> 69 <InspectorControls> 70 <PanelBody title={ __( 'Group\'s home button settings', 'buddypress' ) } initialOpen={ true }> 71 <ToggleControl 72 label={ __( 'Display Group\'s home button', 'buddypress' ) } 73 checked={ !! displayActionButton } 74 onChange={ () => { 75 setAttributes( { displayActionButton: ! displayActionButton } ); 76 } } 77 help={ 78 displayActionButton 79 ? __( 'Include a link to the group\'s home page under their name.', 'buddypress' ) 80 : __( 'Toggle to display a link to the group\'s home page under their name.', 'buddypress' ) 81 } 82 /> 83 </PanelBody> 84 <PanelBody title={ __( 'Description settings', 'buddypress' ) } initialOpen={ false }> 85 <ToggleControl 86 label={ __( 'Display group\'s description', 'buddypress' ) } 87 checked={ !! displayDescription } 88 onChange={ () => { 89 setAttributes( { displayDescription: ! displayDescription } ); 90 } } 91 help={ 92 displayDescription 93 ? __( 'Include the group\'s description under their name.', 'buddypress' ) 94 : __( 'Toggle to display the group\'s description under their name.', 'buddypress' ) 95 } 96 /> 97 </PanelBody> 98 { isAvatarEnabled && ( 99 <PanelBody title={ __( 'Avatar settings', 'buddypress' ) } initialOpen={ false }> 100 <SelectControl 101 label={ __( 'Size', 'buddypress' ) } 102 value={ avatarSize } 103 options={ AVATAR_SIZES } 104 onChange={ ( option ) => { 105 setAttributes( { avatarSize: option } ); 106 } } 107 /> 108 </PanelBody> 109 ) } 110 { isCoverImageEnabled && ( 111 <PanelBody title={ __( 'Cover image settings', 'buddypress' ) } initialOpen={ false }> 112 <ToggleControl 113 label={ __( 'Display Cover Image', 'buddypress' ) } 114 checked={ !! displayCoverImage } 115 onChange={ () => { 116 setAttributes( { displayCoverImage: ! displayCoverImage } ); 117 } } 118 help={ 119 displayCoverImage 120 ? __( 'Include the group\'s cover image over their name.', 'buddypress' ) 121 : __( 'Toggle to display the group\'s cover image over their name.', 'buddypress' ) 122 } 123 /> 124 </PanelBody> 125 ) } 126 </InspectorControls> 127 <Disabled> 128 <ServerSideRender block="bp/group" attributes={ attributes } /> 129 </Disabled> 130 </Fragment> 131 ); 132 }; 133 134 const editGroupBlock = compose( [ 135 withSelect( ( select ) => { 136 const editorSettings = select( 'core/editor' ).getEditorSettings(); 137 return { 138 bpSettings: editorSettings.bp.groups || {}, 139 }; 140 } ), 141 ] )( editGroup ); 142 143 registerBlockType( 'bp/group', { 144 title: __( 'Group', 'buddypress' ), 145 146 description: __( 'BuddyPress Group.', 'buddypress' ), 147 148 icon: 'buddicons-groups', 149 150 category: 'buddypress', 151 152 attributes: { 153 itemID: { 154 type: 'integer', 155 default: 0, 156 }, 157 avatarSize: { 158 type: 'string', 159 default: 'full', 160 }, 161 displayDescription: { 162 type: 'boolean', 163 default: true, 164 }, 165 displayActionButton: { 166 type: 'boolean', 167 default: true, 168 }, 169 displayCoverImage: { 170 type: 'boolean', 171 default: true, 172 }, 173 }, 174 175 edit: editGroupBlock, 176 } ); -
new file src/js/bp-members/js/blocks/.babelrc
diff --git src/js/bp-members/js/blocks/.babelrc src/js/bp-members/js/blocks/.babelrc new file mode 100644 index 000000000..ab258a69c
- + 1 { 2 "presets": ["@wordpress/default"] 3 } -
new file src/js/bp-members/js/blocks/member.js
diff --git src/js/bp-members/js/blocks/member.js src/js/bp-members/js/blocks/member.js new file mode 100644 index 000000000..179a61dbb
- + 1 /** 2 * WordPress dependencies. 3 */ 4 const { registerBlockType } = wp.blocks; 5 const { createElement, Fragment } = wp.element; 6 const { Placeholder, Disabled, PanelBody, SelectControl, ToggleControl, Toolbar, ToolbarButton } = wp.components; 7 const { InspectorControls, BlockControls } = wp.blockEditor; 8 const { withSelect } = wp.data; 9 const { compose } = wp.compose; 10 const { ServerSideRender } = wp.editor; 11 const { __ } = wp.i18n; 12 13 /** 14 * Internal dependencies. 15 */ 16 import BPAutocompleter from '../../../bp-core/js/blocks/bp-autocompleter'; 17 18 const AVATAR_SIZES = [ 19 { 20 label: __( 'None', 'buddypress' ), 21 value: 'none', 22 }, 23 { 24 label: __( 'Thumb', 'buddypress' ), 25 value: 'thumb', 26 }, 27 { 28 label: __( 'Full', 'buddypress' ), 29 value: 'full', 30 }, 31 ]; 32 33 const editMember = ( { attributes, setAttributes, bpSettings } ) => { 34 const { isAvatarEnabled, isMentionEnabled, isCoverImageEnabled } = bpSettings; 35 const { avatarSize, displayMentionSlug, displayActionButton, displayCoverImage } = attributes; 36 37 if ( ! attributes.itemID ) { 38 return ( 39 <Placeholder 40 icon="admin-users" 41 label={ __( 'BuddyPress Member', 'buddypress' ) } 42 instructions={ __( 'Start typing the name of the member you want to feature into this post.', 'buddypress' ) } 43 > 44 <BPAutocompleter 45 component="members" 46 ariaLabel={ __( 'Member\'s username', 'buddypress' ) } 47 placeholder={ __( 'Enter Member\'s username here…', 'buddypress' ) } 48 onSelectItem={ setAttributes } 49 useAvatar={ isAvatarEnabled } 50 /> 51 </Placeholder> 52 ); 53 } 54 55 return ( 56 <Fragment> 57 <BlockControls> 58 <Toolbar> 59 <ToolbarButton 60 icon="edit" 61 title={ __( 'Select another member', 'buddypress' ) } 62 onClick={ () =>{ 63 setAttributes( { itemID: 0 } ); 64 } } 65 /> 66 </Toolbar> 67 </BlockControls> 68 <InspectorControls> 69 <PanelBody title={ __( 'Profile button settings', 'buddypress' ) } initialOpen={ true }> 70 <ToggleControl 71 label={ __( 'Display Profile button', 'buddypress' ) } 72 checked={ !! displayActionButton } 73 onChange={ () => { 74 setAttributes( { displayActionButton: ! displayActionButton } ); 75 } } 76 help={ 77 displayActionButton 78 ? __( 'Include a link to the user\'s profile page under their display name.', 'buddypress' ) 79 : __( 'Toggle to display a link to the user\'s profile page under their display name.', 'buddypress' ) 80 } 81 /> 82 </PanelBody> 83 { isAvatarEnabled && ( 84 <PanelBody title={ __( 'Avatar settings', 'buddypress' ) } initialOpen={ false }> 85 <SelectControl 86 label={ __( 'Size', 'buddypress' ) } 87 value={ avatarSize } 88 options={ AVATAR_SIZES } 89 onChange={ ( option ) => { 90 setAttributes( { avatarSize: option } ); 91 } } 92 /> 93 </PanelBody> 94 ) } 95 { isCoverImageEnabled && ( 96 <PanelBody title={ __( 'Cover image settings', 'buddypress' ) } initialOpen={ false }> 97 <ToggleControl 98 label={ __( 'Display Cover Image', 'buddypress' ) } 99 checked={ !! displayCoverImage } 100 onChange={ () => { 101 setAttributes( { displayCoverImage: ! displayCoverImage } ); 102 } } 103 help={ 104 displayCoverImage 105 ? __( 'Include the user\'s cover image over their display name.', 'buddypress' ) 106 : __( 'Toggle to display the user\'s cover image over their display name.', 'buddypress' ) 107 } 108 /> 109 </PanelBody> 110 ) } 111 { isMentionEnabled && ( 112 <PanelBody title={ __( 'Mention settings', 'buddypress' ) } initialOpen={ false }> 113 <ToggleControl 114 label={ __( 'Display Mention slug', 'buddypress' ) } 115 checked={ !! displayMentionSlug } 116 onChange={ () => { 117 setAttributes( { displayMentionSlug: ! displayMentionSlug } ); 118 } } 119 help={ 120 displayMentionSlug 121 ? __( 'Include the user\'s mention name under their display name.', 'buddypress' ) 122 : __( 'Toggle to display the user\'s mention name under their display name.', 'buddypress' ) 123 } 124 /> 125 </PanelBody> 126 ) } 127 </InspectorControls> 128 <Disabled> 129 <ServerSideRender block="bp/member" attributes={ attributes } /> 130 </Disabled> 131 </Fragment> 132 ); 133 }; 134 135 const editMemberBlock = compose( [ 136 withSelect( ( select ) => { 137 const editorSettings = select( 'core/editor' ).getEditorSettings(); 138 return { 139 bpSettings: editorSettings.bp.members || {}, 140 }; 141 } ), 142 ] )( editMember ); 143 144 registerBlockType( 'bp/member', { 145 title: __( 'Member', 'buddypress' ), 146 147 description: __( 'BuddyPress Member.', 'buddypress' ), 148 149 icon: 'admin-users', 150 151 category: 'buddypress', 152 153 attributes: { 154 itemID: { 155 type: 'integer', 156 default: 0, 157 }, 158 avatarSize: { 159 type: 'string', 160 default: 'full', 161 }, 162 displayMentionSlug: { 163 type: 'boolean', 164 default: true, 165 }, 166 displayActionButton: { 167 type: 'boolean', 168 default: true, 169 }, 170 displayCoverImage: { 171 type: 'boolean', 172 default: true, 173 }, 174 }, 175 176 edit: editMemberBlock, 177 } );