acf-datastore.asset.php
3 months ago
acf-datastore.js
3 months ago
acf-datastore.js.map
3 months ago
acf-datastore.min.asset.php
3 months ago
acf-datastore.min.js
3 months ago
acf-field-bindings.asset.php
3 months ago
acf-field-bindings.js
3 months ago
acf-field-bindings.js.map
3 months ago
acf-field-bindings.min.asset.php
3 months ago
acf-field-bindings.min.js
3 months ago
acf-pro-blocks.asset.php
4 weeks ago
acf-pro-blocks.js
4 weeks ago
acf-pro-blocks.js.map
4 weeks ago
acf-pro-blocks.min.asset.php
4 weeks ago
acf-pro-blocks.min.js
4 weeks ago
acf-pro-field-group.asset.php
11 months ago
acf-pro-field-group.js
11 months ago
acf-pro-field-group.js.map
9 months ago
acf-pro-field-group.min.asset.php
9 months ago
acf-pro-field-group.min.js
9 months ago
acf-pro-input.asset.php
1 month ago
acf-pro-input.js
1 month ago
acf-pro-input.js.map
1 month ago
acf-pro-input.min.asset.php
1 month ago
acf-pro-input.min.js
1 month ago
acf-pro-ui-options-page.asset.php
9 months ago
acf-pro-ui-options-page.js
9 months ago
acf-pro-ui-options-page.js.map
9 months ago
acf-pro-ui-options-page.min.asset.php
9 months ago
acf-pro-ui-options-page.min.js
9 months ago
index.php
1 year ago
acf-pro-blocks.js
5887 lines
| 1 | /******/ (() => { // webpackBootstrap |
| 2 | /******/ var __webpack_modules__ = ({ |
| 3 | |
| 4 | /***/ "./assets/src/js/pro/_acf-blocks-v3.js": |
| 5 | /*!*********************************************!*\ |
| 6 | !*** ./assets/src/js/pro/_acf-blocks-v3.js ***! |
| 7 | \*********************************************/ |
| 8 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 9 | |
| 10 | "use strict"; |
| 11 | __webpack_require__.r(__webpack_exports__); |
| 12 | /* harmony import */ var _blocks_v3_utils_post_locking__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./blocks-v3/utils/post-locking */ "./assets/src/js/pro/blocks-v3/utils/post-locking.js"); |
| 13 | /* harmony import */ var _blocks_v3_components_jsx_parser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./blocks-v3/components/jsx-parser */ "./assets/src/js/pro/blocks-v3/components/jsx-parser.js"); |
| 14 | /* harmony import */ var _blocks_v3_register_block_type_v3__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./blocks-v3/register-block-type-v3 */ "./assets/src/js/pro/blocks-v3/register-block-type-v3.js"); |
| 15 | /** |
| 16 | * ACF Blocks Version 3 - Entry Point |
| 17 | * Imports all modules and initializes the block system |
| 18 | */ |
| 19 | |
| 20 | // Import utilities. |
| 21 | |
| 22 | |
| 23 | // Import JSX parser and expose on acf global. |
| 24 | |
| 25 | |
| 26 | // Import block registration (initializes automatically via acf.addAction). |
| 27 | |
| 28 | |
| 29 | /***/ }), |
| 30 | |
| 31 | /***/ "./assets/src/js/pro/_acf-blocks.js": |
| 32 | /*!******************************************!*\ |
| 33 | !*** ./assets/src/js/pro/_acf-blocks.js ***! |
| 34 | \******************************************/ |
| 35 | /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { |
| 36 | |
| 37 | function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } |
| 38 | const md5 = __webpack_require__(/*! md5 */ "./node_modules/md5/md5.js"); |
| 39 | (($, undefined) => { |
| 40 | // Dependencies. |
| 41 | const { |
| 42 | BlockControls, |
| 43 | InspectorControls, |
| 44 | InnerBlocks, |
| 45 | useBlockProps, |
| 46 | AlignmentToolbar, |
| 47 | BlockVerticalAlignmentToolbar |
| 48 | } = wp.blockEditor; |
| 49 | const { |
| 50 | ToolbarGroup, |
| 51 | ToolbarButton, |
| 52 | Placeholder, |
| 53 | Spinner |
| 54 | } = wp.components; |
| 55 | const { |
| 56 | Fragment |
| 57 | } = wp.element; |
| 58 | const { |
| 59 | Component |
| 60 | } = React; |
| 61 | const { |
| 62 | useSelect |
| 63 | } = wp.data; |
| 64 | const { |
| 65 | createHigherOrderComponent |
| 66 | } = wp.compose; |
| 67 | |
| 68 | // Potentially experimental dependencies. |
| 69 | const BlockAlignmentMatrixToolbar = wp.blockEditor.__experimentalBlockAlignmentMatrixToolbar || wp.blockEditor.BlockAlignmentMatrixToolbar; |
| 70 | // Gutenberg v10.x begins transition from Toolbar components to Control components. |
| 71 | const BlockAlignmentMatrixControl = wp.blockEditor.__experimentalBlockAlignmentMatrixControl || wp.blockEditor.BlockAlignmentMatrixControl; |
| 72 | const BlockFullHeightAlignmentControl = wp.blockEditor.__experimentalBlockFullHeightAligmentControl || wp.blockEditor.__experimentalBlockFullHeightAlignmentControl || wp.blockEditor.BlockFullHeightAlignmentControl; |
| 73 | const useInnerBlocksProps = wp.blockEditor.__experimentalUseInnerBlocksProps || wp.blockEditor.useInnerBlocksProps; |
| 74 | |
| 75 | /** |
| 76 | * Storage for registered block types. |
| 77 | * |
| 78 | * @since ACF 5.8.0 |
| 79 | * @var object |
| 80 | */ |
| 81 | const blockTypes = {}; |
| 82 | |
| 83 | /** |
| 84 | * Data storage for Block Instances and their DynamicHTML components. |
| 85 | * This is temporarily stored on the ACF object, but this will be replaced later. |
| 86 | * Developers should not rely on reading or using any aspect of acf.blockInstances. |
| 87 | * |
| 88 | * @since ACF 6.3 |
| 89 | */ |
| 90 | acf.blockInstances = {}; |
| 91 | |
| 92 | /** |
| 93 | * Returns a block type for the given name. |
| 94 | * |
| 95 | * @date 20/2/19 |
| 96 | * @since ACF 5.8.0 |
| 97 | * |
| 98 | * @param string name The block name. |
| 99 | * @return (object|false) |
| 100 | */ |
| 101 | function getBlockType(name) { |
| 102 | return blockTypes[name] || false; |
| 103 | } |
| 104 | |
| 105 | /** |
| 106 | * Returns a block version for a given block name |
| 107 | * |
| 108 | * @date 8/6/22 |
| 109 | * @since ACF 6.0 |
| 110 | * |
| 111 | * @param string name The block name |
| 112 | * @return int |
| 113 | */ |
| 114 | function getBlockVersion(name) { |
| 115 | const blockType = getBlockType(name); |
| 116 | return blockType.acf_block_version || 1; |
| 117 | } |
| 118 | |
| 119 | /** |
| 120 | * Returns a block's validate property. Default true. |
| 121 | * |
| 122 | * @since ACF 6.3 |
| 123 | * |
| 124 | * @param string name The block name |
| 125 | * @return boolean |
| 126 | */ |
| 127 | function blockSupportsValidation(name) { |
| 128 | const blockType = getBlockType(name); |
| 129 | return blockType.validate; |
| 130 | } |
| 131 | |
| 132 | /** |
| 133 | * Returns true if a block (identified by client ID) is nested in a query loop block. |
| 134 | * |
| 135 | * @date 17/1/22 |
| 136 | * @since ACF 5.12 |
| 137 | * |
| 138 | * @param {string} clientId A block client ID |
| 139 | * @return boolean |
| 140 | */ |
| 141 | function isBlockInQueryLoop(clientId) { |
| 142 | const parents = wp.data.select('core/block-editor').getBlockParents(clientId); |
| 143 | const parentsData = wp.data.select('core/block-editor').getBlocksByClientId(parents); |
| 144 | return parentsData.filter(block => block.name === 'core/query').length; |
| 145 | } |
| 146 | |
| 147 | /** |
| 148 | * Returns true if we're currently inside the WP 5.9+ site editor. |
| 149 | * |
| 150 | * @date 08/02/22 |
| 151 | * @since ACF 5.12 |
| 152 | * |
| 153 | * @return boolean |
| 154 | */ |
| 155 | function isSiteEditor() { |
| 156 | return document.querySelectorAll('iframe[name="editor-canvas"]').length > 0; |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | * Returns true if the block editor is currently showing the desktop device type preview. |
| 161 | * |
| 162 | * This function will always return true in the site editor as it uses the |
| 163 | * edit-post store rather than the edit-site store. |
| 164 | * |
| 165 | * @date 15/02/22 |
| 166 | * @since ACF 5.12 |
| 167 | * |
| 168 | * @return boolean |
| 169 | */ |
| 170 | function isDesktopPreviewDeviceType() { |
| 171 | const editPostStore = select('core/edit-post'); |
| 172 | |
| 173 | // Return true if the edit post store isn't available (such as in the widget editor) |
| 174 | if (!editPostStore) return true; |
| 175 | |
| 176 | // Check if function exists (experimental or not) and return true if it's Desktop, or doesn't exist. |
| 177 | if (editPostStore.__experimentalGetPreviewDeviceType) { |
| 178 | return 'Desktop' === editPostStore.__experimentalGetPreviewDeviceType(); |
| 179 | } else if (editPostStore.getPreviewDeviceType) { |
| 180 | return 'Desktop' === editPostStore.getPreviewDeviceType(); |
| 181 | } else { |
| 182 | return true; |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Returns true if the block editor is currently in template edit mode. |
| 188 | * |
| 189 | * @date 16/02/22 |
| 190 | * @since ACF 5.12 |
| 191 | * |
| 192 | * @return boolean |
| 193 | */ |
| 194 | function isEditingTemplate() { |
| 195 | const editPostStore = select('core/edit-post'); |
| 196 | |
| 197 | // Return false if the edit post store isn't available (such as in the widget editor) |
| 198 | if (!editPostStore) return false; |
| 199 | |
| 200 | // Return false if the function doesn't exist |
| 201 | if (!editPostStore.isEditingTemplate) return false; |
| 202 | return editPostStore.isEditingTemplate(); |
| 203 | } |
| 204 | |
| 205 | /** |
| 206 | * Returns true if we're currently inside an iFramed non-desktop device preview type (WP5.9+) |
| 207 | * |
| 208 | * @date 15/02/22 |
| 209 | * @since ACF 5.12 |
| 210 | * |
| 211 | * @return boolean |
| 212 | */ |
| 213 | function isiFramedMobileDevicePreview() { |
| 214 | return $('iframe[name=editor-canvas]').length && !isDesktopPreviewDeviceType(); |
| 215 | } |
| 216 | |
| 217 | /** |
| 218 | * Registers a block type. |
| 219 | * |
| 220 | * @date 19/2/19 |
| 221 | * @since ACF 5.8.0 |
| 222 | * |
| 223 | * @param object blockType The block type settings localized from PHP. |
| 224 | * @return object The result from wp.blocks.registerBlockType(). |
| 225 | */ |
| 226 | function registerBlockType(blockType) { |
| 227 | // Bail early if is excluded post_type. |
| 228 | const allowedTypes = blockType.post_types || []; |
| 229 | if (allowedTypes.length) { |
| 230 | // Always allow block to appear on "Edit reusable Block" screen. |
| 231 | allowedTypes.push('wp_block'); |
| 232 | |
| 233 | // Check post type. |
| 234 | const postType = acf.get('postType'); |
| 235 | if (!allowedTypes.includes(postType)) { |
| 236 | return false; |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | // Handle svg HTML. |
| 241 | if (typeof blockType.icon === 'string' && blockType.icon.substr(0, 4) === '<svg') { |
| 242 | const iconHTML = blockType.icon; |
| 243 | blockType.icon = /*#__PURE__*/React.createElement(Div, null, iconHTML); |
| 244 | } |
| 245 | |
| 246 | // Remove icon if empty to allow for default "block". |
| 247 | // Avoids JS error preventing block from being registered. |
| 248 | if (!blockType.icon) { |
| 249 | delete blockType.icon; |
| 250 | } |
| 251 | |
| 252 | // Check category exists and fallback to "common". |
| 253 | const category = wp.blocks.getCategories().filter(({ |
| 254 | slug |
| 255 | }) => slug === blockType.category).pop(); |
| 256 | if (!category) { |
| 257 | //console.warn( `The block "${blockType.name}" is registered with an unknown category "${blockType.category}".` ); |
| 258 | blockType.category = 'common'; |
| 259 | } |
| 260 | |
| 261 | // Merge in block settings before local additions. |
| 262 | blockType = acf.parseArgs(blockType, { |
| 263 | title: '', |
| 264 | name: '', |
| 265 | category: '', |
| 266 | api_version: 2, |
| 267 | acf_block_version: 1 |
| 268 | }); |
| 269 | |
| 270 | // Remove all empty attribute defaults from PHP values to allow serialisation. |
| 271 | // https://github.com/WordPress/gutenberg/issues/7342 |
| 272 | for (const key in blockType.attributes) { |
| 273 | if ('default' in blockType.attributes[key] && blockType.attributes[key].default.length === 0) { |
| 274 | delete blockType.attributes[key].default; |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | // Apply anchor supports to avoid block editor default writing to ID. |
| 279 | if (blockType.supports.anchor) { |
| 280 | blockType.attributes.anchor = { |
| 281 | type: 'string' |
| 282 | }; |
| 283 | } |
| 284 | |
| 285 | // Append edit and save functions. |
| 286 | let ThisBlockEdit = BlockEdit; |
| 287 | let ThisBlockSave = BlockSave; |
| 288 | |
| 289 | // Apply alignText functionality. |
| 290 | if (blockType.supports.alignText || blockType.supports.align_text) { |
| 291 | blockType.attributes = addBackCompatAttribute(blockType.attributes, 'align_text', 'string'); |
| 292 | ThisBlockEdit = withAlignTextComponent(ThisBlockEdit, blockType); |
| 293 | } |
| 294 | |
| 295 | // Apply alignContent functionality. |
| 296 | if (blockType.supports.alignContent || blockType.supports.align_content) { |
| 297 | blockType.attributes = addBackCompatAttribute(blockType.attributes, 'align_content', 'string'); |
| 298 | ThisBlockEdit = withAlignContentComponent(ThisBlockEdit, blockType); |
| 299 | } |
| 300 | |
| 301 | // Apply fullHeight functionality. |
| 302 | if (blockType.supports.fullHeight || blockType.supports.full_height) { |
| 303 | blockType.attributes = addBackCompatAttribute(blockType.attributes, 'full_height', 'boolean'); |
| 304 | ThisBlockEdit = withFullHeightComponent(ThisBlockEdit, blockType.blockType); |
| 305 | } |
| 306 | |
| 307 | // Set edit and save functions. |
| 308 | blockType.edit = props => { |
| 309 | // Ensure we remove our save lock if a block is removed. |
| 310 | wp.element.useEffect(() => { |
| 311 | return () => { |
| 312 | if (!wp.data.dispatch('core/editor')) return; |
| 313 | wp.data.dispatch('core/editor').unlockPostSaving('acf/block/' + props.clientId); |
| 314 | }; |
| 315 | }, []); |
| 316 | return /*#__PURE__*/React.createElement(ThisBlockEdit, props); |
| 317 | }; |
| 318 | blockType.save = () => /*#__PURE__*/React.createElement(ThisBlockSave, null); |
| 319 | |
| 320 | // Add to storage. |
| 321 | blockTypes[blockType.name] = blockType; |
| 322 | |
| 323 | // Register with WP. |
| 324 | const result = wp.blocks.registerBlockType(blockType.name, blockType); |
| 325 | |
| 326 | // Fix bug in 'core/anchor/attribute' filter overwriting attribute. |
| 327 | // Required for < WP5.9 |
| 328 | // See https://github.com/WordPress/gutenberg/issues/15240 |
| 329 | if (result.attributes.anchor) { |
| 330 | result.attributes.anchor = { |
| 331 | type: 'string' |
| 332 | }; |
| 333 | } |
| 334 | |
| 335 | // Return result. |
| 336 | return result; |
| 337 | } |
| 338 | |
| 339 | /** |
| 340 | * Returns the wp.data.select() response with backwards compatibility. |
| 341 | * |
| 342 | * @date 17/06/2020 |
| 343 | * @since ACF 5.9.0 |
| 344 | * |
| 345 | * @param string selector The selector name. |
| 346 | * @return mixed |
| 347 | */ |
| 348 | function select(selector) { |
| 349 | if (selector === 'core/block-editor') { |
| 350 | return wp.data.select('core/block-editor') || wp.data.select('core/editor'); |
| 351 | } |
| 352 | return wp.data.select(selector); |
| 353 | } |
| 354 | |
| 355 | /** |
| 356 | * Returns the wp.data.dispatch() response with backwards compatibility. |
| 357 | * |
| 358 | * @date 17/06/2020 |
| 359 | * @since ACF 5.9.0 |
| 360 | * |
| 361 | * @param string selector The selector name. |
| 362 | * @return mixed |
| 363 | */ |
| 364 | function dispatch(selector) { |
| 365 | return wp.data.dispatch(selector); |
| 366 | } |
| 367 | |
| 368 | /** |
| 369 | * Returns an array of all blocks for the given args. |
| 370 | * |
| 371 | * @date 27/2/19 |
| 372 | * @since ACF 5.7.13 |
| 373 | * |
| 374 | * @param {object} args An object of key=>value pairs used to filter results. |
| 375 | * @return array. |
| 376 | */ |
| 377 | function getBlocks(args) { |
| 378 | let blocks = []; |
| 379 | |
| 380 | // Local function to recurse through all child blocks and add to the blocks array. |
| 381 | const recurseBlocks = block => { |
| 382 | blocks.push(block); |
| 383 | select('core/block-editor').getBlocks(block.clientId).forEach(recurseBlocks); |
| 384 | }; |
| 385 | |
| 386 | // Trigger initial recursion for parent level blocks. |
| 387 | select('core/block-editor').getBlocks().forEach(recurseBlocks); |
| 388 | |
| 389 | // Loop over args and filter. |
| 390 | for (const k in args) { |
| 391 | blocks = blocks.filter(({ |
| 392 | attributes |
| 393 | }) => attributes[k] === args[k]); |
| 394 | } |
| 395 | |
| 396 | // Return results. |
| 397 | return blocks; |
| 398 | } |
| 399 | |
| 400 | /** |
| 401 | * Storage for the AJAX queue. |
| 402 | * |
| 403 | * @const {array} |
| 404 | */ |
| 405 | const ajaxQueue = {}; |
| 406 | |
| 407 | /** |
| 408 | * Storage for cached AJAX requests for block content. |
| 409 | * |
| 410 | * @since ACF 5.12 |
| 411 | * @const {array} |
| 412 | */ |
| 413 | const fetchCache = {}; |
| 414 | |
| 415 | /** |
| 416 | * Fetches a JSON result from the AJAX API. |
| 417 | * |
| 418 | * @date 28/2/19 |
| 419 | * @since ACF 5.7.13 |
| 420 | * |
| 421 | * @param object block The block props. |
| 422 | * @query object The query args used in AJAX callback. |
| 423 | * @return object The AJAX promise. |
| 424 | */ |
| 425 | function fetchBlock(args) { |
| 426 | const { |
| 427 | attributes = {}, |
| 428 | context = {}, |
| 429 | query = {}, |
| 430 | clientId = null, |
| 431 | delay = 0 |
| 432 | } = args; |
| 433 | |
| 434 | // Build a unique queue ID from block data, including the clientId for edit forms. |
| 435 | const queueId = md5(JSON.stringify({ |
| 436 | ...attributes, |
| 437 | ...context, |
| 438 | ...query |
| 439 | })); |
| 440 | const data = ajaxQueue[queueId] || { |
| 441 | query: {}, |
| 442 | timeout: false, |
| 443 | promise: $.Deferred(), |
| 444 | started: false |
| 445 | }; |
| 446 | |
| 447 | // Append query args to storage. |
| 448 | data.query = { |
| 449 | ...data.query, |
| 450 | ...query |
| 451 | }; |
| 452 | if (data.started) return data.promise; |
| 453 | |
| 454 | // Set fresh timeout. |
| 455 | clearTimeout(data.timeout); |
| 456 | data.timeout = setTimeout(() => { |
| 457 | data.started = true; |
| 458 | if (fetchCache[queueId]) { |
| 459 | ajaxQueue[queueId] = null; |
| 460 | data.promise.resolve.apply(fetchCache[queueId][0], fetchCache[queueId][1]); |
| 461 | } else { |
| 462 | $.ajax({ |
| 463 | url: acf.get('ajaxurl'), |
| 464 | dataType: 'json', |
| 465 | type: 'post', |
| 466 | cache: false, |
| 467 | data: acf.prepareForAjax({ |
| 468 | action: 'acf/ajax/fetch-block', |
| 469 | block: JSON.stringify(attributes), |
| 470 | clientId: clientId, |
| 471 | context: JSON.stringify(context), |
| 472 | query: data.query |
| 473 | }) |
| 474 | }).always(() => { |
| 475 | // Clean up queue after AJAX request is complete. |
| 476 | ajaxQueue[queueId] = null; |
| 477 | }).done(function () { |
| 478 | fetchCache[queueId] = [this, arguments]; |
| 479 | data.promise.resolve.apply(this, arguments); |
| 480 | }).fail(function () { |
| 481 | data.promise.reject.apply(this, arguments); |
| 482 | }); |
| 483 | } |
| 484 | }, delay); |
| 485 | |
| 486 | // Update storage. |
| 487 | ajaxQueue[queueId] = data; |
| 488 | |
| 489 | // Return promise. |
| 490 | return data.promise; |
| 491 | } |
| 492 | |
| 493 | /** |
| 494 | * Returns true if both object are the same. |
| 495 | * |
| 496 | * @date 19/05/2020 |
| 497 | * @since ACF 5.9.0 |
| 498 | * |
| 499 | * @param object obj1 |
| 500 | * @param object obj2 |
| 501 | * @return bool |
| 502 | */ |
| 503 | function compareObjects(obj1, obj2) { |
| 504 | return JSON.stringify(obj1) === JSON.stringify(obj2); |
| 505 | } |
| 506 | |
| 507 | /** |
| 508 | * Converts HTML into a React element. |
| 509 | * |
| 510 | * @date 19/05/2020 |
| 511 | * @since ACF 5.9.0 |
| 512 | * |
| 513 | * @param string html The HTML to convert. |
| 514 | * @param int acfBlockVersion The ACF block version number. |
| 515 | * @return object Result of React.createElement(). |
| 516 | */ |
| 517 | acf.parseJSX = (html, acfBlockVersion) => { |
| 518 | // Apply a temporary wrapper for the jQuery parse to prevent text nodes triggering errors. |
| 519 | html = '<div>' + html + '</div>'; |
| 520 | // Correctly balance InnerBlocks tags for jQuery's initial parse. |
| 521 | html = html.replace(/<InnerBlocks([^>]+)?\/>/, '<InnerBlocks$1></InnerBlocks>'); |
| 522 | return parseNode($(html)[0], acfBlockVersion, 0).props.children; |
| 523 | }; |
| 524 | |
| 525 | /** |
| 526 | * Converts a DOM node into a React element. |
| 527 | * |
| 528 | * @date 19/05/2020 |
| 529 | * @since ACF 5.9.0 |
| 530 | * |
| 531 | * @param DOM node The DOM node. |
| 532 | * @param int acfBlockVersion The ACF block version number. |
| 533 | * @param int level The recursion level. |
| 534 | * @return object Result of React.createElement(). |
| 535 | */ |
| 536 | function parseNode(node, acfBlockVersion, level = 0) { |
| 537 | // Get node name. |
| 538 | const nodeName = parseNodeName(node.nodeName.toLowerCase(), acfBlockVersion); |
| 539 | if (!nodeName) { |
| 540 | return null; |
| 541 | } |
| 542 | |
| 543 | // Get node attributes in React friendly format. |
| 544 | const nodeAttrs = {}; |
| 545 | if (level === 1 && nodeName !== 'ACFInnerBlocks') { |
| 546 | // Top level (after stripping away the container div), create a ref for passing through to ACF's JS API. |
| 547 | nodeAttrs.ref = React.createRef(); |
| 548 | } |
| 549 | acf.arrayArgs(node.attributes).map(parseNodeAttr).forEach(({ |
| 550 | name, |
| 551 | value |
| 552 | }) => { |
| 553 | nodeAttrs[name] = value; |
| 554 | }); |
| 555 | if ('ACFInnerBlocks' === nodeName) { |
| 556 | return /*#__PURE__*/React.createElement(ACFInnerBlocks, nodeAttrs); |
| 557 | } |
| 558 | |
| 559 | // Define args for React.createElement(). |
| 560 | const args = [nodeName, nodeAttrs]; |
| 561 | acf.arrayArgs(node.childNodes).forEach(child => { |
| 562 | if (child instanceof Text) { |
| 563 | const text = child.textContent; |
| 564 | if (text) { |
| 565 | args.push(text); |
| 566 | } |
| 567 | } else { |
| 568 | args.push(parseNode(child, acfBlockVersion, level + 1)); |
| 569 | } |
| 570 | }); |
| 571 | |
| 572 | // Return element. |
| 573 | return React.createElement.apply(this, args); |
| 574 | } |
| 575 | |
| 576 | /** |
| 577 | * Converts a node or attribute name into it's JSX compliant name |
| 578 | * |
| 579 | * @date 05/07/2021 |
| 580 | * @since ACF 5.9.8 |
| 581 | * |
| 582 | * @param string name The node or attribute name. |
| 583 | * @return string |
| 584 | */ |
| 585 | function getJSXName(name) { |
| 586 | const replacement = acf.isget(acf, 'jsxNameReplacements', name); |
| 587 | if (replacement) return replacement; |
| 588 | return name; |
| 589 | } |
| 590 | |
| 591 | /** |
| 592 | * A react Component for inline scripts. |
| 593 | * |
| 594 | * This Component uses a combination of React references and jQuery to append the |
| 595 | * inline <script> HTML each time the component is rendered. |
| 596 | * |
| 597 | * @date 29/05/2020 |
| 598 | * @since ACF 5.9.0 |
| 599 | * |
| 600 | * @param type Var Description. |
| 601 | * @return type Description. |
| 602 | */ |
| 603 | class Script extends Component { |
| 604 | render() { |
| 605 | return /*#__PURE__*/React.createElement("div", { |
| 606 | ref: el => this.el = el |
| 607 | }); |
| 608 | } |
| 609 | setHTML(html) { |
| 610 | $(this.el).html(`<script>${html}</script>`); |
| 611 | } |
| 612 | componentDidUpdate() { |
| 613 | this.setHTML(this.props.children); |
| 614 | } |
| 615 | componentDidMount() { |
| 616 | this.setHTML(this.props.children); |
| 617 | } |
| 618 | } |
| 619 | |
| 620 | /** |
| 621 | * Converts the given name into a React friendly name or component. |
| 622 | * |
| 623 | * @date 19/05/2020 |
| 624 | * @since ACF 5.9.0 |
| 625 | * |
| 626 | * @param string name The node name in lowercase. |
| 627 | * @param int acfBlockVersion The ACF block version number. |
| 628 | * @return mixed |
| 629 | */ |
| 630 | function parseNodeName(name, acfBlockVersion) { |
| 631 | switch (name) { |
| 632 | case 'innerblocks': |
| 633 | if (acfBlockVersion < 2) { |
| 634 | return InnerBlocks; |
| 635 | } |
| 636 | return 'ACFInnerBlocks'; |
| 637 | case 'script': |
| 638 | return Script; |
| 639 | case '#comment': |
| 640 | return null; |
| 641 | default: |
| 642 | // Replace names for JSX counterparts. |
| 643 | name = getJSXName(name); |
| 644 | } |
| 645 | return name; |
| 646 | } |
| 647 | |
| 648 | /** |
| 649 | * Functional component for ACFInnerBlocks. |
| 650 | * |
| 651 | * @since ACF 6.0.0 |
| 652 | * |
| 653 | * @param obj props element properties. |
| 654 | * @return DOM element |
| 655 | */ |
| 656 | function ACFInnerBlocks(props) { |
| 657 | const { |
| 658 | className = 'acf-innerblocks-container' |
| 659 | } = props; |
| 660 | const innerBlockProps = useInnerBlocksProps({ |
| 661 | className: className |
| 662 | }, props); |
| 663 | return /*#__PURE__*/React.createElement("div", innerBlockProps, innerBlockProps.children); |
| 664 | } |
| 665 | |
| 666 | /** |
| 667 | * Converts the given attribute into a React friendly name and value object. |
| 668 | * |
| 669 | * @date 19/05/2020 |
| 670 | * @since ACF 5.9.0 |
| 671 | * |
| 672 | * @param obj nodeAttr The node attribute. |
| 673 | * @return obj |
| 674 | */ |
| 675 | function parseNodeAttr(nodeAttr) { |
| 676 | let name = nodeAttr.name; |
| 677 | let value = nodeAttr.value; |
| 678 | |
| 679 | // Allow overrides for third party libraries who might use specific attributes. |
| 680 | let shortcut = acf.applyFilters('acf_blocks_parse_node_attr', false, nodeAttr); |
| 681 | if (shortcut) return shortcut; |
| 682 | switch (name) { |
| 683 | // Class. |
| 684 | case 'class': |
| 685 | name = 'className'; |
| 686 | break; |
| 687 | |
| 688 | // Style. |
| 689 | case 'style': |
| 690 | const css = {}; |
| 691 | value.split(';').forEach(s => { |
| 692 | const pos = s.indexOf(':'); |
| 693 | if (pos > 0) { |
| 694 | let ruleName = s.substr(0, pos).trim(); |
| 695 | const ruleValue = s.substr(pos + 1).trim(); |
| 696 | |
| 697 | // Rename core properties, but not CSS variables. |
| 698 | if (ruleName.charAt(0) !== '-') { |
| 699 | ruleName = acf.strCamelCase(ruleName); |
| 700 | } |
| 701 | css[ruleName] = ruleValue; |
| 702 | } |
| 703 | }); |
| 704 | value = css; |
| 705 | break; |
| 706 | |
| 707 | // Default. |
| 708 | default: |
| 709 | // No formatting needed for "data-x" attributes. |
| 710 | if (name.indexOf('data-') === 0) { |
| 711 | break; |
| 712 | } |
| 713 | |
| 714 | // Replace names for JSX counterparts. |
| 715 | name = getJSXName(name); |
| 716 | |
| 717 | // Convert JSON values. Ignore values that merely start with a |
| 718 | // JSON-like character but aren't valid JSON (e.g. an oEmbed |
| 719 | // title beginning with "[" or "{"). |
| 720 | const c1 = value.charAt(0); |
| 721 | if (c1 === '[' || c1 === '{') { |
| 722 | try { |
| 723 | value = JSON.parse(value); |
| 724 | } catch (err) {} |
| 725 | } |
| 726 | |
| 727 | // Convert bool values. |
| 728 | if (value === 'true' || value === 'false') { |
| 729 | value = value === 'true'; |
| 730 | } |
| 731 | break; |
| 732 | } |
| 733 | return { |
| 734 | name, |
| 735 | value |
| 736 | }; |
| 737 | } |
| 738 | |
| 739 | /** |
| 740 | * Higher Order Component used to set default block attribute values. |
| 741 | * |
| 742 | * By modifying block attributes directly, instead of defining defaults in registerBlockType(), |
| 743 | * WordPress will include them always within the saved block serialized JSON. |
| 744 | * |
| 745 | * @date 31/07/2020 |
| 746 | * @since ACF 5.9.0 |
| 747 | * |
| 748 | * @param Component BlockListBlock The BlockListBlock Component. |
| 749 | * @return Component |
| 750 | */ |
| 751 | const withDefaultAttributes = createHigherOrderComponent(BlockListBlock => class WrappedBlockEdit extends Component { |
| 752 | constructor(props) { |
| 753 | super(props); |
| 754 | |
| 755 | // Extract vars. |
| 756 | const { |
| 757 | name, |
| 758 | attributes |
| 759 | } = this.props; |
| 760 | |
| 761 | // Only run on ACF Blocks. |
| 762 | const blockType = getBlockType(name); |
| 763 | if (!blockType) { |
| 764 | return; |
| 765 | } |
| 766 | |
| 767 | // Check and remove any empty string attributes to match PHP behaviour. |
| 768 | Object.keys(attributes).forEach(key => { |
| 769 | if (attributes[key] === '') { |
| 770 | delete attributes[key]; |
| 771 | } |
| 772 | }); |
| 773 | |
| 774 | // Backward compatibility attribute replacement. |
| 775 | const upgrades = { |
| 776 | full_height: 'fullHeight', |
| 777 | align_content: 'alignContent', |
| 778 | align_text: 'alignText' |
| 779 | }; |
| 780 | Object.keys(upgrades).forEach(key => { |
| 781 | if (attributes[key] !== undefined) { |
| 782 | attributes[upgrades[key]] = attributes[key]; |
| 783 | } else if (attributes[upgrades[key]] === undefined) { |
| 784 | //Check for a default |
| 785 | if (blockType[key] !== undefined) { |
| 786 | attributes[upgrades[key]] = blockType[key]; |
| 787 | } |
| 788 | } |
| 789 | delete blockType[key]; |
| 790 | delete attributes[key]; |
| 791 | }); |
| 792 | |
| 793 | // Set default attributes for those undefined. |
| 794 | for (let attribute in blockType.attributes) { |
| 795 | if (attributes[attribute] === undefined && blockType[attribute] !== undefined) { |
| 796 | attributes[attribute] = blockType[attribute]; |
| 797 | } |
| 798 | } |
| 799 | } |
| 800 | render() { |
| 801 | return /*#__PURE__*/React.createElement(BlockListBlock, this.props); |
| 802 | } |
| 803 | }, 'withDefaultAttributes'); |
| 804 | wp.hooks.addFilter('editor.BlockListBlock', 'acf/with-default-attributes', withDefaultAttributes); |
| 805 | |
| 806 | /** |
| 807 | * The BlockSave functional component. |
| 808 | * |
| 809 | * @date 08/07/2020 |
| 810 | * @since ACF 5.9.0 |
| 811 | */ |
| 812 | function BlockSave() { |
| 813 | return /*#__PURE__*/React.createElement(InnerBlocks.Content, null); |
| 814 | } |
| 815 | |
| 816 | /** |
| 817 | * The BlockEdit component. |
| 818 | * |
| 819 | * @date 19/2/19 |
| 820 | * @since ACF 5.7.12 |
| 821 | */ |
| 822 | class BlockEdit extends Component { |
| 823 | constructor(props) { |
| 824 | super(props); |
| 825 | this.setup(); |
| 826 | } |
| 827 | setup() { |
| 828 | const { |
| 829 | name, |
| 830 | attributes, |
| 831 | clientId |
| 832 | } = this.props; |
| 833 | const blockType = getBlockType(name); |
| 834 | |
| 835 | // Restrict current mode. |
| 836 | function restrictMode(modes) { |
| 837 | if (!modes.includes(attributes.mode)) { |
| 838 | attributes.mode = modes[0]; |
| 839 | } |
| 840 | } |
| 841 | if (isBlockInQueryLoop(clientId) || isSiteEditor()) { |
| 842 | restrictMode(['preview']); |
| 843 | } else { |
| 844 | switch (blockType.mode) { |
| 845 | case 'edit': |
| 846 | restrictMode(['edit', 'preview']); |
| 847 | break; |
| 848 | case 'preview': |
| 849 | restrictMode(['preview', 'edit']); |
| 850 | break; |
| 851 | default: |
| 852 | restrictMode(['auto']); |
| 853 | break; |
| 854 | } |
| 855 | } |
| 856 | } |
| 857 | render() { |
| 858 | const { |
| 859 | name, |
| 860 | attributes, |
| 861 | setAttributes, |
| 862 | clientId |
| 863 | } = this.props; |
| 864 | const blockType = getBlockType(name); |
| 865 | const forcePreview = isBlockInQueryLoop(clientId) || isSiteEditor(); |
| 866 | let { |
| 867 | mode |
| 868 | } = attributes; |
| 869 | if (forcePreview) { |
| 870 | mode = 'preview'; |
| 871 | } |
| 872 | |
| 873 | // Show toggle only for edit/preview modes and for blocks not in a query loop/FSE. |
| 874 | let showToggle = blockType.supports.mode; |
| 875 | if (mode === 'auto' || forcePreview) { |
| 876 | showToggle = false; |
| 877 | } |
| 878 | |
| 879 | // Configure toggle variables. |
| 880 | const toggleText = mode === 'preview' ? acf.__('Switch to Edit') : acf.__('Switch to Preview'); |
| 881 | const toggleIcon = mode === 'preview' ? 'edit' : 'welcome-view-site'; |
| 882 | function toggleMode() { |
| 883 | setAttributes({ |
| 884 | mode: mode === 'preview' ? 'edit' : 'preview' |
| 885 | }); |
| 886 | } |
| 887 | |
| 888 | // Return template. |
| 889 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockControls, null, showToggle && /*#__PURE__*/React.createElement(ToolbarGroup, null, /*#__PURE__*/React.createElement(ToolbarButton, { |
| 890 | className: "components-icon-button components-toolbar__control", |
| 891 | label: toggleText, |
| 892 | icon: toggleIcon, |
| 893 | onClick: toggleMode |
| 894 | }))), /*#__PURE__*/React.createElement(InspectorControls, null, mode === 'preview' && /*#__PURE__*/React.createElement("div", { |
| 895 | className: "acf-block-component acf-block-panel" |
| 896 | }, /*#__PURE__*/React.createElement(BlockForm, this.props))), /*#__PURE__*/React.createElement(BlockBody, this.props)); |
| 897 | } |
| 898 | } |
| 899 | |
| 900 | /** |
| 901 | * The BlockBody functional component. |
| 902 | * |
| 903 | * @since ACF 5.7.12 |
| 904 | */ |
| 905 | function BlockBody(props) { |
| 906 | const { |
| 907 | attributes, |
| 908 | isSelected, |
| 909 | name, |
| 910 | clientId |
| 911 | } = props; |
| 912 | const { |
| 913 | mode |
| 914 | } = attributes; |
| 915 | const index = useSelect(select => { |
| 916 | const rootClientId = select('core/block-editor').getBlockRootClientId(clientId); |
| 917 | return select('core/block-editor').getBlockIndex(clientId, rootClientId); |
| 918 | }); |
| 919 | let showForm = true; |
| 920 | let additionalClasses = 'acf-block-component acf-block-body'; |
| 921 | if (mode === 'auto' && !isSelected || mode === 'preview') { |
| 922 | additionalClasses += ' acf-block-preview'; |
| 923 | showForm = false; |
| 924 | } |
| 925 | |
| 926 | // Setup block cache if required, and update mode. |
| 927 | if (!(clientId in acf.blockInstances)) { |
| 928 | acf.blockInstances[clientId] = { |
| 929 | validation_errors: false, |
| 930 | mode: mode |
| 931 | }; |
| 932 | } |
| 933 | acf.blockInstances[clientId].mode = mode; |
| 934 | if (!isSelected) { |
| 935 | if (blockSupportsValidation(name) && acf.blockInstances[clientId].validation_errors) { |
| 936 | additionalClasses += ' acf-block-has-validation-error'; |
| 937 | } |
| 938 | acf.blockInstances[clientId].has_been_deselected = true; |
| 939 | } |
| 940 | if (getBlockVersion(name) > 1) { |
| 941 | return /*#__PURE__*/React.createElement("div", useBlockProps({ |
| 942 | className: additionalClasses |
| 943 | }), showForm ? /*#__PURE__*/React.createElement(BlockForm, _extends({}, props, { |
| 944 | index: index |
| 945 | })) : /*#__PURE__*/React.createElement(BlockPreview, _extends({}, props, { |
| 946 | index: index |
| 947 | }))); |
| 948 | } else { |
| 949 | return /*#__PURE__*/React.createElement("div", useBlockProps(), /*#__PURE__*/React.createElement("div", { |
| 950 | className: "acf-block-component acf-block-body" |
| 951 | }, showForm ? /*#__PURE__*/React.createElement(BlockForm, _extends({}, props, { |
| 952 | index: index |
| 953 | })) : /*#__PURE__*/React.createElement(BlockPreview, _extends({}, props, { |
| 954 | index: index |
| 955 | })))); |
| 956 | } |
| 957 | } |
| 958 | |
| 959 | /** |
| 960 | * A react component to append HTMl. |
| 961 | * |
| 962 | * @date 19/2/19 |
| 963 | * @since ACF 5.7.12 |
| 964 | * |
| 965 | * @param string children The html to insert. |
| 966 | * @return void |
| 967 | */ |
| 968 | class Div extends Component { |
| 969 | render() { |
| 970 | return /*#__PURE__*/React.createElement("div", { |
| 971 | dangerouslySetInnerHTML: { |
| 972 | __html: this.props.children |
| 973 | } |
| 974 | }); |
| 975 | } |
| 976 | } |
| 977 | |
| 978 | /** |
| 979 | * DynamicHTML Class. |
| 980 | * |
| 981 | * A react componenet to load and insert dynamic HTML. |
| 982 | * |
| 983 | * @date 19/2/19 |
| 984 | * @since ACF 5.7.12 |
| 985 | * |
| 986 | * @param void |
| 987 | * @return void |
| 988 | */ |
| 989 | class DynamicHTML extends Component { |
| 990 | constructor(props) { |
| 991 | super(props); |
| 992 | |
| 993 | // Bind callbacks. |
| 994 | this.setRef = this.setRef.bind(this); |
| 995 | |
| 996 | // Define default props and call setup(). |
| 997 | this.id = ''; |
| 998 | this.el = false; |
| 999 | this.subscribed = true; |
| 1000 | this.renderMethod = 'jQuery'; |
| 1001 | this.passedValidation = false; |
| 1002 | this.setup(props); |
| 1003 | |
| 1004 | // Load state. |
| 1005 | this.loadState(); |
| 1006 | } |
| 1007 | setup(props) { |
| 1008 | const constructor = this.constructor.name; |
| 1009 | const clientId = props.clientId; |
| 1010 | if (!(clientId in acf.blockInstances)) { |
| 1011 | acf.blockInstances[clientId] = { |
| 1012 | validation_errors: false, |
| 1013 | mode: props.mode |
| 1014 | }; |
| 1015 | } |
| 1016 | if (!(constructor in acf.blockInstances[clientId])) { |
| 1017 | acf.blockInstances[clientId][constructor] = {}; |
| 1018 | } |
| 1019 | } |
| 1020 | fetch() { |
| 1021 | // Do nothing. |
| 1022 | } |
| 1023 | maybePreload(blockId, clientId, form) { |
| 1024 | acf.debug('Preload check', blockId, clientId, form); |
| 1025 | |
| 1026 | // Early return if block is in query loop. |
| 1027 | if (isBlockInQueryLoop(this.props.clientId)) { |
| 1028 | acf.debug('Preload failed: Block is in query loop.'); |
| 1029 | return false; |
| 1030 | } |
| 1031 | const preloadedBlocks = acf.get('preloadedBlocks'); |
| 1032 | |
| 1033 | // Early return if no preloaded blocks exist. |
| 1034 | if (!preloadedBlocks || !preloadedBlocks[blockId]) { |
| 1035 | acf.debug('Preload failed: Block not preloaded.'); |
| 1036 | return false; |
| 1037 | } |
| 1038 | |
| 1039 | // Create a copy to avoid mutating the original preloaded data. |
| 1040 | const preloadedBlock = { |
| 1041 | ...preloadedBlocks[blockId] |
| 1042 | }; |
| 1043 | |
| 1044 | // Ensure we only preload the correct block state (form or preview). |
| 1045 | if (form && !preloadedBlock.form || !form && preloadedBlock.form) { |
| 1046 | acf.debug('Preload failed: Correct state not preloaded.', form ? 'form' : 'preview'); |
| 1047 | return false; |
| 1048 | } |
| 1049 | |
| 1050 | // Replace blockId with clientId in HTML. |
| 1051 | preloadedBlock.html = preloadedBlock.html.replaceAll(blockId, clientId); |
| 1052 | |
| 1053 | // Replace blockId in validation errors. |
| 1054 | if (preloadedBlock.validation && preloadedBlock.validation.errors) { |
| 1055 | preloadedBlock.validation.errors = preloadedBlock.validation.errors.map(error => { |
| 1056 | error.input = error.input.replaceAll(blockId, clientId); |
| 1057 | return error; |
| 1058 | }); |
| 1059 | } |
| 1060 | |
| 1061 | // Return preloaded object. |
| 1062 | acf.debug('Preload successful', preloadedBlock); |
| 1063 | return preloadedBlock; |
| 1064 | } |
| 1065 | loadState() { |
| 1066 | const client = acf.blockInstances[this.props.clientId] || {}; |
| 1067 | this.state = client[this.constructor.name] || {}; |
| 1068 | } |
| 1069 | setState(state) { |
| 1070 | acf.blockInstances[this.props.clientId][this.constructor.name] = { |
| 1071 | ...this.state, |
| 1072 | ...state |
| 1073 | }; |
| 1074 | |
| 1075 | // Update component state if subscribed. |
| 1076 | // - Allows AJAX callback to update store without modifying state of an unmounted component. |
| 1077 | if (this.subscribed || acf.get('StrictMode')) { |
| 1078 | super.setState(state); |
| 1079 | } |
| 1080 | acf.debug('SetState', Object.assign({}, this), this.props.clientId, this.constructor.name, Object.assign({}, acf.blockInstances[this.props.clientId][this.constructor.name])); |
| 1081 | } |
| 1082 | setHtml(html) { |
| 1083 | html = html ? html.trim() : ''; |
| 1084 | |
| 1085 | // Bail early if html has not changed. |
| 1086 | if (html === this.state.html) { |
| 1087 | return; |
| 1088 | } |
| 1089 | |
| 1090 | // Update state. |
| 1091 | const state = { |
| 1092 | html |
| 1093 | }; |
| 1094 | if (this.renderMethod === 'jsx') { |
| 1095 | state.jsx = acf.parseJSX(html, getBlockVersion(this.props.name)); |
| 1096 | |
| 1097 | // Handle templates which don't contain any valid JSX parsable elements. |
| 1098 | if (!state.jsx) { |
| 1099 | console.warn('Your ACF block template contains no valid HTML elements. Appending a empty div to prevent React JS errors.'); |
| 1100 | state.html += '<div></div>'; |
| 1101 | state.jsx = acf.parseJSX(state.html, getBlockVersion(this.props.name)); |
| 1102 | } |
| 1103 | |
| 1104 | // If we've got an object (as an array) find the first valid React ref. |
| 1105 | if (Array.isArray(state.jsx)) { |
| 1106 | let refElement = state.jsx.find(element => React.isValidElement(element)); |
| 1107 | state.ref = refElement.ref; |
| 1108 | } else { |
| 1109 | state.ref = state.jsx.ref; |
| 1110 | } |
| 1111 | state.$el = $(this.el); |
| 1112 | } else { |
| 1113 | state.$el = $(html); |
| 1114 | } |
| 1115 | this.setState(state); |
| 1116 | } |
| 1117 | setRef(el) { |
| 1118 | this.el = el; |
| 1119 | } |
| 1120 | render() { |
| 1121 | // Render JSX. |
| 1122 | if (this.state.jsx) { |
| 1123 | // If we're a v2+ block, use the jsx element itself as our ref. |
| 1124 | if (getBlockVersion(this.props.name) > 1) { |
| 1125 | this.setRef(this.state.jsx); |
| 1126 | return this.state.jsx; |
| 1127 | } else { |
| 1128 | return /*#__PURE__*/React.createElement("div", { |
| 1129 | ref: this.setRef |
| 1130 | }, this.state.jsx); |
| 1131 | } |
| 1132 | } |
| 1133 | |
| 1134 | // Return HTML. |
| 1135 | return /*#__PURE__*/React.createElement("div", { |
| 1136 | ref: this.setRef |
| 1137 | }, /*#__PURE__*/React.createElement(Placeholder, null, /*#__PURE__*/React.createElement(Spinner, null))); |
| 1138 | } |
| 1139 | shouldComponentUpdate({ |
| 1140 | index |
| 1141 | }, { |
| 1142 | html |
| 1143 | }) { |
| 1144 | if (index !== this.props.index) { |
| 1145 | this.componentWillMove(); |
| 1146 | } |
| 1147 | return html !== this.state.html; |
| 1148 | } |
| 1149 | display(context) { |
| 1150 | // This method is called after setting new HTML and the Component render. |
| 1151 | // The jQuery render method simply needs to move $el into place. |
| 1152 | if (this.renderMethod === 'jQuery') { |
| 1153 | const $el = this.state.$el; |
| 1154 | const $prevParent = $el.parent(); |
| 1155 | const $thisParent = $(this.el); |
| 1156 | |
| 1157 | // Move $el into place. |
| 1158 | // Skip this in StrictMode unless context is 'append' or component is subscribed. |
| 1159 | if (!(acf.get('StrictMode') && context !== 'append' && !this.subscribed)) { |
| 1160 | $thisParent.html($el); |
| 1161 | } |
| 1162 | |
| 1163 | // Special case for reusable blocks. |
| 1164 | // Multiple instances of the same reusable block share the same block id. |
| 1165 | // This causes all instances to share the same state (cool), which unfortunately |
| 1166 | // pulls $el back and forth between the last rendered reusable block. |
| 1167 | // This simple fix leaves a "clone" behind :) |
| 1168 | if ($prevParent.length && $prevParent[0] !== $thisParent[0]) { |
| 1169 | $prevParent.html($el.clone()); |
| 1170 | } |
| 1171 | } |
| 1172 | |
| 1173 | // Lock block if required. |
| 1174 | if (this.getValidationErrors() && this.isNotNewlyAdded()) { |
| 1175 | this.lockBlockForSaving(); |
| 1176 | } else { |
| 1177 | this.unlockBlockForSaving(); |
| 1178 | } |
| 1179 | |
| 1180 | // Call context specific method. |
| 1181 | switch (context) { |
| 1182 | case 'append': |
| 1183 | this.componentDidAppend(); |
| 1184 | break; |
| 1185 | case 'remount': |
| 1186 | this.componentDidRemount(); |
| 1187 | break; |
| 1188 | } |
| 1189 | } |
| 1190 | validate() { |
| 1191 | // Do nothing. |
| 1192 | } |
| 1193 | componentDidMount() { |
| 1194 | // Fetch on first load. |
| 1195 | if (this.state.html === undefined) { |
| 1196 | this.fetch(); |
| 1197 | |
| 1198 | // Or remount existing HTML. |
| 1199 | } else { |
| 1200 | this.display('remount'); |
| 1201 | } |
| 1202 | } |
| 1203 | componentDidUpdate(prevProps, prevState) { |
| 1204 | // HTML has changed. |
| 1205 | this.display('append'); |
| 1206 | } |
| 1207 | componentDidAppend() { |
| 1208 | acf.doAction('append', this.state.$el); |
| 1209 | } |
| 1210 | componentWillUnmount() { |
| 1211 | // Only skip unmount action if in StrictMode AND component is not subscribed |
| 1212 | if (!acf.get('StrictMode') || this.subscribed) { |
| 1213 | acf.doAction('unmount', this.state.$el); |
| 1214 | } |
| 1215 | |
| 1216 | // Unsubscribe this component from state |
| 1217 | this.subscribed = false; |
| 1218 | } |
| 1219 | componentDidRemount() { |
| 1220 | this.subscribed = true; |
| 1221 | |
| 1222 | // Use setTimeout to avoid incorrect timing of events. |
| 1223 | // React will unmount and mount components in DOM order. |
| 1224 | // This means a new component can be mounted before an old one is unmounted. |
| 1225 | // ACF shares $el across new/old components which is un-React-like. |
| 1226 | // This timout ensures that unmounting occurs before remounting. |
| 1227 | setTimeout(() => { |
| 1228 | acf.doAction('remount', this.state.$el); |
| 1229 | }); |
| 1230 | } |
| 1231 | componentWillMove() { |
| 1232 | acf.doAction('unmount', this.state.$el); |
| 1233 | setTimeout(() => { |
| 1234 | acf.doAction('remount', this.state.$el); |
| 1235 | }); |
| 1236 | } |
| 1237 | isNotNewlyAdded() { |
| 1238 | return acf.blockInstances[this.props.clientId].has_been_deselected || false; |
| 1239 | } |
| 1240 | hasShownValidation() { |
| 1241 | return acf.blockInstances[this.props.clientId].shown_validation || false; |
| 1242 | } |
| 1243 | setShownValidation() { |
| 1244 | acf.blockInstances[this.props.clientId].shown_validation = true; |
| 1245 | } |
| 1246 | setValidationErrors(errors) { |
| 1247 | acf.blockInstances[this.props.clientId].validation_errors = errors; |
| 1248 | } |
| 1249 | getValidationErrors() { |
| 1250 | return acf.blockInstances[this.props.clientId].validation_errors; |
| 1251 | } |
| 1252 | getMode() { |
| 1253 | return acf.blockInstances[this.props.clientId].mode; |
| 1254 | } |
| 1255 | lockBlockForSaving() { |
| 1256 | if (!wp.data.dispatch('core/editor')) return; |
| 1257 | wp.data.dispatch('core/editor').lockPostSaving('acf/block/' + this.props.clientId); |
| 1258 | } |
| 1259 | unlockBlockForSaving() { |
| 1260 | if (!wp.data.dispatch('core/editor')) return; |
| 1261 | wp.data.dispatch('core/editor').unlockPostSaving('acf/block/' + this.props.clientId); |
| 1262 | } |
| 1263 | displayValidation($formEl) { |
| 1264 | if (!blockSupportsValidation(this.props.name)) { |
| 1265 | acf.debug('Block does not support validation'); |
| 1266 | return; |
| 1267 | } |
| 1268 | if (!$formEl || $formEl.hasClass('acf-empty-block-fields')) { |
| 1269 | acf.debug('There is no edit form available to validate.'); |
| 1270 | return; |
| 1271 | } |
| 1272 | const errors = this.getValidationErrors(); |
| 1273 | acf.debug('Starting handle validation', Object.assign({}, this), Object.assign({}, $formEl), errors); |
| 1274 | this.setShownValidation(); |
| 1275 | let validator = acf.getBlockFormValidator($formEl); |
| 1276 | validator.clearErrors(); |
| 1277 | acf.doAction('blocks/validation/pre_apply', errors); |
| 1278 | if (errors) { |
| 1279 | validator.addErrors(errors); |
| 1280 | validator.showErrors('after'); |
| 1281 | this.lockBlockForSaving(); |
| 1282 | } else { |
| 1283 | // remove previous error message |
| 1284 | if (validator.has('notice')) { |
| 1285 | validator.get('notice').update({ |
| 1286 | type: 'success', |
| 1287 | text: acf.__('Validation successful'), |
| 1288 | timeout: 1000 |
| 1289 | }); |
| 1290 | validator.set('notice', null); |
| 1291 | } |
| 1292 | this.unlockBlockForSaving(); |
| 1293 | } |
| 1294 | acf.doAction('blocks/validation/post_apply', errors); |
| 1295 | } |
| 1296 | } |
| 1297 | |
| 1298 | /** |
| 1299 | * BlockForm Class. |
| 1300 | * |
| 1301 | * A react componenet to handle the block form. |
| 1302 | * |
| 1303 | * @date 19/2/19 |
| 1304 | * @since ACF 5.7.12 |
| 1305 | * |
| 1306 | * @param string id the block id. |
| 1307 | * @return void |
| 1308 | */ |
| 1309 | class BlockForm extends DynamicHTML { |
| 1310 | setup(props) { |
| 1311 | this.id = `BlockForm-${props.clientId}`; |
| 1312 | super.setup(props); |
| 1313 | } |
| 1314 | fetch(validate_only = false, data = false) { |
| 1315 | // Extract props. |
| 1316 | const { |
| 1317 | context, |
| 1318 | clientId, |
| 1319 | name |
| 1320 | } = this.props; |
| 1321 | let { |
| 1322 | attributes |
| 1323 | } = this.props; |
| 1324 | let query = { |
| 1325 | form: true |
| 1326 | }; |
| 1327 | if (validate_only) { |
| 1328 | query = { |
| 1329 | validate: true |
| 1330 | }; |
| 1331 | attributes.data = data; |
| 1332 | } |
| 1333 | const hash = createBlockAttributesHash(attributes, context); |
| 1334 | acf.debug('BlockForm fetch', attributes, query); |
| 1335 | |
| 1336 | // Try preloaded data first. |
| 1337 | const preloaded = this.maybePreload(hash, clientId, true); |
| 1338 | if (preloaded) { |
| 1339 | this.setHtml(acf.applyFilters('blocks/form/render', preloaded.html, true)); |
| 1340 | if (preloaded.validation) this.setValidationErrors(preloaded.validation.errors); |
| 1341 | return; |
| 1342 | } |
| 1343 | if (!blockSupportsValidation(name)) { |
| 1344 | query.validate = false; |
| 1345 | } |
| 1346 | |
| 1347 | // Request AJAX and update HTML on complete. |
| 1348 | fetchBlock({ |
| 1349 | attributes, |
| 1350 | context, |
| 1351 | clientId, |
| 1352 | query |
| 1353 | }).done(({ |
| 1354 | data |
| 1355 | }) => { |
| 1356 | acf.debug('fetch block form promise'); |
| 1357 | if (!data) { |
| 1358 | this.setHtml(`<div class="acf-block-fields acf-fields acf-empty-block-fields">${acf.__('Error loading block form')}</div>`); |
| 1359 | return; |
| 1360 | } |
| 1361 | if (data.form) { |
| 1362 | this.setHtml(acf.applyFilters('blocks/form/render', data.form.replaceAll(data.clientId, clientId), false)); |
| 1363 | } |
| 1364 | if (data.validation) this.setValidationErrors(data.validation.errors); |
| 1365 | if (this.isNotNewlyAdded()) { |
| 1366 | acf.debug("Block has already shown it's invalid. The form needs to show validation errors"); |
| 1367 | this.validate(); |
| 1368 | } |
| 1369 | }); |
| 1370 | } |
| 1371 | validate(loadState = true) { |
| 1372 | if (loadState) { |
| 1373 | this.loadState(); |
| 1374 | } |
| 1375 | acf.debug('BlockForm calling validate with state', Object.assign({}, this)); |
| 1376 | super.displayValidation(this.state.$el); |
| 1377 | } |
| 1378 | shouldComponentUpdate(nextProps, nextState) { |
| 1379 | if (blockSupportsValidation(this.props.name) && this.state.$el && this.isNotNewlyAdded() && !this.hasShownValidation()) { |
| 1380 | this.validate(false); // Shouldn't update state in shouldComponentUpdate. |
| 1381 | } |
| 1382 | return super.shouldComponentUpdate(nextProps, nextState); |
| 1383 | } |
| 1384 | componentWillUnmount() { |
| 1385 | super.componentWillUnmount(); |
| 1386 | |
| 1387 | //TODO: either delete this, or clear validations here (if that's a sensible idea) |
| 1388 | |
| 1389 | acf.debug('BlockForm Component did unmount'); |
| 1390 | } |
| 1391 | componentDidRemount() { |
| 1392 | super.componentDidRemount(); |
| 1393 | acf.debug('BlockForm component did remount'); |
| 1394 | const { |
| 1395 | $el |
| 1396 | } = this.state; |
| 1397 | if (blockSupportsValidation(this.props.name) && this.isNotNewlyAdded()) { |
| 1398 | acf.debug("Block has already shown it's invalid. The form needs to show validation errors"); |
| 1399 | this.validate(); |
| 1400 | } |
| 1401 | |
| 1402 | // Make sure our on append events are registered. |
| 1403 | if ($el.data('acf-events-added') !== true) { |
| 1404 | this.componentDidAppend(); |
| 1405 | } |
| 1406 | } |
| 1407 | componentDidAppend() { |
| 1408 | super.componentDidAppend(); |
| 1409 | acf.debug('BlockForm component did append'); |
| 1410 | |
| 1411 | // Extract props. |
| 1412 | const { |
| 1413 | attributes, |
| 1414 | setAttributes, |
| 1415 | clientId, |
| 1416 | name |
| 1417 | } = this.props; |
| 1418 | const thisBlockForm = this; |
| 1419 | const { |
| 1420 | $el |
| 1421 | } = this.state; |
| 1422 | |
| 1423 | // Callback for updating block data and validation status if we're in an edit only mode. |
| 1424 | function serializeData(silent = false) { |
| 1425 | const data = acf.serialize($el, `acf-block_${clientId}`); |
| 1426 | if (silent) { |
| 1427 | attributes.data = data; |
| 1428 | } else { |
| 1429 | setAttributes({ |
| 1430 | data |
| 1431 | }); |
| 1432 | } |
| 1433 | if (blockSupportsValidation(name) && !silent && thisBlockForm.getMode() === 'edit') { |
| 1434 | acf.debug('No block preview currently available. Need to trigger a validation only fetch.'); |
| 1435 | thisBlockForm.fetch(true, data); |
| 1436 | } |
| 1437 | } |
| 1438 | |
| 1439 | // Add events. |
| 1440 | let timeout = false; |
| 1441 | $el.on('change keyup', () => { |
| 1442 | clearTimeout(timeout); |
| 1443 | timeout = setTimeout(serializeData, 300); |
| 1444 | }); |
| 1445 | |
| 1446 | // Log initialization for remount check on the persistent element. |
| 1447 | $el.data('acf-events-added', true); |
| 1448 | |
| 1449 | // Ensure newly added block is saved with data. |
| 1450 | // Do it silently to avoid triggering a preview render. |
| 1451 | if (!attributes.data) { |
| 1452 | serializeData(true); |
| 1453 | } |
| 1454 | } |
| 1455 | } |
| 1456 | |
| 1457 | /** |
| 1458 | * BlockPreview Class. |
| 1459 | * |
| 1460 | * A react componenet to handle the block preview. |
| 1461 | * |
| 1462 | * @date 19/2/19 |
| 1463 | * @since ACF 5.7.12 |
| 1464 | * |
| 1465 | * @param string id the block id. |
| 1466 | * @return void |
| 1467 | */ |
| 1468 | class BlockPreview extends DynamicHTML { |
| 1469 | setup(props) { |
| 1470 | const blockType = getBlockType(props.name); |
| 1471 | const contextPostId = acf.isget(this.props, 'context', 'postId'); |
| 1472 | this.id = `BlockPreview-${props.clientId}`; |
| 1473 | super.setup(props); |
| 1474 | |
| 1475 | // Apply the contextPostId to the ID if set to stop query loop ID duplication. |
| 1476 | if (contextPostId) { |
| 1477 | this.id = `BlockPreview-${props.clientId}-${contextPostId}`; |
| 1478 | } |
| 1479 | if (blockType.supports.jsx) { |
| 1480 | this.renderMethod = 'jsx'; |
| 1481 | } |
| 1482 | } |
| 1483 | fetch(args = {}) { |
| 1484 | const { |
| 1485 | attributes = this.props.attributes, |
| 1486 | clientId = this.props.clientId, |
| 1487 | context = this.props.context, |
| 1488 | delay = 0 |
| 1489 | } = args; |
| 1490 | const { |
| 1491 | name |
| 1492 | } = this.props; |
| 1493 | |
| 1494 | // Remember attributes used to fetch HTML. |
| 1495 | this.setState({ |
| 1496 | prevAttributes: attributes, |
| 1497 | prevContext: context |
| 1498 | }); |
| 1499 | const hash = createBlockAttributesHash(attributes, context); |
| 1500 | |
| 1501 | // Try preloaded data first. |
| 1502 | let preloaded = this.maybePreload(hash, clientId, false); |
| 1503 | if (preloaded) { |
| 1504 | if (getBlockVersion(name) == 1) { |
| 1505 | preloaded.html = '<div class="acf-block-preview">' + preloaded.html + '</div>'; |
| 1506 | } |
| 1507 | this.setHtml(acf.applyFilters('blocks/preview/render', preloaded.html, true)); |
| 1508 | if (preloaded.validation) this.setValidationErrors(preloaded.validation.errors); |
| 1509 | return; |
| 1510 | } |
| 1511 | let query = { |
| 1512 | preview: true |
| 1513 | }; |
| 1514 | if (!blockSupportsValidation(name)) { |
| 1515 | query.validate = false; |
| 1516 | } |
| 1517 | |
| 1518 | // Request AJAX and update HTML on complete. |
| 1519 | fetchBlock({ |
| 1520 | attributes, |
| 1521 | context, |
| 1522 | clientId, |
| 1523 | query, |
| 1524 | delay |
| 1525 | }).done(({ |
| 1526 | data |
| 1527 | }) => { |
| 1528 | if (!data) { |
| 1529 | this.setHtml(`<div class="acf-block-fields acf-fields acf-empty-block-fields">${acf.__('Error previewing block')}</div>`); |
| 1530 | return; |
| 1531 | } |
| 1532 | let replaceHtml = data.preview.replaceAll(data.clientId, clientId); |
| 1533 | if (getBlockVersion(name) == 1) { |
| 1534 | replaceHtml = '<div class="acf-block-preview">' + replaceHtml + '</div>'; |
| 1535 | } |
| 1536 | acf.debug('fetch block render promise'); |
| 1537 | this.setHtml(acf.applyFilters('blocks/preview/render', replaceHtml, false)); |
| 1538 | if (data.validation) { |
| 1539 | this.setValidationErrors(data.validation.errors); |
| 1540 | } |
| 1541 | if (this.isNotNewlyAdded()) { |
| 1542 | this.validate(); |
| 1543 | } |
| 1544 | }); |
| 1545 | } |
| 1546 | validate() { |
| 1547 | // Check we've got a block form for this instance. |
| 1548 | const client = acf.blockInstances[this.props.clientId] || {}; |
| 1549 | const blockFormState = client.BlockForm || false; |
| 1550 | if (blockFormState) { |
| 1551 | super.displayValidation(blockFormState.$el); |
| 1552 | } |
| 1553 | } |
| 1554 | componentDidAppend() { |
| 1555 | super.componentDidAppend(); |
| 1556 | this.renderBlockPreviewEvent(); |
| 1557 | } |
| 1558 | shouldComponentUpdate(nextProps, nextState) { |
| 1559 | const nextAttributes = nextProps.attributes; |
| 1560 | const thisAttributes = this.props.attributes; |
| 1561 | |
| 1562 | // Update preview if block data has changed. |
| 1563 | if (!compareObjects(nextAttributes, thisAttributes) || !compareObjects(nextProps.context, this.props.context)) { |
| 1564 | let delay = 0; |
| 1565 | |
| 1566 | // Delay fetch when editing className or anchor to simulate consistent logic to custom fields. |
| 1567 | if (nextAttributes.className !== thisAttributes.className) { |
| 1568 | delay = 300; |
| 1569 | } |
| 1570 | if (nextAttributes.anchor !== thisAttributes.anchor) { |
| 1571 | delay = 300; |
| 1572 | } |
| 1573 | acf.debug('Triggering fetch from block preview shouldComponentUpdate'); |
| 1574 | this.fetch({ |
| 1575 | attributes: nextAttributes, |
| 1576 | context: nextProps.context, |
| 1577 | delay |
| 1578 | }); |
| 1579 | } |
| 1580 | return super.shouldComponentUpdate(nextProps, nextState); |
| 1581 | } |
| 1582 | renderBlockPreviewEvent() { |
| 1583 | // Extract props. |
| 1584 | const { |
| 1585 | attributes, |
| 1586 | name |
| 1587 | } = this.props; |
| 1588 | const { |
| 1589 | $el, |
| 1590 | ref |
| 1591 | } = this.state; |
| 1592 | var blockElement; |
| 1593 | |
| 1594 | // Generate action friendly type. |
| 1595 | const type = attributes.name.replace('acf/', ''); |
| 1596 | if (ref && ref.current) { |
| 1597 | // We've got a react ref from a JSX container. Use the parent as the blockElement |
| 1598 | blockElement = $(ref.current).parent(); |
| 1599 | } else if (getBlockVersion(name) == 1) { |
| 1600 | blockElement = $el; |
| 1601 | } else { |
| 1602 | blockElement = $el.parents('.acf-block-preview'); |
| 1603 | } |
| 1604 | |
| 1605 | // Do action. |
| 1606 | acf.doAction('render_block_preview', blockElement, attributes); |
| 1607 | acf.doAction(`render_block_preview/type=${type}`, blockElement, attributes); |
| 1608 | } |
| 1609 | componentDidRemount() { |
| 1610 | super.componentDidRemount(); |
| 1611 | acf.debug('Checking if fetch is required in BlockPreview componentDidRemount', Object.assign({}, this.state.prevAttributes), Object.assign({}, this.props.attributes), Object.assign({}, this.state.prevContext), Object.assign({}, this.props.context)); |
| 1612 | |
| 1613 | // Update preview if data has changed since last render (changing from "edit" to "preview"). |
| 1614 | if (!compareObjects(this.state.prevAttributes, this.props.attributes) || !compareObjects(this.state.prevContext, this.props.context)) { |
| 1615 | acf.debug('Triggering block preview fetch from componentDidRemount'); |
| 1616 | this.fetch(); |
| 1617 | } |
| 1618 | |
| 1619 | // Fire the block preview event so blocks can reinit JS elements. |
| 1620 | // React reusing DOM elements covers any potential race condition from the above fetch. |
| 1621 | this.renderBlockPreviewEvent(); |
| 1622 | } |
| 1623 | } |
| 1624 | |
| 1625 | /** |
| 1626 | * Initializes ACF Blocks logic and registration. |
| 1627 | * |
| 1628 | * @since ACF 5.9.0 |
| 1629 | */ |
| 1630 | function initialize() { |
| 1631 | // Add support for WordPress versions before 5.2. |
| 1632 | if (!wp.blockEditor) { |
| 1633 | wp.blockEditor = wp.editor; |
| 1634 | } |
| 1635 | |
| 1636 | // Register block types. |
| 1637 | const blockTypes = acf.get('blockTypes'); |
| 1638 | if (blockTypes) { |
| 1639 | // Only register blocks with version <= 2 (v3+ blocks are registered separately). |
| 1640 | blockTypes.forEach(blockType => { |
| 1641 | parseInt(blockType.acf_block_version) <= 2 && registerBlockType(blockType); |
| 1642 | }); |
| 1643 | } |
| 1644 | } |
| 1645 | |
| 1646 | // Run the initialize callback during the "prepare" action. |
| 1647 | // This ensures that all localized data is available and that blocks are registered before the WP editor has been instantiated. |
| 1648 | acf.addAction('prepare', initialize); |
| 1649 | |
| 1650 | /** |
| 1651 | * Returns a valid vertical alignment. |
| 1652 | * |
| 1653 | * @date 07/08/2020 |
| 1654 | * @since ACF 5.9.0 |
| 1655 | * |
| 1656 | * @param string align A vertical alignment. |
| 1657 | * @return string |
| 1658 | */ |
| 1659 | function validateVerticalAlignment(align) { |
| 1660 | const ALIGNMENTS = ['top', 'center', 'bottom']; |
| 1661 | const DEFAULT = 'top'; |
| 1662 | return ALIGNMENTS.includes(align) ? align : DEFAULT; |
| 1663 | } |
| 1664 | |
| 1665 | /** |
| 1666 | * Returns a valid horizontal alignment. |
| 1667 | * |
| 1668 | * @date 07/08/2020 |
| 1669 | * @since ACF 5.9.0 |
| 1670 | * |
| 1671 | * @param string align A horizontal alignment. |
| 1672 | * @return string |
| 1673 | */ |
| 1674 | function validateHorizontalAlignment(align) { |
| 1675 | const ALIGNMENTS = ['left', 'center', 'right']; |
| 1676 | const DEFAULT = acf.get('rtl') ? 'right' : 'left'; |
| 1677 | return ALIGNMENTS.includes(align) ? align : DEFAULT; |
| 1678 | } |
| 1679 | |
| 1680 | /** |
| 1681 | * Returns a valid matrix alignment. |
| 1682 | * |
| 1683 | * Written for "upgrade-path" compatibility from vertical alignment to matrix alignment. |
| 1684 | * |
| 1685 | * @date 07/08/2020 |
| 1686 | * @since ACF 5.9.0 |
| 1687 | * |
| 1688 | * @param string align A matrix alignment. |
| 1689 | * @return string |
| 1690 | */ |
| 1691 | function validateMatrixAlignment(align) { |
| 1692 | const DEFAULT = 'center center'; |
| 1693 | if (align) { |
| 1694 | const [y, x] = align.split(' '); |
| 1695 | return `${validateVerticalAlignment(y)} ${validateHorizontalAlignment(x)}`; |
| 1696 | } |
| 1697 | return DEFAULT; |
| 1698 | } |
| 1699 | |
| 1700 | /** |
| 1701 | * A higher order component adding alignContent editing functionality. |
| 1702 | * |
| 1703 | * @date 08/07/2020 |
| 1704 | * @since ACF 5.9.0 |
| 1705 | * |
| 1706 | * @param component OriginalBlockEdit The original BlockEdit component. |
| 1707 | * @param object blockType The block type settings. |
| 1708 | * @return component |
| 1709 | */ |
| 1710 | function withAlignContentComponent(OriginalBlockEdit, blockType) { |
| 1711 | // Determine alignment vars |
| 1712 | let type = blockType.supports.align_content || blockType.supports.alignContent; |
| 1713 | let AlignmentComponent; |
| 1714 | let validateAlignment; |
| 1715 | switch (type) { |
| 1716 | case 'matrix': |
| 1717 | AlignmentComponent = BlockAlignmentMatrixControl || BlockAlignmentMatrixToolbar; |
| 1718 | validateAlignment = validateMatrixAlignment; |
| 1719 | break; |
| 1720 | default: |
| 1721 | AlignmentComponent = BlockVerticalAlignmentToolbar; |
| 1722 | validateAlignment = validateVerticalAlignment; |
| 1723 | break; |
| 1724 | } |
| 1725 | |
| 1726 | // Ensure alignment component exists. |
| 1727 | if (AlignmentComponent === undefined) { |
| 1728 | console.warn(`The "${type}" alignment component was not found.`); |
| 1729 | return OriginalBlockEdit; |
| 1730 | } |
| 1731 | |
| 1732 | // Ensure correct block attribute data is sent in intial preview AJAX request. |
| 1733 | blockType.alignContent = validateAlignment(blockType.alignContent); |
| 1734 | |
| 1735 | // Return wrapped component. |
| 1736 | return class WrappedBlockEdit extends Component { |
| 1737 | render() { |
| 1738 | const { |
| 1739 | attributes, |
| 1740 | setAttributes |
| 1741 | } = this.props; |
| 1742 | const { |
| 1743 | alignContent |
| 1744 | } = attributes; |
| 1745 | function onChangeAlignContent(alignContent) { |
| 1746 | setAttributes({ |
| 1747 | alignContent: validateAlignment(alignContent) |
| 1748 | }); |
| 1749 | } |
| 1750 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockControls, { |
| 1751 | group: "block" |
| 1752 | }, /*#__PURE__*/React.createElement(AlignmentComponent, { |
| 1753 | label: acf.__('Change content alignment'), |
| 1754 | value: validateAlignment(alignContent), |
| 1755 | onChange: onChangeAlignContent |
| 1756 | })), /*#__PURE__*/React.createElement(OriginalBlockEdit, this.props)); |
| 1757 | } |
| 1758 | }; |
| 1759 | } |
| 1760 | |
| 1761 | /** |
| 1762 | * A higher order component adding alignText editing functionality. |
| 1763 | * |
| 1764 | * @date 08/07/2020 |
| 1765 | * @since ACF 5.9.0 |
| 1766 | * |
| 1767 | * @param component OriginalBlockEdit The original BlockEdit component. |
| 1768 | * @param object blockType The block type settings. |
| 1769 | * @return component |
| 1770 | */ |
| 1771 | function withAlignTextComponent(OriginalBlockEdit, blockType) { |
| 1772 | const validateAlignment = validateHorizontalAlignment; |
| 1773 | |
| 1774 | // Ensure correct block attribute data is sent in intial preview AJAX request. |
| 1775 | blockType.alignText = validateAlignment(blockType.alignText); |
| 1776 | |
| 1777 | // Return wrapped component. |
| 1778 | return class WrappedBlockEdit extends Component { |
| 1779 | render() { |
| 1780 | const { |
| 1781 | attributes, |
| 1782 | setAttributes |
| 1783 | } = this.props; |
| 1784 | const { |
| 1785 | alignText |
| 1786 | } = attributes; |
| 1787 | function onChangeAlignText(alignText) { |
| 1788 | setAttributes({ |
| 1789 | alignText: validateAlignment(alignText) |
| 1790 | }); |
| 1791 | } |
| 1792 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockControls, { |
| 1793 | group: "block" |
| 1794 | }, /*#__PURE__*/React.createElement(AlignmentToolbar, { |
| 1795 | value: validateAlignment(alignText), |
| 1796 | onChange: onChangeAlignText |
| 1797 | })), /*#__PURE__*/React.createElement(OriginalBlockEdit, this.props)); |
| 1798 | } |
| 1799 | }; |
| 1800 | } |
| 1801 | |
| 1802 | /** |
| 1803 | * A higher order component adding full height support. |
| 1804 | * |
| 1805 | * @date 19/07/2021 |
| 1806 | * @since ACF 5.10.0 |
| 1807 | * |
| 1808 | * @param component OriginalBlockEdit The original BlockEdit component. |
| 1809 | * @param object blockType The block type settings. |
| 1810 | * @return component |
| 1811 | */ |
| 1812 | function withFullHeightComponent(OriginalBlockEdit, blockType) { |
| 1813 | if (!BlockFullHeightAlignmentControl) return OriginalBlockEdit; |
| 1814 | |
| 1815 | // Return wrapped component. |
| 1816 | return class WrappedBlockEdit extends Component { |
| 1817 | render() { |
| 1818 | const { |
| 1819 | attributes, |
| 1820 | setAttributes |
| 1821 | } = this.props; |
| 1822 | const { |
| 1823 | fullHeight |
| 1824 | } = attributes; |
| 1825 | function onToggleFullHeight(fullHeight) { |
| 1826 | setAttributes({ |
| 1827 | fullHeight |
| 1828 | }); |
| 1829 | } |
| 1830 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockControls, { |
| 1831 | group: "block" |
| 1832 | }, /*#__PURE__*/React.createElement(BlockFullHeightAlignmentControl, { |
| 1833 | isActive: fullHeight, |
| 1834 | onToggle: onToggleFullHeight |
| 1835 | })), /*#__PURE__*/React.createElement(OriginalBlockEdit, this.props)); |
| 1836 | } |
| 1837 | }; |
| 1838 | } |
| 1839 | |
| 1840 | /** |
| 1841 | * Appends a backwards compatibility attribute for conversion. |
| 1842 | * |
| 1843 | * @since ACF 6.0 |
| 1844 | * |
| 1845 | * @param object attributes The block type attributes. |
| 1846 | * @return object |
| 1847 | */ |
| 1848 | function addBackCompatAttribute(attributes, new_attribute, type) { |
| 1849 | attributes[new_attribute] = { |
| 1850 | type: type |
| 1851 | }; |
| 1852 | return attributes; |
| 1853 | } |
| 1854 | |
| 1855 | /** |
| 1856 | * Create a block hash from attributes |
| 1857 | * |
| 1858 | * @since ACF 6.0 |
| 1859 | * |
| 1860 | * @param object attributes The block type attributes. |
| 1861 | * @param object context The current block context object. |
| 1862 | * @return string |
| 1863 | */ |
| 1864 | function createBlockAttributesHash(attributes, context) { |
| 1865 | attributes['_acf_context'] = sortObjectByKey(context); |
| 1866 | return md5(JSON.stringify(sortObjectByKey(attributes))); |
| 1867 | } |
| 1868 | |
| 1869 | /** |
| 1870 | * Key sort an object |
| 1871 | * |
| 1872 | * @since ACF 6.3.1 |
| 1873 | * |
| 1874 | * @param object toSort The object to be sorted |
| 1875 | * @return object |
| 1876 | */ |
| 1877 | function sortObjectByKey(toSort) { |
| 1878 | return Object.keys(toSort).sort().reduce((acc, currValue) => { |
| 1879 | acc[currValue] = toSort[currValue]; |
| 1880 | return acc; |
| 1881 | }, {}); |
| 1882 | } |
| 1883 | })(jQuery); |
| 1884 | |
| 1885 | /***/ }), |
| 1886 | |
| 1887 | /***/ "./assets/src/js/pro/_acf-jsx-names.js": |
| 1888 | /*!*********************************************!*\ |
| 1889 | !*** ./assets/src/js/pro/_acf-jsx-names.js ***! |
| 1890 | \*********************************************/ |
| 1891 | /***/ (() => { |
| 1892 | |
| 1893 | (function ($, undefined) { |
| 1894 | acf.jsxNameReplacements = { |
| 1895 | 'accent-height': 'accentHeight', |
| 1896 | accentheight: 'accentHeight', |
| 1897 | 'accept-charset': 'acceptCharset', |
| 1898 | acceptcharset: 'acceptCharset', |
| 1899 | accesskey: 'accessKey', |
| 1900 | 'alignment-baseline': 'alignmentBaseline', |
| 1901 | alignmentbaseline: 'alignmentBaseline', |
| 1902 | allowedblocks: 'allowedBlocks', |
| 1903 | allowfullscreen: 'allowFullScreen', |
| 1904 | allowreorder: 'allowReorder', |
| 1905 | 'arabic-form': 'arabicForm', |
| 1906 | arabicform: 'arabicForm', |
| 1907 | attributename: 'attributeName', |
| 1908 | attributetype: 'attributeType', |
| 1909 | autocapitalize: 'autoCapitalize', |
| 1910 | autocomplete: 'autoComplete', |
| 1911 | autocorrect: 'autoCorrect', |
| 1912 | autofocus: 'autoFocus', |
| 1913 | autoplay: 'autoPlay', |
| 1914 | autoreverse: 'autoReverse', |
| 1915 | autosave: 'autoSave', |
| 1916 | basefrequency: 'baseFrequency', |
| 1917 | 'baseline-shift': 'baselineShift', |
| 1918 | baselineshift: 'baselineShift', |
| 1919 | baseprofile: 'baseProfile', |
| 1920 | calcmode: 'calcMode', |
| 1921 | 'cap-height': 'capHeight', |
| 1922 | capheight: 'capHeight', |
| 1923 | cellpadding: 'cellPadding', |
| 1924 | cellspacing: 'cellSpacing', |
| 1925 | charset: 'charSet', |
| 1926 | class: 'className', |
| 1927 | classid: 'classID', |
| 1928 | classname: 'className', |
| 1929 | 'clip-path': 'clipPath', |
| 1930 | 'clip-rule': 'clipRule', |
| 1931 | clippath: 'clipPath', |
| 1932 | clippathunits: 'clipPathUnits', |
| 1933 | cliprule: 'clipRule', |
| 1934 | 'color-interpolation': 'colorInterpolation', |
| 1935 | 'color-interpolation-filters': 'colorInterpolationFilters', |
| 1936 | 'color-profile': 'colorProfile', |
| 1937 | 'color-rendering': 'colorRendering', |
| 1938 | colorinterpolation: 'colorInterpolation', |
| 1939 | colorinterpolationfilters: 'colorInterpolationFilters', |
| 1940 | colorprofile: 'colorProfile', |
| 1941 | colorrendering: 'colorRendering', |
| 1942 | colspan: 'colSpan', |
| 1943 | contenteditable: 'contentEditable', |
| 1944 | contentscripttype: 'contentScriptType', |
| 1945 | contentstyletype: 'contentStyleType', |
| 1946 | contextmenu: 'contextMenu', |
| 1947 | controlslist: 'controlsList', |
| 1948 | crossorigin: 'crossOrigin', |
| 1949 | dangerouslysetinnerhtml: 'dangerouslySetInnerHTML', |
| 1950 | datetime: 'dateTime', |
| 1951 | defaultchecked: 'defaultChecked', |
| 1952 | defaultvalue: 'defaultValue', |
| 1953 | diffuseconstant: 'diffuseConstant', |
| 1954 | disablepictureinpicture: 'disablePictureInPicture', |
| 1955 | disableremoteplayback: 'disableRemotePlayback', |
| 1956 | 'dominant-baseline': 'dominantBaseline', |
| 1957 | dominantbaseline: 'dominantBaseline', |
| 1958 | edgemode: 'edgeMode', |
| 1959 | 'enable-background': 'enableBackground', |
| 1960 | enablebackground: 'enableBackground', |
| 1961 | enctype: 'encType', |
| 1962 | enterkeyhint: 'enterKeyHint', |
| 1963 | externalresourcesrequired: 'externalResourcesRequired', |
| 1964 | 'fill-opacity': 'fillOpacity', |
| 1965 | 'fill-rule': 'fillRule', |
| 1966 | fillopacity: 'fillOpacity', |
| 1967 | fillrule: 'fillRule', |
| 1968 | filterres: 'filterRes', |
| 1969 | filterunits: 'filterUnits', |
| 1970 | 'flood-color': 'floodColor', |
| 1971 | 'flood-opacity': 'floodOpacity', |
| 1972 | floodcolor: 'floodColor', |
| 1973 | floodopacity: 'floodOpacity', |
| 1974 | 'font-family': 'fontFamily', |
| 1975 | 'font-size': 'fontSize', |
| 1976 | 'font-size-adjust': 'fontSizeAdjust', |
| 1977 | 'font-stretch': 'fontStretch', |
| 1978 | 'font-style': 'fontStyle', |
| 1979 | 'font-variant': 'fontVariant', |
| 1980 | 'font-weight': 'fontWeight', |
| 1981 | fontfamily: 'fontFamily', |
| 1982 | fontsize: 'fontSize', |
| 1983 | fontsizeadjust: 'fontSizeAdjust', |
| 1984 | fontstretch: 'fontStretch', |
| 1985 | fontstyle: 'fontStyle', |
| 1986 | fontvariant: 'fontVariant', |
| 1987 | fontweight: 'fontWeight', |
| 1988 | for: 'htmlFor', |
| 1989 | foreignobject: 'foreignObject', |
| 1990 | formaction: 'formAction', |
| 1991 | formenctype: 'formEncType', |
| 1992 | formmethod: 'formMethod', |
| 1993 | formnovalidate: 'formNoValidate', |
| 1994 | formtarget: 'formTarget', |
| 1995 | frameborder: 'frameBorder', |
| 1996 | 'glyph-name': 'glyphName', |
| 1997 | 'glyph-orientation-horizontal': 'glyphOrientationHorizontal', |
| 1998 | 'glyph-orientation-vertical': 'glyphOrientationVertical', |
| 1999 | glyphname: 'glyphName', |
| 2000 | glyphorientationhorizontal: 'glyphOrientationHorizontal', |
| 2001 | glyphorientationvertical: 'glyphOrientationVertical', |
| 2002 | glyphref: 'glyphRef', |
| 2003 | gradienttransform: 'gradientTransform', |
| 2004 | gradientunits: 'gradientUnits', |
| 2005 | 'horiz-adv-x': 'horizAdvX', |
| 2006 | 'horiz-origin-x': 'horizOriginX', |
| 2007 | horizadvx: 'horizAdvX', |
| 2008 | horizoriginx: 'horizOriginX', |
| 2009 | hreflang: 'hrefLang', |
| 2010 | htmlfor: 'htmlFor', |
| 2011 | 'http-equiv': 'httpEquiv', |
| 2012 | httpequiv: 'httpEquiv', |
| 2013 | 'image-rendering': 'imageRendering', |
| 2014 | imagerendering: 'imageRendering', |
| 2015 | innerhtml: 'innerHTML', |
| 2016 | inputmode: 'inputMode', |
| 2017 | itemid: 'itemID', |
| 2018 | itemprop: 'itemProp', |
| 2019 | itemref: 'itemRef', |
| 2020 | itemscope: 'itemScope', |
| 2021 | itemtype: 'itemType', |
| 2022 | kernelmatrix: 'kernelMatrix', |
| 2023 | kernelunitlength: 'kernelUnitLength', |
| 2024 | keyparams: 'keyParams', |
| 2025 | keypoints: 'keyPoints', |
| 2026 | keysplines: 'keySplines', |
| 2027 | keytimes: 'keyTimes', |
| 2028 | keytype: 'keyType', |
| 2029 | lengthadjust: 'lengthAdjust', |
| 2030 | 'letter-spacing': 'letterSpacing', |
| 2031 | letterspacing: 'letterSpacing', |
| 2032 | 'lighting-color': 'lightingColor', |
| 2033 | lightingcolor: 'lightingColor', |
| 2034 | limitingconeangle: 'limitingConeAngle', |
| 2035 | marginheight: 'marginHeight', |
| 2036 | marginwidth: 'marginWidth', |
| 2037 | 'marker-end': 'markerEnd', |
| 2038 | 'marker-mid': 'markerMid', |
| 2039 | 'marker-start': 'markerStart', |
| 2040 | markerend: 'markerEnd', |
| 2041 | markerheight: 'markerHeight', |
| 2042 | markermid: 'markerMid', |
| 2043 | markerstart: 'markerStart', |
| 2044 | markerunits: 'markerUnits', |
| 2045 | markerwidth: 'markerWidth', |
| 2046 | maskcontentunits: 'maskContentUnits', |
| 2047 | maskunits: 'maskUnits', |
| 2048 | maxlength: 'maxLength', |
| 2049 | mediagroup: 'mediaGroup', |
| 2050 | minlength: 'minLength', |
| 2051 | nomodule: 'noModule', |
| 2052 | novalidate: 'noValidate', |
| 2053 | numoctaves: 'numOctaves', |
| 2054 | 'overline-position': 'overlinePosition', |
| 2055 | 'overline-thickness': 'overlineThickness', |
| 2056 | overlineposition: 'overlinePosition', |
| 2057 | overlinethickness: 'overlineThickness', |
| 2058 | 'paint-order': 'paintOrder', |
| 2059 | paintorder: 'paintOrder', |
| 2060 | 'panose-1': 'panose1', |
| 2061 | pathlength: 'pathLength', |
| 2062 | patterncontentunits: 'patternContentUnits', |
| 2063 | patterntransform: 'patternTransform', |
| 2064 | patternunits: 'patternUnits', |
| 2065 | playsinline: 'playsInline', |
| 2066 | 'pointer-events': 'pointerEvents', |
| 2067 | pointerevents: 'pointerEvents', |
| 2068 | pointsatx: 'pointsAtX', |
| 2069 | pointsaty: 'pointsAtY', |
| 2070 | pointsatz: 'pointsAtZ', |
| 2071 | preservealpha: 'preserveAlpha', |
| 2072 | preserveaspectratio: 'preserveAspectRatio', |
| 2073 | primitiveunits: 'primitiveUnits', |
| 2074 | radiogroup: 'radioGroup', |
| 2075 | readonly: 'readOnly', |
| 2076 | referrerpolicy: 'referrerPolicy', |
| 2077 | refx: 'refX', |
| 2078 | refy: 'refY', |
| 2079 | 'rendering-intent': 'renderingIntent', |
| 2080 | renderingintent: 'renderingIntent', |
| 2081 | repeatcount: 'repeatCount', |
| 2082 | repeatdur: 'repeatDur', |
| 2083 | requiredextensions: 'requiredExtensions', |
| 2084 | requiredfeatures: 'requiredFeatures', |
| 2085 | rowspan: 'rowSpan', |
| 2086 | 'shape-rendering': 'shapeRendering', |
| 2087 | shaperendering: 'shapeRendering', |
| 2088 | specularconstant: 'specularConstant', |
| 2089 | specularexponent: 'specularExponent', |
| 2090 | spellcheck: 'spellCheck', |
| 2091 | spreadmethod: 'spreadMethod', |
| 2092 | srcdoc: 'srcDoc', |
| 2093 | srclang: 'srcLang', |
| 2094 | srcset: 'srcSet', |
| 2095 | startoffset: 'startOffset', |
| 2096 | stddeviation: 'stdDeviation', |
| 2097 | stitchtiles: 'stitchTiles', |
| 2098 | 'stop-color': 'stopColor', |
| 2099 | 'stop-opacity': 'stopOpacity', |
| 2100 | stopcolor: 'stopColor', |
| 2101 | stopopacity: 'stopOpacity', |
| 2102 | 'strikethrough-position': 'strikethroughPosition', |
| 2103 | 'strikethrough-thickness': 'strikethroughThickness', |
| 2104 | strikethroughposition: 'strikethroughPosition', |
| 2105 | strikethroughthickness: 'strikethroughThickness', |
| 2106 | 'stroke-dasharray': 'strokeDasharray', |
| 2107 | 'stroke-dashoffset': 'strokeDashoffset', |
| 2108 | 'stroke-linecap': 'strokeLinecap', |
| 2109 | 'stroke-linejoin': 'strokeLinejoin', |
| 2110 | 'stroke-miterlimit': 'strokeMiterlimit', |
| 2111 | 'stroke-opacity': 'strokeOpacity', |
| 2112 | 'stroke-width': 'strokeWidth', |
| 2113 | strokedasharray: 'strokeDasharray', |
| 2114 | strokedashoffset: 'strokeDashoffset', |
| 2115 | strokelinecap: 'strokeLinecap', |
| 2116 | strokelinejoin: 'strokeLinejoin', |
| 2117 | strokemiterlimit: 'strokeMiterlimit', |
| 2118 | strokeopacity: 'strokeOpacity', |
| 2119 | strokewidth: 'strokeWidth', |
| 2120 | suppresscontenteditablewarning: 'suppressContentEditableWarning', |
| 2121 | suppresshydrationwarning: 'suppressHydrationWarning', |
| 2122 | surfacescale: 'surfaceScale', |
| 2123 | systemlanguage: 'systemLanguage', |
| 2124 | tabindex: 'tabIndex', |
| 2125 | tablevalues: 'tableValues', |
| 2126 | targetx: 'targetX', |
| 2127 | targety: 'targetY', |
| 2128 | templatelock: 'templateLock', |
| 2129 | 'text-anchor': 'textAnchor', |
| 2130 | 'text-decoration': 'textDecoration', |
| 2131 | 'text-rendering': 'textRendering', |
| 2132 | textanchor: 'textAnchor', |
| 2133 | textdecoration: 'textDecoration', |
| 2134 | textlength: 'textLength', |
| 2135 | textrendering: 'textRendering', |
| 2136 | 'underline-position': 'underlinePosition', |
| 2137 | 'underline-thickness': 'underlineThickness', |
| 2138 | underlineposition: 'underlinePosition', |
| 2139 | underlinethickness: 'underlineThickness', |
| 2140 | 'unicode-bidi': 'unicodeBidi', |
| 2141 | 'unicode-range': 'unicodeRange', |
| 2142 | unicodebidi: 'unicodeBidi', |
| 2143 | unicoderange: 'unicodeRange', |
| 2144 | 'units-per-em': 'unitsPerEm', |
| 2145 | unitsperem: 'unitsPerEm', |
| 2146 | usemap: 'useMap', |
| 2147 | 'v-alphabetic': 'vAlphabetic', |
| 2148 | 'v-hanging': 'vHanging', |
| 2149 | 'v-ideographic': 'vIdeographic', |
| 2150 | 'v-mathematical': 'vMathematical', |
| 2151 | valphabetic: 'vAlphabetic', |
| 2152 | 'vector-effect': 'vectorEffect', |
| 2153 | vectoreffect: 'vectorEffect', |
| 2154 | 'vert-adv-y': 'vertAdvY', |
| 2155 | 'vert-origin-x': 'vertOriginX', |
| 2156 | 'vert-origin-y': 'vertOriginY', |
| 2157 | vertadvy: 'vertAdvY', |
| 2158 | vertoriginx: 'vertOriginX', |
| 2159 | vertoriginy: 'vertOriginY', |
| 2160 | vhanging: 'vHanging', |
| 2161 | videographic: 'vIdeographic', |
| 2162 | viewbox: 'viewBox', |
| 2163 | viewtarget: 'viewTarget', |
| 2164 | vmathematical: 'vMathematical', |
| 2165 | 'word-spacing': 'wordSpacing', |
| 2166 | wordspacing: 'wordSpacing', |
| 2167 | 'writing-mode': 'writingMode', |
| 2168 | writingmode: 'writingMode', |
| 2169 | 'x-height': 'xHeight', |
| 2170 | xchannelselector: 'xChannelSelector', |
| 2171 | xheight: 'xHeight', |
| 2172 | 'xlink:actuate': 'xlinkActuate', |
| 2173 | 'xlink:arcrole': 'xlinkArcrole', |
| 2174 | 'xlink:href': 'xlinkHref', |
| 2175 | 'xlink:role': 'xlinkRole', |
| 2176 | 'xlink:show': 'xlinkShow', |
| 2177 | 'xlink:title': 'xlinkTitle', |
| 2178 | 'xlink:type': 'xlinkType', |
| 2179 | xlinkactuate: 'xlinkActuate', |
| 2180 | xlinkarcrole: 'xlinkArcrole', |
| 2181 | xlinkhref: 'xlinkHref', |
| 2182 | xlinkrole: 'xlinkRole', |
| 2183 | xlinkshow: 'xlinkShow', |
| 2184 | xlinktitle: 'xlinkTitle', |
| 2185 | xlinktype: 'xlinkType', |
| 2186 | 'xml:base': 'xmlBase', |
| 2187 | 'xml:lang': 'xmlLang', |
| 2188 | 'xml:space': 'xmlSpace', |
| 2189 | xmlbase: 'xmlBase', |
| 2190 | xmllang: 'xmlLang', |
| 2191 | 'xmlns:xlink': 'xmlnsXlink', |
| 2192 | xmlnsxlink: 'xmlnsXlink', |
| 2193 | xmlspace: 'xmlSpace', |
| 2194 | ychannelselector: 'yChannelSelector', |
| 2195 | zoomandpan: 'zoomAndPan' |
| 2196 | }; |
| 2197 | })(jQuery); |
| 2198 | |
| 2199 | /***/ }), |
| 2200 | |
| 2201 | /***/ "./assets/src/js/pro/blocks-v3/components/block-edit.js": |
| 2202 | /*!**************************************************************!*\ |
| 2203 | !*** ./assets/src/js/pro/blocks-v3/components/block-edit.js ***! |
| 2204 | \**************************************************************/ |
| 2205 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 2206 | |
| 2207 | "use strict"; |
| 2208 | __webpack_require__.r(__webpack_exports__); |
| 2209 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 2210 | /* harmony export */ BlockEdit: () => (/* binding */ BlockEdit) |
| 2211 | /* harmony export */ }); |
| 2212 | /* harmony import */ var md5__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! md5 */ "./node_modules/md5/md5.js"); |
| 2213 | /* harmony import */ var md5__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(md5__WEBPACK_IMPORTED_MODULE_0__); |
| 2214 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); |
| 2215 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_1__); |
| 2216 | /* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/block-editor */ "@wordpress/block-editor"); |
| 2217 | /* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_2__); |
| 2218 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components"); |
| 2219 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__); |
| 2220 | /* harmony import */ var _block_placeholder__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./block-placeholder */ "./assets/src/js/pro/blocks-v3/components/block-placeholder.js"); |
| 2221 | /* harmony import */ var _block_form__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./block-form */ "./assets/src/js/pro/blocks-v3/components/block-form.js"); |
| 2222 | /* harmony import */ var _block_preview__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./block-preview */ "./assets/src/js/pro/blocks-v3/components/block-preview.js"); |
| 2223 | /* harmony import */ var _error_boundary__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./error-boundary */ "./assets/src/js/pro/blocks-v3/components/error-boundary.js"); |
| 2224 | /* harmony import */ var _block_toolbar_fields__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./block-toolbar-fields */ "./assets/src/js/pro/blocks-v3/components/block-toolbar-fields.js"); |
| 2225 | /* harmony import */ var _inline_editing_toolbar__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./inline-editing-toolbar */ "./assets/src/js/pro/blocks-v3/components/inline-editing-toolbar.js"); |
| 2226 | /* harmony import */ var _popover_wrapper__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./popover-wrapper */ "./assets/src/js/pro/blocks-v3/components/popover-wrapper.js"); |
| 2227 | /* harmony import */ var _utils_post_locking__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../utils/post-locking */ "./assets/src/js/pro/blocks-v3/utils/post-locking.js"); |
| 2228 | function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } |
| 2229 | /** |
| 2230 | * BlockEdit Component |
| 2231 | * Main component for editing ACF blocks in the Gutenberg editor |
| 2232 | * Handles form fetching, validation, preview rendering, and user interactions |
| 2233 | */ |
| 2234 | |
| 2235 | |
| 2236 | |
| 2237 | |
| 2238 | |
| 2239 | |
| 2240 | |
| 2241 | |
| 2242 | |
| 2243 | |
| 2244 | |
| 2245 | |
| 2246 | |
| 2247 | /** |
| 2248 | * InspectorBlockFormContainer |
| 2249 | * Small helper component that manages the inspector panel container ref |
| 2250 | * Sets the current form container when the inspector panel is available |
| 2251 | * |
| 2252 | * @param {Object} props |
| 2253 | * @param {React.RefObject} props.inspectorBlockFormRef - Ref to inspector container |
| 2254 | * @param {Function} props.setCurrentBlockFormContainer - Setter for current container |
| 2255 | */ |
| 2256 | const InspectorBlockFormContainer = ({ |
| 2257 | inspectorBlockFormRef, |
| 2258 | setCurrentBlockFormContainer |
| 2259 | }) => { |
| 2260 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2261 | setCurrentBlockFormContainer(inspectorBlockFormRef.current); |
| 2262 | }, []); |
| 2263 | return /*#__PURE__*/React.createElement("div", { |
| 2264 | ref: inspectorBlockFormRef |
| 2265 | }); |
| 2266 | }; |
| 2267 | const isBlockEditorInspectorSidebarOpen = () => { |
| 2268 | const interfaceStore = wp.data.select('core/interface'); |
| 2269 | return typeof interfaceStore?.getActiveComplementaryArea === 'function' && interfaceStore.getActiveComplementaryArea('core') === 'edit-post/block'; |
| 2270 | }; |
| 2271 | const useBlockEditorInspectorSidebarOpen = () => { |
| 2272 | const [isOpen, setIsOpen] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(() => isBlockEditorInspectorSidebarOpen()); |
| 2273 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2274 | if (typeof wp.data.subscribe !== 'function') { |
| 2275 | return; |
| 2276 | } |
| 2277 | const unsubscribe = wp.data.subscribe(() => { |
| 2278 | setIsOpen(isBlockEditorInspectorSidebarOpen()); |
| 2279 | }); |
| 2280 | return () => { |
| 2281 | unsubscribe(); |
| 2282 | }; |
| 2283 | }, []); |
| 2284 | return isOpen; |
| 2285 | }; |
| 2286 | |
| 2287 | /** |
| 2288 | * Converts serialized Google Map field values from JSON strings back into |
| 2289 | * objects so they aren't double-encoded when the block's data is stored as |
| 2290 | * a JSON block attribute. Google Map fields keep their value as a JSON |
| 2291 | * string in a hidden input, which acf.serialize() would otherwise pass |
| 2292 | * through as a string. |
| 2293 | * |
| 2294 | * @param {Object} $form The block form jQuery element that was serialized. |
| 2295 | * @param {Object} serializedData The data returned by acf.serialize(); modified in place. |
| 2296 | * @param {string} clientId The block client ID. |
| 2297 | * @return {void} |
| 2298 | */ |
| 2299 | function deserializeGoogleMapValues($form, serializedData, clientId) { |
| 2300 | const inputPrefix = `acf-block_${clientId}`; |
| 2301 | $form.find('.acf-field-google-map input[type="hidden"][name]').each(function () { |
| 2302 | if (this.name.indexOf(inputPrefix) !== 0) { |
| 2303 | return; |
| 2304 | } |
| 2305 | |
| 2306 | // Extract the bracketed key path, e.g. "[field_abc][field_def]" -> [ 'field_abc', 'field_def' ]. |
| 2307 | const keyPath = this.name.slice(inputPrefix.length).match(/([^\[\]])+/g); |
| 2308 | if (!keyPath) { |
| 2309 | return; |
| 2310 | } |
| 2311 | |
| 2312 | // Walk the serialized data down to the parent of the leaf key. |
| 2313 | let parent = serializedData; |
| 2314 | for (let i = 0; i < keyPath.length - 1; i++) { |
| 2315 | if (parent === null || typeof parent !== 'object') { |
| 2316 | return; |
| 2317 | } |
| 2318 | parent = parent[keyPath[i]]; |
| 2319 | } |
| 2320 | if (parent === null || typeof parent !== 'object') { |
| 2321 | return; |
| 2322 | } |
| 2323 | const leafKey = keyPath[keyPath.length - 1]; |
| 2324 | if (typeof parent[leafKey] === 'string') { |
| 2325 | try { |
| 2326 | const parsedValue = JSON.parse(parent[leafKey]); |
| 2327 | if (typeof parsedValue === 'object' && parsedValue !== null) { |
| 2328 | parent[leafKey] = parsedValue; |
| 2329 | } |
| 2330 | } catch (err) {} |
| 2331 | } |
| 2332 | }); |
| 2333 | } |
| 2334 | |
| 2335 | /** |
| 2336 | * Main BlockEdit component wrapper |
| 2337 | * Manages block data fetching and initial setup |
| 2338 | * |
| 2339 | * @param {Object} props - Component props |
| 2340 | * @param {Object} props.attributes - Block attributes |
| 2341 | * @param {Function} props.setAttributes - Function to update block attributes |
| 2342 | * @param {Object} props.context - Block context |
| 2343 | * @param {boolean} props.isSelected - Whether block is currently selected |
| 2344 | * @param {jQuery} props.$ - jQuery instance |
| 2345 | * @param {Object} props.blockType - ACF block type configuration |
| 2346 | * @returns {JSX.Element} - Rendered block editor |
| 2347 | */ |
| 2348 | const BlockEdit = props => { |
| 2349 | const { |
| 2350 | attributes, |
| 2351 | setAttributes, |
| 2352 | context, |
| 2353 | isSelected, |
| 2354 | $, |
| 2355 | blockType |
| 2356 | } = props; |
| 2357 | const shouldValidate = blockType.validate; |
| 2358 | const { |
| 2359 | clientId |
| 2360 | } = (0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_2__.useBlockEditContext)(); |
| 2361 | const preloadedData = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useMemo)(() => { |
| 2362 | return checkPreloadedData(generateAttributesHash(attributes, context), clientId, isSelected); |
| 2363 | }, []); |
| 2364 | const [validationErrors, setValidationErrors] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(() => { |
| 2365 | return preloadedData?.validation?.errors ?? null; |
| 2366 | }); |
| 2367 | const [showValidationErrors, setShowValidationErrors] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(null); |
| 2368 | const [theSerializedAcfData, setTheSerializedAcfData] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(null); |
| 2369 | const [blockFormHtml, setBlockFormHtml] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(() => preloadedData?.form ?? ''); |
| 2370 | const [blockPreviewHtml, setBlockPreviewHtml] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(() => { |
| 2371 | if (preloadedData?.html) { |
| 2372 | return acf.applyFilters('blocks/preview/render', preloadedData.html, true); |
| 2373 | } |
| 2374 | return 'acf-block-preview-loading'; |
| 2375 | }); |
| 2376 | const [userHasInteractedWithForm, setUserHasInteractedWithForm] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2377 | const [hasFetchedOnce, setHasFetchedOnce] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2378 | const [ajaxRequest, setAjaxRequest] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(); |
| 2379 | const [isFetchingBlock, setIsFetchingBlock] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2380 | |
| 2381 | // New state for inline editing features |
| 2382 | const [blockToolbarFields, setBlockToolbarFields] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)([]); |
| 2383 | const [blockFieldInfo, setBlockFieldInfo] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(() => preloadedData?.fields ?? null); |
| 2384 | const [gutenbergIframeOrDocument, setGutenbergIframeOrDocument] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(() => { |
| 2385 | const iframe = document.querySelector('[name="editor-canvas"]'); |
| 2386 | return iframe ? iframe.contentDocument || iframe.contentWindow.document : document; |
| 2387 | }); |
| 2388 | const [currentInlineEditingElement, setCurrentInlineEditingElement] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(null); |
| 2389 | const [currentInlineEditingElementUid, setCurrentInlineEditingElementUid] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(null); |
| 2390 | const [currentContentEditableElement, setCurrentContentEditableElement] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(null); |
| 2391 | const [inlineEditingToolbarHasFocus, setInlineEditingToolbarHasFocus] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2392 | const [contentEditableChangeInProgress, setContentEditableChangeInProgress] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2393 | const [acfDynamicStylesElement, setAcfDynamicStylesElement] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(null); |
| 2394 | const [freezeInlineToolbarDuringReRender, setFreezeInlineToolbarDuringReRender] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(''); |
| 2395 | const blockEditorInspectorSidebarOpen = useBlockEditorInspectorSidebarOpen(); |
| 2396 | const acfFormRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); |
| 2397 | const previewRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); |
| 2398 | const debounceRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useRef)(null); |
| 2399 | |
| 2400 | // Initialize acf.blockEdit namespace for jsx-parser to use |
| 2401 | if (!acf.blockEdit) { |
| 2402 | acf.blockEdit = {}; |
| 2403 | } |
| 2404 | acf.blockEdit.setCurrentInlineEditingElementUid = setCurrentInlineEditingElementUid; |
| 2405 | acf.blockEdit.setCurrentInlineEditingElement = setCurrentInlineEditingElement; |
| 2406 | acf.blockEdit.setCurrentContentEditableElement = setCurrentContentEditableElement; |
| 2407 | acf.blockEdit.getBlockFieldInfo = () => blockFieldInfo; |
| 2408 | const attributesWithoutError = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useMemo)(() => { |
| 2409 | const { |
| 2410 | hasAcfError, |
| 2411 | ...rest |
| 2412 | } = attributes; |
| 2413 | return rest; |
| 2414 | }, [attributes]); |
| 2415 | |
| 2416 | /** |
| 2417 | * Fetches block data from server (form HTML, preview HTML, validation) |
| 2418 | * |
| 2419 | * @param {Object} params - Fetch parameters |
| 2420 | * @param {Object} params.theAttributes - Block attributes to fetch for |
| 2421 | * @param {string} params.theClientId - Block client ID |
| 2422 | * @param {Object} params.theContext - Block context |
| 2423 | * @param {boolean} params.isSelected - Whether block is selected |
| 2424 | */ |
| 2425 | function fetchBlockData({ |
| 2426 | theAttributes, |
| 2427 | theClientId, |
| 2428 | theContext, |
| 2429 | isSelected |
| 2430 | }) { |
| 2431 | if (!theAttributes) return; |
| 2432 | |
| 2433 | // NEW: Abort any pending request |
| 2434 | if (ajaxRequest) { |
| 2435 | ajaxRequest.abort(); |
| 2436 | } |
| 2437 | |
| 2438 | // Generate hash of attributes for preload cache lookup |
| 2439 | const attributesHash = generateAttributesHash(theAttributes, context); |
| 2440 | |
| 2441 | // Check for preloaded block data |
| 2442 | const preloadedData = checkPreloadedData(attributesHash, theClientId, isSelected); |
| 2443 | if (preloadedData) { |
| 2444 | handlePreloadedData(preloadedData); |
| 2445 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.unlockPostSavingByName)('acf-fetching-block'); |
| 2446 | setIsFetchingBlock(false); |
| 2447 | return; |
| 2448 | } |
| 2449 | |
| 2450 | // Prepare query options |
| 2451 | const queryOptions = { |
| 2452 | preview: true, |
| 2453 | form: true, |
| 2454 | validate: true |
| 2455 | }; |
| 2456 | if (!blockFormHtml) { |
| 2457 | queryOptions.validate = false; |
| 2458 | } |
| 2459 | if (!shouldValidate) { |
| 2460 | queryOptions.validate = false; |
| 2461 | } |
| 2462 | const blockData = { |
| 2463 | ...theAttributes |
| 2464 | }; |
| 2465 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.lockPostSavingByName)('acf-fetching-block'); |
| 2466 | setIsFetchingBlock(true); |
| 2467 | |
| 2468 | // Fetch block data via AJAX |
| 2469 | const request = $.ajax({ |
| 2470 | url: acf.get('ajaxurl'), |
| 2471 | dataType: 'json', |
| 2472 | type: 'post', |
| 2473 | cache: false, |
| 2474 | data: acf.prepareForAjax({ |
| 2475 | action: 'acf/ajax/fetch-block', |
| 2476 | block: JSON.stringify(blockData), |
| 2477 | clientId: theClientId, |
| 2478 | context: JSON.stringify(theContext), |
| 2479 | query: queryOptions |
| 2480 | }) |
| 2481 | }).done(response => { |
| 2482 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.unlockPostSavingByName)('acf-fetching-block'); |
| 2483 | setIsFetchingBlock(false); |
| 2484 | setBlockFormHtml(response.data.form); |
| 2485 | |
| 2486 | // Handle new field metadata for inline editing |
| 2487 | if (response.data.fields) { |
| 2488 | setBlockFieldInfo(response.data.fields); |
| 2489 | } |
| 2490 | |
| 2491 | // Handle block toolbar fields configuration |
| 2492 | if (response.data.blockToolbarFields) { |
| 2493 | setBlockToolbarFields(response.data.blockToolbarFields); |
| 2494 | } |
| 2495 | if (response.data.preview) { |
| 2496 | setBlockPreviewHtml(acf.applyFilters('blocks/preview/render', response.data.preview, false)); |
| 2497 | } else { |
| 2498 | setBlockPreviewHtml(acf.applyFilters('blocks/preview/render', 'acf-block-preview-no-html', false)); |
| 2499 | } |
| 2500 | if (response.data?.validation && !response.data.validation.valid && response.data.validation.errors) { |
| 2501 | setValidationErrors(response.data.validation.errors); |
| 2502 | } else { |
| 2503 | setValidationErrors(null); |
| 2504 | } |
| 2505 | setHasFetchedOnce(true); |
| 2506 | }).fail(function () { |
| 2507 | setHasFetchedOnce(true); |
| 2508 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.unlockPostSavingByName)('acf-fetching-block'); |
| 2509 | setIsFetchingBlock(false); |
| 2510 | }); |
| 2511 | setAjaxRequest(request); |
| 2512 | } |
| 2513 | |
| 2514 | /** |
| 2515 | * Generates a hash of block attributes for caching |
| 2516 | * |
| 2517 | * @param {Object} attrs - Block attributes |
| 2518 | * @param {Object} ctx - Block context |
| 2519 | * @returns {string} - MD5 hash of serialized attributes |
| 2520 | */ |
| 2521 | function generateAttributesHash(attrs, ctx) { |
| 2522 | delete attrs.hasAcfError; |
| 2523 | attrs._acf_context = (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.sortObjectKeys)(ctx); |
| 2524 | return md5__WEBPACK_IMPORTED_MODULE_0___default()(JSON.stringify((0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.sortObjectKeys)(attrs))); |
| 2525 | } |
| 2526 | |
| 2527 | /** |
| 2528 | * Checks if block data was preloaded and returns it |
| 2529 | * |
| 2530 | * @param {string} hash - Attributes hash |
| 2531 | * @param {string} clientId - Block client ID |
| 2532 | * @param {boolean} selected - Whether block is selected |
| 2533 | * @returns {Object|boolean} - Preloaded data or false |
| 2534 | */ |
| 2535 | function checkPreloadedData(hash, clientId, selected) { |
| 2536 | if (selected) return false; |
| 2537 | acf.debug('Preload check', hash, clientId); |
| 2538 | |
| 2539 | // Don't preload blocks inside Query Loop blocks |
| 2540 | if (isInQueryLoop(clientId)) { |
| 2541 | return false; |
| 2542 | } |
| 2543 | const data = getPreloadedBlockData(hash, clientId, acf.get('preloadedBlocks')); |
| 2544 | if (!data) { |
| 2545 | acf.debug('Preload failed: not preloaded.'); |
| 2546 | return false; |
| 2547 | } |
| 2548 | acf.debug('Preload successful', data); |
| 2549 | return data; |
| 2550 | } |
| 2551 | |
| 2552 | /** |
| 2553 | * Returns a copy of a preloaded block entry with the placeholder hash |
| 2554 | * replaced by the actual client ID. |
| 2555 | * |
| 2556 | * Works on a deep clone so the shared preloaded entry is never mutated — |
| 2557 | * duplicating a block with identical attributes reuses the same hash, and |
| 2558 | * an in-place replacement would corrupt the entry for the duplicate. |
| 2559 | * |
| 2560 | * @param {string} hash - Attributes hash |
| 2561 | * @param {string} blockClientId - Block client ID |
| 2562 | * @param {Object} preloadedBlocks - The preloaded blocks store |
| 2563 | * @return {Object|boolean} - Preloaded data or false |
| 2564 | */ |
| 2565 | function getPreloadedBlockData(hash, blockClientId, preloadedBlocks) { |
| 2566 | if (!preloadedBlocks || !preloadedBlocks[hash]) { |
| 2567 | return false; |
| 2568 | } |
| 2569 | const data = JSON.parse(JSON.stringify(preloadedBlocks[hash])); |
| 2570 | |
| 2571 | // Replace placeholder client ID with actual client ID |
| 2572 | data.html = data.html.replaceAll(hash, blockClientId); |
| 2573 | data.form = data.form.replaceAll(hash, blockClientId); |
| 2574 | if (data?.validation?.errors) { |
| 2575 | data.validation.errors = data.validation.errors.map(error => { |
| 2576 | error.input = error.input.replaceAll(hash, blockClientId); |
| 2577 | return error; |
| 2578 | }); |
| 2579 | } |
| 2580 | return data; |
| 2581 | } |
| 2582 | |
| 2583 | /** |
| 2584 | * Checks if block is inside a Query Loop block |
| 2585 | * |
| 2586 | * @param {string} clientId - Block client ID |
| 2587 | * @returns {boolean} - True if inside Query Loop |
| 2588 | */ |
| 2589 | function isInQueryLoop(clientId) { |
| 2590 | const parentIds = wp.data.select('core/block-editor').getBlockParents(clientId); |
| 2591 | return wp.data.select('core/block-editor').getBlocksByClientId(parentIds).filter(block => block.name === 'core/query').length > 0; |
| 2592 | } |
| 2593 | |
| 2594 | /** |
| 2595 | * Handles preloaded block data |
| 2596 | * |
| 2597 | * @param {Object} data - Preloaded data |
| 2598 | */ |
| 2599 | function handlePreloadedData(data) { |
| 2600 | if (data.form) { |
| 2601 | setBlockFormHtml(data.form); |
| 2602 | } |
| 2603 | if (data.html) { |
| 2604 | setBlockPreviewHtml(acf.applyFilters('blocks/preview/render', data.html, true)); |
| 2605 | } else { |
| 2606 | setBlockPreviewHtml(acf.applyFilters('blocks/preview/render', 'acf-block-preview-no-html', true)); |
| 2607 | } |
| 2608 | |
| 2609 | // Handle block toolbar fields from preloaded data |
| 2610 | if (data?.blockToolbarFields) { |
| 2611 | setBlockToolbarFields(data.blockToolbarFields); |
| 2612 | } |
| 2613 | |
| 2614 | // Handle field info from preloaded data |
| 2615 | if (data?.fields) { |
| 2616 | setBlockFieldInfo(data.fields); |
| 2617 | } |
| 2618 | if (data?.validation && !data.validation.valid && data.validation.errors) { |
| 2619 | setValidationErrors(data.validation.errors); |
| 2620 | } else { |
| 2621 | setValidationErrors(null); |
| 2622 | } |
| 2623 | } |
| 2624 | |
| 2625 | // Initial fetch on mount and when selection changes |
| 2626 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2627 | function trackUserInteraction() { |
| 2628 | setUserHasInteractedWithForm(true); |
| 2629 | window.removeEventListener('click', trackUserInteraction); |
| 2630 | window.removeEventListener('keydown', trackUserInteraction); |
| 2631 | } |
| 2632 | window.addEventListener('click', trackUserInteraction); |
| 2633 | window.addEventListener('keydown', trackUserInteraction); |
| 2634 | return () => { |
| 2635 | window.removeEventListener('click', trackUserInteraction); |
| 2636 | window.removeEventListener('keydown', trackUserInteraction); |
| 2637 | }; |
| 2638 | }, []); |
| 2639 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2640 | if (isSelected) { |
| 2641 | return; |
| 2642 | } |
| 2643 | setCurrentInlineEditingElementUid(null); |
| 2644 | setCurrentInlineEditingElement(null); |
| 2645 | setCurrentContentEditableElement(null); |
| 2646 | }, [isSelected]); |
| 2647 | |
| 2648 | // Update hasAcfError attribute based on validation errors |
| 2649 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2650 | setAttributes(validationErrors ? { |
| 2651 | hasAcfError: true |
| 2652 | } : { |
| 2653 | hasAcfError: false |
| 2654 | }); |
| 2655 | }, [validationErrors, setAttributes]); |
| 2656 | |
| 2657 | // Listen for validation error events from other blocks |
| 2658 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2659 | const handleErrorEvent = event => { |
| 2660 | // Only handle if this event is for this specific block |
| 2661 | if (clientId === event.detail.acfBlocksWithValidationErrors) { |
| 2662 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.lockPostSaving)(clientId); |
| 2663 | setShowValidationErrors(true); |
| 2664 | setCurrentInlineEditingElementUid(null); |
| 2665 | } |
| 2666 | }; |
| 2667 | document.addEventListener('acf/block/has-error', handleErrorEvent); |
| 2668 | return () => { |
| 2669 | document.removeEventListener('acf/block/has-error', handleErrorEvent); |
| 2670 | }; |
| 2671 | }, []); |
| 2672 | |
| 2673 | // Cleanup: unlock post saving on unmount |
| 2674 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => () => { |
| 2675 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.unlockPostSaving)(props.clientId); |
| 2676 | }, []); |
| 2677 | |
| 2678 | // Handle form data changes with debouncing |
| 2679 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2680 | clearTimeout(debounceRef.current); |
| 2681 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.lockPostSavingByName)('acf-fetching-block'); |
| 2682 | setIsFetchingBlock(true); |
| 2683 | debounceRef.current = setTimeout(() => { |
| 2684 | const parsedData = JSON.parse(theSerializedAcfData); |
| 2685 | if (!parsedData) { |
| 2686 | return void fetchBlockData({ |
| 2687 | theAttributes: attributesWithoutError, |
| 2688 | theClientId: clientId, |
| 2689 | theContext: context, |
| 2690 | isSelected: isSelected |
| 2691 | }); |
| 2692 | } |
| 2693 | if (theSerializedAcfData === JSON.stringify(attributesWithoutError.data)) { |
| 2694 | return void fetchBlockData({ |
| 2695 | theAttributes: attributesWithoutError, |
| 2696 | theClientId: clientId, |
| 2697 | theContext: context, |
| 2698 | isSelected: isSelected |
| 2699 | }); |
| 2700 | } |
| 2701 | |
| 2702 | // Use original attributes (with hasAcfError) when updating |
| 2703 | const updatedAttributes = { |
| 2704 | ...attributes, |
| 2705 | data: { |
| 2706 | ...parsedData |
| 2707 | } |
| 2708 | }; |
| 2709 | setAttributes(updatedAttributes); |
| 2710 | }, 200); |
| 2711 | |
| 2712 | // Cleanup function to unlock post saving |
| 2713 | return () => { |
| 2714 | clearTimeout(debounceRef.current); |
| 2715 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_11__.unlockPostSavingByName)('acf-fetching-block'); |
| 2716 | setIsFetchingBlock(false); |
| 2717 | }; |
| 2718 | }, [theSerializedAcfData, attributesWithoutError]); |
| 2719 | |
| 2720 | // Trigger ACF actions when preview is rendered |
| 2721 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2722 | if (previewRef.current && blockPreviewHtml) { |
| 2723 | const blockName = attributes.name.replace('acf/', ''); |
| 2724 | const $preview = $(previewRef.current); |
| 2725 | acf.doAction('render_block_preview', $preview, attributes); |
| 2726 | acf.doAction(`render_block_preview/type=${blockName}`, $preview, attributes); |
| 2727 | |
| 2728 | // If there's an active inline editing element, re-initialize it after preview renders |
| 2729 | if (currentInlineEditingElementUid) { |
| 2730 | const inlineElement = previewRef?.current.querySelector(`[data-acf-inline-fields-uid="${currentInlineEditingElementUid}"]`); |
| 2731 | setCurrentInlineEditingElement(inlineElement); |
| 2732 | } |
| 2733 | } |
| 2734 | }, [blockPreviewHtml]); |
| 2735 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2736 | if (currentContentEditableElement && !inlineEditingToolbarHasFocus || !currentInlineEditingElement) { |
| 2737 | return; |
| 2738 | } |
| 2739 | const toolbar = document.querySelector('.acf-inline-editing-toolbar'); |
| 2740 | if (toolbar?.style?.cssText) { |
| 2741 | setFreezeInlineToolbarDuringReRender(toolbar.style.cssText.replaceAll(';', '!important;')); |
| 2742 | } |
| 2743 | setTimeout(() => { |
| 2744 | setCurrentInlineEditingElement(currentInlineEditingElement); |
| 2745 | setTimeout(() => { |
| 2746 | setFreezeInlineToolbarDuringReRender(null); |
| 2747 | }, 0); |
| 2748 | }, 0); |
| 2749 | }, [currentInlineEditingElement]); |
| 2750 | return /*#__PURE__*/React.createElement(BlockEditInner, _extends({}, props, { |
| 2751 | validationErrors: validationErrors, |
| 2752 | showValidationErrors: showValidationErrors, |
| 2753 | theSerializedAcfData: theSerializedAcfData, |
| 2754 | setTheSerializedAcfData: setTheSerializedAcfData, |
| 2755 | acfFormRef: acfFormRef, |
| 2756 | blockFormHtml: blockFormHtml, |
| 2757 | blockPreviewHtml: blockPreviewHtml, |
| 2758 | blockFetcher: fetchBlockData, |
| 2759 | userHasInteractedWithForm: userHasInteractedWithForm, |
| 2760 | setUserHasInteractedWithForm: setUserHasInteractedWithForm, |
| 2761 | previewRef: previewRef, |
| 2762 | hasFetchedOnce: hasFetchedOnce, |
| 2763 | blockToolbarFields: blockToolbarFields, |
| 2764 | blockFieldInfo: blockFieldInfo, |
| 2765 | gutenbergIframeOrDocument: gutenbergIframeOrDocument, |
| 2766 | setGutenbergIframeOrDocument: setGutenbergIframeOrDocument, |
| 2767 | currentInlineEditingElement: currentInlineEditingElement, |
| 2768 | setCurrentInlineEditingElement: setCurrentInlineEditingElement, |
| 2769 | currentInlineEditingElementUid: currentInlineEditingElementUid, |
| 2770 | setCurrentInlineEditingElementUid: setCurrentInlineEditingElementUid, |
| 2771 | currentContentEditableElement: currentContentEditableElement, |
| 2772 | setCurrentContentEditableElement: setCurrentContentEditableElement, |
| 2773 | inlineEditingToolbarHasFocus: inlineEditingToolbarHasFocus, |
| 2774 | setInlineEditingToolbarHasFocus: setInlineEditingToolbarHasFocus, |
| 2775 | contentEditableChangeInProgress: contentEditableChangeInProgress, |
| 2776 | setContentEditableChangeInProgress: setContentEditableChangeInProgress, |
| 2777 | acfDynamicStylesElement: acfDynamicStylesElement, |
| 2778 | setAcfDynamicStylesElement: setAcfDynamicStylesElement, |
| 2779 | blockEditorInspectorSidebarOpen: blockEditorInspectorSidebarOpen, |
| 2780 | freezeInlineToolbarDuringReRender: freezeInlineToolbarDuringReRender, |
| 2781 | isFetchingBlock: isFetchingBlock |
| 2782 | })); |
| 2783 | }; |
| 2784 | |
| 2785 | /** |
| 2786 | * Inner component that handles rendering and portals |
| 2787 | * Separated to manage refs and portal targets properly |
| 2788 | */ |
| 2789 | function BlockEditInner(props) { |
| 2790 | const { |
| 2791 | blockType, |
| 2792 | $, |
| 2793 | isSelected, |
| 2794 | attributes, |
| 2795 | context, |
| 2796 | validationErrors, |
| 2797 | showValidationErrors, |
| 2798 | theSerializedAcfData, |
| 2799 | setTheSerializedAcfData, |
| 2800 | acfFormRef, |
| 2801 | blockFormHtml, |
| 2802 | blockPreviewHtml, |
| 2803 | blockFetcher, |
| 2804 | userHasInteractedWithForm, |
| 2805 | setUserHasInteractedWithForm, |
| 2806 | previewRef, |
| 2807 | hasFetchedOnce, |
| 2808 | blockToolbarFields, |
| 2809 | blockFieldInfo, |
| 2810 | gutenbergIframeOrDocument, |
| 2811 | setGutenbergIframeOrDocument, |
| 2812 | currentInlineEditingElement, |
| 2813 | setCurrentInlineEditingElement, |
| 2814 | currentInlineEditingElementUid, |
| 2815 | setCurrentInlineEditingElementUid, |
| 2816 | currentContentEditableElement, |
| 2817 | setCurrentContentEditableElement, |
| 2818 | inlineEditingToolbarHasFocus, |
| 2819 | setInlineEditingToolbarHasFocus, |
| 2820 | contentEditableChangeInProgress, |
| 2821 | setContentEditableChangeInProgress, |
| 2822 | acfDynamicStylesElement, |
| 2823 | setAcfDynamicStylesElement, |
| 2824 | blockEditorInspectorSidebarOpen, |
| 2825 | freezeInlineToolbarDuringReRender, |
| 2826 | isFetchingBlock |
| 2827 | } = props; |
| 2828 | const { |
| 2829 | clientId |
| 2830 | } = (0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_2__.useBlockEditContext)(); |
| 2831 | const inspectorControlsRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useRef)(); |
| 2832 | const [blockFormModalOpen, setBlockFormModalOpen] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2833 | const modalFormContainerRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useRef)(); |
| 2834 | const [currentFormContainer, setCurrentFormContainer] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(); |
| 2835 | const [canRenderForm, setCanRenderForm] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2836 | const [shouldShowModalDoneFallback, setShouldShowModalDoneFallback] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(false); |
| 2837 | const [invisibleBlockFormContainer, setInvisibleBlockFormContainer] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useState)(); |
| 2838 | const closeBlockFormModal = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useCallback)(() => { |
| 2839 | setCurrentFormContainer(null); |
| 2840 | setBlockFormModalOpen(false); |
| 2841 | }, []); |
| 2842 | const setModalFormContainer = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useCallback)(container => { |
| 2843 | modalFormContainerRef.current = container; |
| 2844 | if (container && blockFormModalOpen) { |
| 2845 | setCurrentFormContainer(container); |
| 2846 | } |
| 2847 | }, [blockFormModalOpen]); |
| 2848 | |
| 2849 | // Render counter for debugging |
| 2850 | const renderCount = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useRef)(0); |
| 2851 | renderCount.current++; |
| 2852 | |
| 2853 | // Detect Gutenberg iframe or document |
| 2854 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2855 | const gutenbergIframe = document.querySelector('iframe[name="editor-canvas"]'); |
| 2856 | if (gutenbergIframe?.contentDocument) { |
| 2857 | setGutenbergIframeOrDocument(gutenbergIframe.contentDocument); |
| 2858 | } else { |
| 2859 | setGutenbergIframeOrDocument(document); |
| 2860 | } |
| 2861 | }, []); |
| 2862 | |
| 2863 | // Create/get dynamic styles element for inline field highlighting |
| 2864 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2865 | if (!gutenbergIframeOrDocument) return; |
| 2866 | let styleElement = gutenbergIframeOrDocument.getElementById('acf-dynamic-styles'); |
| 2867 | if (!styleElement) { |
| 2868 | styleElement = document.createElement('style'); |
| 2869 | styleElement.id = 'acf-dynamic-styles'; |
| 2870 | gutenbergIframeOrDocument.head.appendChild(styleElement); |
| 2871 | } |
| 2872 | setAcfDynamicStylesElement(styleElement); |
| 2873 | }, [gutenbergIframeOrDocument]); |
| 2874 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2875 | let invisibleContainer = document.getElementById('invisible-acf-form-element'); |
| 2876 | if (!invisibleContainer) { |
| 2877 | invisibleContainer = document.createElement('div'); |
| 2878 | invisibleContainer.id = 'invisible-acf-form-element'; |
| 2879 | invisibleContainer.style.display = 'none'; |
| 2880 | document.body.appendChild(invisibleContainer); |
| 2881 | } |
| 2882 | setInvisibleBlockFormContainer(invisibleContainer); |
| 2883 | }, [blockEditorInspectorSidebarOpen]); |
| 2884 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2885 | if (blockFormModalOpen) { |
| 2886 | return; |
| 2887 | } |
| 2888 | setCurrentFormContainer(blockEditorInspectorSidebarOpen ? inspectorControlsRef.current : invisibleBlockFormContainer); |
| 2889 | }, [blockEditorInspectorSidebarOpen, invisibleBlockFormContainer, blockFormModalOpen]); |
| 2890 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2891 | if (!blockFormModalOpen) { |
| 2892 | return; |
| 2893 | } |
| 2894 | const setModalContainer = () => { |
| 2895 | if (modalFormContainerRef?.current) { |
| 2896 | setCurrentFormContainer(modalFormContainerRef.current); |
| 2897 | } |
| 2898 | }; |
| 2899 | setModalContainer(); |
| 2900 | const timeout = setTimeout(setModalContainer, 0); |
| 2901 | return () => { |
| 2902 | clearTimeout(timeout); |
| 2903 | }; |
| 2904 | }, [blockFormModalOpen]); |
| 2905 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2906 | if (!blockFormModalOpen) { |
| 2907 | setShouldShowModalDoneFallback(false); |
| 2908 | return; |
| 2909 | } |
| 2910 | const updateFallbackVisibility = () => { |
| 2911 | const modal = modalFormContainerRef?.current?.closest('.acf-block-form-modal'); |
| 2912 | const hasHeaderActions = modal?.querySelector('.components-modal__header .components-button'); |
| 2913 | setShouldShowModalDoneFallback(!hasHeaderActions); |
| 2914 | }; |
| 2915 | updateFallbackVisibility(); |
| 2916 | const timeout = setTimeout(updateFallbackVisibility, 0); |
| 2917 | return () => { |
| 2918 | clearTimeout(timeout); |
| 2919 | }; |
| 2920 | }, [blockFormModalOpen]); |
| 2921 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2922 | if (blockFormModalOpen) { |
| 2923 | return; |
| 2924 | } |
| 2925 | if (blockEditorInspectorSidebarOpen) { |
| 2926 | setCurrentFormContainer(inspectorControlsRef.current); |
| 2927 | return; |
| 2928 | } |
| 2929 | setCurrentFormContainer(invisibleBlockFormContainer); |
| 2930 | }, [blockEditorInspectorSidebarOpen, invisibleBlockFormContainer, blockFormModalOpen]); |
| 2931 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2932 | if (isSelected && inspectorControlsRef?.current) { |
| 2933 | setCanRenderForm(true); |
| 2934 | } else if (isSelected && !inspectorControlsRef?.current) { |
| 2935 | setTimeout(() => { |
| 2936 | setCanRenderForm(true); |
| 2937 | }, 1); |
| 2938 | } |
| 2939 | }, [isSelected, inspectorControlsRef, inspectorControlsRef.current]); |
| 2940 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2941 | if (isSelected && validationErrors && showValidationErrors && blockType?.hide_fields_in_sidebar) { |
| 2942 | setBlockFormModalOpen(true); |
| 2943 | } |
| 2944 | }, [isSelected, showValidationErrors, validationErrors, blockType]); |
| 2945 | |
| 2946 | // Build block CSS classes |
| 2947 | let blockClasses = 'acf-block-component acf-block-body'; |
| 2948 | blockClasses += ' acf-block-preview'; |
| 2949 | if (validationErrors && showValidationErrors) { |
| 2950 | blockClasses += ' acf-block-has-validation-error'; |
| 2951 | } |
| 2952 | const blockProps = { |
| 2953 | ...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_2__.useBlockProps)({ |
| 2954 | className: blockClasses, |
| 2955 | ref: previewRef |
| 2956 | }) |
| 2957 | }; |
| 2958 | |
| 2959 | // Update field value from contentEditable changes (matches 6.7.0.2) |
| 2960 | const updateFieldValueFromContentEditable = (content, fieldSlug) => { |
| 2961 | if (!acfFormRef?.current || !fieldSlug) return; |
| 2962 | const fieldWrapper = acfFormRef.current.querySelector(`[data-name=${fieldSlug}]`); |
| 2963 | if (!fieldWrapper) return; |
| 2964 | const fieldKey = fieldWrapper.attributes.getNamedItem('data-key')?.value; |
| 2965 | if (!fieldKey) return; |
| 2966 | const fieldInput = acfFormRef.current.querySelector(`[name="acf-block_${clientId}[${fieldKey}]"`); |
| 2967 | if (!fieldInput) return; |
| 2968 | |
| 2969 | // Update field value and trigger serialization (debouncing happens in useEffect) |
| 2970 | if (content) { |
| 2971 | setUserHasInteractedWithForm(true); |
| 2972 | } |
| 2973 | setContentEditableChangeInProgress(false); |
| 2974 | fieldInput.value = content; |
| 2975 | const $form = $(acfFormRef?.current); |
| 2976 | const serializedData = acf.serialize($form, `acf-block_${clientId}`); |
| 2977 | if (serializedData) { |
| 2978 | deserializeGoogleMapValues($form, serializedData, clientId); |
| 2979 | setTheSerializedAcfData(JSON.stringify(serializedData)); |
| 2980 | } else { |
| 2981 | setUserHasInteractedWithForm(false); |
| 2982 | } |
| 2983 | }; |
| 2984 | |
| 2985 | // Watch for changes in contentEditable fields using MutationObserver |
| 2986 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => { |
| 2987 | if (!gutenbergIframeOrDocument || !blockPreviewHtml) return; |
| 2988 | const observer = new MutationObserver(mutations => { |
| 2989 | for (const mutation of mutations) { |
| 2990 | // Handle text content changes |
| 2991 | if (mutation.type === 'characterData') { |
| 2992 | let element = mutation.target.parentNode; |
| 2993 | const blockElement = element?.closest('[data-block]'); |
| 2994 | const blockId = blockElement?.getAttribute('data-block'); |
| 2995 | if (!element || !blockElement || blockId !== clientId) return; |
| 2996 | |
| 2997 | // Find the contentEditable element |
| 2998 | if (element && !element.hasAttribute('data-acf-inline-contenteditable')) { |
| 2999 | element = element.closest('[data-acf-inline-contenteditable]'); |
| 3000 | } |
| 3001 | if (element && element.hasAttribute('data-acf-inline-contenteditable')) { |
| 3002 | const fieldSlug = element.attributes.getNamedItem('data-acf-inline-contenteditable-field-slug').value; |
| 3003 | let content = element.innerHTML.trim(); |
| 3004 | if (!content) content = ''; |
| 3005 | updateFieldValueFromContentEditable(content, fieldSlug); |
| 3006 | } |
| 3007 | } |
| 3008 | // Handle attribute or child list changes |
| 3009 | else { |
| 3010 | const element = mutation.target.closest('[data-acf-inline-contenteditable]'); |
| 3011 | const blockElement = element?.closest('[data-block]'); |
| 3012 | if (!element || !blockElement || blockElement.getAttribute('data-block') !== clientId) return; |
| 3013 | if (element) { |
| 3014 | const fieldSlug = element.attributes.getNamedItem('data-acf-inline-contenteditable-field-slug').value; |
| 3015 | let content = element.innerHTML.trim(); |
| 3016 | |
| 3017 | // Handle empty content - remove empty BR tags |
| 3018 | if (!content || element.textContent.trim().length === 0 && element.children.length === 1 && element.firstElementChild && element.firstElementChild.nodeName === 'BR') { |
| 3019 | element.innerHTML = ''; |
| 3020 | content = ''; |
| 3021 | } |
| 3022 | updateFieldValueFromContentEditable(content, fieldSlug); |
| 3023 | } |
| 3024 | } |
| 3025 | } |
| 3026 | }); |
| 3027 | |
| 3028 | // Observe the gutenberg iframe/document for changes |
| 3029 | observer.observe(gutenbergIframeOrDocument, { |
| 3030 | attributes: true, |
| 3031 | childList: true, |
| 3032 | subtree: true, |
| 3033 | characterData: true, |
| 3034 | attributeFilter: ['data-acf-inline-contenteditable'] |
| 3035 | }); |
| 3036 | |
| 3037 | // Cleanup |
| 3038 | return () => { |
| 3039 | observer.disconnect(); |
| 3040 | }; |
| 3041 | }, [blockPreviewHtml, gutenbergIframeOrDocument]); |
| 3042 | |
| 3043 | // Callback when a new inline editing element is selected |
| 3044 | const handleNewInlineEditingElementSelected = uid => { |
| 3045 | setTimeout(() => { |
| 3046 | setCurrentInlineEditingElementUid(uid); |
| 3047 | const element = previewRef?.current.querySelector(`[data-acf-inline-fields-uid="${uid}"]`); |
| 3048 | setCurrentInlineEditingElement(element); |
| 3049 | if (element) { |
| 3050 | element.scrollIntoView({ |
| 3051 | behavior: 'smooth', |
| 3052 | block: 'nearest' |
| 3053 | }); |
| 3054 | } |
| 3055 | }, 1); |
| 3056 | }; |
| 3057 | |
| 3058 | // Callback when a new contentEditable element is selected |
| 3059 | const handleNewContentEditableElementSelected = fieldSlug => { |
| 3060 | if (fieldSlug) { |
| 3061 | const element = previewRef?.current.querySelector(`[data-acf-inline-contenteditable-field-slug="${fieldSlug}"]`); |
| 3062 | setCurrentContentEditableElement(element); |
| 3063 | } else { |
| 3064 | setCurrentContentEditableElement(null); |
| 3065 | } |
| 3066 | }; |
| 3067 | let portalTarget = blockEditorInspectorSidebarOpen && inspectorControlsRef?.current ? inspectorControlsRef.current : invisibleBlockFormContainer; |
| 3068 | if (currentFormContainer) { |
| 3069 | portalTarget = currentFormContainer; |
| 3070 | } |
| 3071 | |
| 3072 | // Determine inline editing toolbar anchor (matches 6.7.0.2 logic) |
| 3073 | let inlineEditingToolbarAnchor = null; |
| 3074 | if (currentInlineEditingElement && currentContentEditableElement) { |
| 3075 | inlineEditingToolbarAnchor = currentInlineEditingElement; |
| 3076 | } else if (currentInlineEditingElement && !currentContentEditableElement) { |
| 3077 | inlineEditingToolbarAnchor = currentInlineEditingElement; |
| 3078 | } else if (!currentInlineEditingElement && currentContentEditableElement) { |
| 3079 | inlineEditingToolbarAnchor = currentContentEditableElement; |
| 3080 | } |
| 3081 | // Ensure anchor is connected to DOM |
| 3082 | if (inlineEditingToolbarAnchor && !inlineEditingToolbarAnchor.isConnected) { |
| 3083 | inlineEditingToolbarAnchor = null; |
| 3084 | } |
| 3085 | return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_block_toolbar_fields__WEBPACK_IMPORTED_MODULE_8__.BlockToolbarFields, { |
| 3086 | blockToolbarFields: blockToolbarFields, |
| 3087 | blockFieldInfo: blockFieldInfo, |
| 3088 | setCurrentBlockFormContainer: setCurrentFormContainer, |
| 3089 | gutenbergIframeOrDocument: gutenbergIframeOrDocument, |
| 3090 | setBlockFormModalOpen: setBlockFormModalOpen, |
| 3091 | blockFormModalOpen: blockFormModalOpen, |
| 3092 | invisibleBlockFormContainer: invisibleBlockFormContainer, |
| 3093 | currentInlineEditingElement: currentInlineEditingElement, |
| 3094 | setCurrentInlineEditingElement: setCurrentInlineEditingElement, |
| 3095 | currentInlineEditingElementUid: currentInlineEditingElementUid, |
| 3096 | hideExpandedEditorBtnInToolbar: blockType?.expanded_editor_buttons === false || Array.isArray(blockType?.expanded_editor_buttons) && !blockType?.expanded_editor_buttons.includes('toolbar') || !blockFieldInfo || blockFieldInfo?.length === 0, |
| 3097 | onNewInlineEditingElementSelected: handleNewInlineEditingElementSelected |
| 3098 | }), /*#__PURE__*/React.createElement(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_2__.InspectorControls, null, blockFieldInfo?.length > 0 && (blockType?.expanded_editor_buttons === true || Array.isArray(blockType?.expanded_editor_buttons) && blockType?.expanded_editor_buttons.includes('sidebar')) && /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__.PanelBody, null, /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__.Button, { |
| 3099 | className: "acf-blocks-open-expanded-editor-btn", |
| 3100 | variant: "secondary", |
| 3101 | onClick: () => { |
| 3102 | setBlockFormModalOpen(true); |
| 3103 | }, |
| 3104 | icon: "edit" |
| 3105 | }, blockType?.expanded_editor_button_text || acf.__('Open Expanded Editor'))), /*#__PURE__*/React.createElement(InspectorBlockFormContainer, { |
| 3106 | inspectorBlockFormRef: inspectorControlsRef, |
| 3107 | setCurrentBlockFormContainer: setCurrentFormContainer |
| 3108 | })), portalTarget && canRenderForm && (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.createPortal)(/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_block_form__WEBPACK_IMPORTED_MODULE_5__.BlockForm, { |
| 3109 | $: $, |
| 3110 | clientId: clientId, |
| 3111 | blockFormHtml: blockFormHtml, |
| 3112 | onChange: function ($form) { |
| 3113 | const serializedData = acf.serialize($form, `acf-block_${clientId}`); |
| 3114 | if (serializedData) { |
| 3115 | deserializeGoogleMapValues($form, serializedData, clientId); |
| 3116 | setTheSerializedAcfData(JSON.stringify(serializedData)); |
| 3117 | } |
| 3118 | }, |
| 3119 | validationErrors: validationErrors, |
| 3120 | showValidationErrors: showValidationErrors, |
| 3121 | acfFormRef: acfFormRef, |
| 3122 | userHasInteractedWithForm: userHasInteractedWithForm, |
| 3123 | attributes: attributes, |
| 3124 | hideFieldsInSidebar: blockType?.auto_inline_editing && blockType?.hide_fields_in_sidebar === undefined && currentFormContainer === inspectorControlsRef.current || blockType?.hide_fields_in_sidebar && currentFormContainer === inspectorControlsRef.current |
| 3125 | }), freezeInlineToolbarDuringReRender && /*#__PURE__*/React.createElement("style", null, `.acf-inline-editing-toolbar{${freezeInlineToolbarDuringReRender}}`)), portalTarget), /*#__PURE__*/React.createElement(React.Fragment, null, blockFormModalOpen && /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__.Modal, { |
| 3126 | className: "acf-block-form-modal", |
| 3127 | overlayClassName: acf.applyFilters('blocks/expanded_editor_overlay_class', 'acf-expanded-editor-panel-overlay'), |
| 3128 | isFullScreen: true, |
| 3129 | title: blockType.title, |
| 3130 | onRequestClose: () => { |
| 3131 | if (!isFetchingBlock || validationErrors) { |
| 3132 | setBlockFormModalOpen(false); |
| 3133 | } |
| 3134 | }, |
| 3135 | shouldCloseOnEsc: !isFetchingBlock || validationErrors, |
| 3136 | isDismissible: false, |
| 3137 | headerActions: [/*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__.Button, { |
| 3138 | key: "done", |
| 3139 | variant: "primary", |
| 3140 | disabled: isFetchingBlock && !validationErrors, |
| 3141 | isBusy: isFetchingBlock, |
| 3142 | onClick: closeBlockFormModal |
| 3143 | }, acf.__('Done'))] |
| 3144 | }, shouldShowModalDoneFallback && /*#__PURE__*/React.createElement("div", { |
| 3145 | className: "acf-block-form-modal__actions" |
| 3146 | }, /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__.Button, { |
| 3147 | className: "acf-block-form-modal__done-button", |
| 3148 | variant: "primary", |
| 3149 | disabled: isFetchingBlock && !validationErrors, |
| 3150 | isBusy: isFetchingBlock, |
| 3151 | onClick: closeBlockFormModal |
| 3152 | }, acf.__('Done'))), /*#__PURE__*/React.createElement("div", { |
| 3153 | className: "acf-modal-block-form-container", |
| 3154 | ref: setModalFormContainer |
| 3155 | }))), inlineEditingToolbarAnchor && /*#__PURE__*/React.createElement(_popover_wrapper__WEBPACK_IMPORTED_MODULE_10__.PopoverWrapper, { |
| 3156 | key: currentContentEditableElement, |
| 3157 | focusOnMount: (() => { |
| 3158 | const activeElement = document.activeElement; |
| 3159 | return activeElement && activeElement.isContentEditable, false; |
| 3160 | })(), |
| 3161 | variant: "unstyled", |
| 3162 | anchor: inlineEditingToolbarAnchor, |
| 3163 | className: "acf-inline-editing-toolbar block-editor-block-list__block-popover", |
| 3164 | placement: "top-start", |
| 3165 | onClose: event => { |
| 3166 | // Don't close if clicking toolbar button |
| 3167 | if (event.key !== 'Escape' && event.target.closest('.acf-toolbar-button')) { |
| 3168 | return false; |
| 3169 | } |
| 3170 | |
| 3171 | // Handle Escape key |
| 3172 | if (event.key === 'Escape') { |
| 3173 | return !document.querySelector('.acf-inline-fields-popover-inner') && !currentContentEditableElement && (currentInlineEditingElement && currentInlineEditingElement.focus(), setCurrentInlineEditingElementUid(null), setCurrentContentEditableElement(null), true); |
| 3174 | } |
| 3175 | |
| 3176 | // Don't close if clicking on contenteditable element |
| 3177 | if (event.target.getAttribute('data-acf-inline-contenteditable')) { |
| 3178 | return false; |
| 3179 | } |
| 3180 | |
| 3181 | // Don't close if clicking inside popover or modal |
| 3182 | const inlineFieldsPopover = event.target.closest('.acf-inline-fields-popover-inner'); |
| 3183 | const modal = event.target.closest('.components-modal__content'); |
| 3184 | return inlineFieldsPopover || modal || (setCurrentInlineEditingElementUid(null), setCurrentContentEditableElement(null)), true; |
| 3185 | }, |
| 3186 | gutenbergIframeOrDocument: gutenbergIframeOrDocument, |
| 3187 | hidePrimaryBlockToolbar: true |
| 3188 | }, /*#__PURE__*/React.createElement(_inline_editing_toolbar__WEBPACK_IMPORTED_MODULE_9__.InlineEditingToolbar, { |
| 3189 | key: currentInlineEditingElementUid, |
| 3190 | blockIcon: blockType.icon, |
| 3191 | blockFieldInfo: blockFieldInfo, |
| 3192 | acfFormRef: acfFormRef, |
| 3193 | setInlineEditingToolbarHasFocus: setInlineEditingToolbarHasFocus, |
| 3194 | currentContentEditableElement: currentContentEditableElement, |
| 3195 | currentInlineEditingElement: currentInlineEditingElement, |
| 3196 | currentInlineEditingElementUid: currentInlineEditingElementUid, |
| 3197 | gutenbergIframeOrDocument: gutenbergIframeOrDocument, |
| 3198 | setCurrentBlockFormContainer: setCurrentFormContainer, |
| 3199 | contentEditableChangeInProgress: contentEditableChangeInProgress |
| 3200 | })), currentInlineEditingElementUid && acfDynamicStylesElement && (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.createPortal)(/*#__PURE__*/React.createElement("style", null, ` |
| 3201 | [data-acf-inline-fields-uid="${currentInlineEditingElementUid}"]{ |
| 3202 | outline: 2px solid var( --wp-admin-theme-color ); |
| 3203 | outline-offset: 2px; |
| 3204 | } |
| 3205 | `), acfDynamicStylesElement), /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_block_preview__WEBPACK_IMPORTED_MODULE_6__.BlockPreview, { |
| 3206 | blockPreviewHtml: blockPreviewHtml, |
| 3207 | blockProps: blockProps |
| 3208 | }, /*#__PURE__*/React.createElement(_error_boundary__WEBPACK_IMPORTED_MODULE_7__.ErrorBoundary, { |
| 3209 | fallbackRender: ({ |
| 3210 | error |
| 3211 | }) => /*#__PURE__*/React.createElement(_error_boundary__WEBPACK_IMPORTED_MODULE_7__.BlockPreviewErrorFallback, { |
| 3212 | blockLabel: blockType?.title || acf.__('ACF Block'), |
| 3213 | setBlockFormModalOpen: setBlockFormModalOpen, |
| 3214 | error: error |
| 3215 | }) |
| 3216 | }, blockPreviewHtml === 'acf-block-preview-no-html' ? /*#__PURE__*/React.createElement(_block_placeholder__WEBPACK_IMPORTED_MODULE_4__.BlockPlaceholder, { |
| 3217 | setBlockFormModalOpen: setBlockFormModalOpen, |
| 3218 | blockLabel: blockType.title |
| 3219 | }) : null, blockPreviewHtml === 'acf-block-preview-loading' && /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__.Placeholder, null, /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_3__.Spinner, null)), blockPreviewHtml !== 'acf-block-preview-loading' && blockPreviewHtml !== 'acf-block-preview-no-html' && blockPreviewHtml && acf.parseJSX(blockPreviewHtml, handleNewInlineEditingElementSelected, updateFieldValueFromContentEditable, handleNewContentEditableElementSelected, blockFieldInfo, $))))); |
| 3220 | } |
| 3221 | |
| 3222 | /***/ }), |
| 3223 | |
| 3224 | /***/ "./assets/src/js/pro/blocks-v3/components/block-form.js": |
| 3225 | /*!**************************************************************!*\ |
| 3226 | !*** ./assets/src/js/pro/blocks-v3/components/block-form.js ***! |
| 3227 | \**************************************************************/ |
| 3228 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 3229 | |
| 3230 | "use strict"; |
| 3231 | __webpack_require__.r(__webpack_exports__); |
| 3232 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 3233 | /* harmony export */ BlockForm: () => (/* binding */ BlockForm) |
| 3234 | /* harmony export */ }); |
| 3235 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); |
| 3236 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__); |
| 3237 | /* harmony import */ var _utils_post_locking__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/post-locking */ "./assets/src/js/pro/blocks-v3/utils/post-locking.js"); |
| 3238 | /** |
| 3239 | * BlockForm Component |
| 3240 | * Renders the ACF fields form inside a block and handles form changes, validation, and remounting |
| 3241 | */ |
| 3242 | |
| 3243 | |
| 3244 | |
| 3245 | |
| 3246 | /** |
| 3247 | * BlockForm component |
| 3248 | * Manages ACF field forms within Gutenberg blocks, including validation and change detection |
| 3249 | * |
| 3250 | * @param {Object} props - Component props |
| 3251 | * @param {jQuery} props.$ - jQuery instance |
| 3252 | * @param {string} props.clientId - Block client ID |
| 3253 | * @param {string} props.blockFormHtml - HTML markup for the ACF form |
| 3254 | * @param {Function} props.onMount - Callback when the form mounts |
| 3255 | * @param {Function} props.onChange - Callback when form data changes |
| 3256 | * @param {Array} props.validationErrors - Array of validation error objects |
| 3257 | * @param {boolean} props.showValidationErrors - Whether to display validation errors |
| 3258 | * @param {React.RefObject} props.acfFormRef - Ref to the form container element |
| 3259 | * @param {boolean} props.userHasInteractedWithForm - Whether user has interacted with the form |
| 3260 | * @param {Object} props.attributes - Block attributes |
| 3261 | * @returns {JSX.Element} - Rendered form component |
| 3262 | */ |
| 3263 | const BlockForm = ({ |
| 3264 | $, |
| 3265 | clientId, |
| 3266 | blockFormHtml, |
| 3267 | onMount, |
| 3268 | onChange, |
| 3269 | validationErrors, |
| 3270 | showValidationErrors, |
| 3271 | acfFormRef, |
| 3272 | userHasInteractedWithForm, |
| 3273 | attributes, |
| 3274 | hideFieldsInSidebar |
| 3275 | }) => { |
| 3276 | const [formHtml, setFormHtml] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(blockFormHtml); |
| 3277 | const [pendingChange, setPendingChange] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(false); |
| 3278 | const debounceTimer = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useRef)(null); |
| 3279 | const [userInteracted, setUserInteracted] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(false); |
| 3280 | const [hasRemounted, setHasRemounted] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(false); |
| 3281 | |
| 3282 | // Trigger onChange when there's a pending change |
| 3283 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { |
| 3284 | if (pendingChange && (userHasInteractedWithForm || userInteracted)) { |
| 3285 | onChange(pendingChange); |
| 3286 | setPendingChange(false); |
| 3287 | } |
| 3288 | }, [pendingChange, userHasInteractedWithForm, userInteracted, setPendingChange, onChange]); |
| 3289 | |
| 3290 | // Update form HTML when blockFormHtml prop changes |
| 3291 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { |
| 3292 | if (!formHtml && blockFormHtml) { |
| 3293 | setFormHtml(blockFormHtml); |
| 3294 | } |
| 3295 | }, [blockFormHtml]); |
| 3296 | |
| 3297 | // Handle validation errors |
| 3298 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { |
| 3299 | if (!acfFormRef?.current) return; |
| 3300 | const validator = acf.getBlockFormValidator($(acfFormRef.current).find('.acf-block-fields')); |
| 3301 | validator.clearErrors(); |
| 3302 | validator.set('notice', null); |
| 3303 | acf.doAction('blocks/validation/pre_apply', validationErrors); |
| 3304 | if (validationErrors) { |
| 3305 | if (showValidationErrors) { |
| 3306 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_1__.lockPostSaving)(clientId); |
| 3307 | validator.$el.find('.acf-notice').remove(); |
| 3308 | validator.addErrors(validationErrors); |
| 3309 | validator.showErrors('after'); |
| 3310 | } |
| 3311 | } else { |
| 3312 | // Handle successful validation |
| 3313 | if (validator.$el.find('.acf-notice').length > 0 && showValidationErrors) { |
| 3314 | validator.$el.find('.acf-notice').remove(); |
| 3315 | validator.addErrors([{ |
| 3316 | message: acf.__('Validation successful') |
| 3317 | }]); |
| 3318 | validator.showErrors('after'); |
| 3319 | validator.get('notice').update({ |
| 3320 | type: 'success', |
| 3321 | text: acf.__('Validation successful'), |
| 3322 | timeout: 1000 |
| 3323 | }); |
| 3324 | validator.set('notice', null); |
| 3325 | setTimeout(() => { |
| 3326 | validator.$el.find('.acf-notice').remove(); |
| 3327 | }, 1001); |
| 3328 | const noticeDispatch = wp.data.dispatch('core/notices'); |
| 3329 | |
| 3330 | /** |
| 3331 | * Recursively checks for ACF errors in blocks |
| 3332 | * @param {Array} blocks - Array of block objects |
| 3333 | * @returns {Promise<boolean>} - True if error found |
| 3334 | */ |
| 3335 | function checkForErrors(blocks) { |
| 3336 | return new Promise(function (resolve) { |
| 3337 | blocks.forEach(block => { |
| 3338 | if (block.innerBlocks.length > 0) { |
| 3339 | checkForErrors(block.innerBlocks).then(hasError => { |
| 3340 | if (hasError) return resolve(true); |
| 3341 | }); |
| 3342 | } |
| 3343 | if (block.attributes.hasAcfError && block.clientId !== clientId) { |
| 3344 | return resolve(true); |
| 3345 | } |
| 3346 | }); |
| 3347 | return resolve(false); |
| 3348 | }); |
| 3349 | } |
| 3350 | checkForErrors(wp.data.select('core/block-editor').getBlocks()).then(hasError => { |
| 3351 | if (hasError) { |
| 3352 | noticeDispatch.createErrorNotice(acf.__('An ACF Block on this page requires attention before you can save.'), { |
| 3353 | id: 'acf-blocks-validation', |
| 3354 | isDismissible: true |
| 3355 | }); |
| 3356 | } else { |
| 3357 | noticeDispatch.removeNotice('acf-blocks-validation'); |
| 3358 | } |
| 3359 | }); |
| 3360 | } |
| 3361 | (0,_utils_post_locking__WEBPACK_IMPORTED_MODULE_1__.unlockPostSaving)(clientId); |
| 3362 | } |
| 3363 | acf.doAction('blocks/validation/post_apply', validationErrors); |
| 3364 | }, [validationErrors, clientId, showValidationErrors]); |
| 3365 | |
| 3366 | // Handle form remounting and change detection |
| 3367 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { |
| 3368 | if (!acfFormRef?.current || !formHtml) return; |
| 3369 | acf.debug('Remounting ACF Form'); |
| 3370 | const formElement = acfFormRef.current; |
| 3371 | const $form = $(formElement); |
| 3372 | let isActive = true; |
| 3373 | if (!hasRemounted) { |
| 3374 | acf.debug('Remounting ACF Form'); |
| 3375 | acf.doAction('remount', $form); |
| 3376 | onMount?.($form); |
| 3377 | setHasRemounted(true); |
| 3378 | } |
| 3379 | const handleChange = () => { |
| 3380 | onChange($form); |
| 3381 | }; |
| 3382 | const scheduleChange = () => { |
| 3383 | if (!isActive) return; |
| 3384 | const inputs = formElement.querySelectorAll('input, textarea'); |
| 3385 | const selects = formElement.querySelectorAll('select'); |
| 3386 | inputs.forEach(input => { |
| 3387 | input.removeEventListener('input', handleChange); |
| 3388 | input.addEventListener('input', handleChange); |
| 3389 | input.removeEventListener('change', handleChange); |
| 3390 | input.addEventListener('change', handleChange); |
| 3391 | }); |
| 3392 | selects.forEach(select => { |
| 3393 | select.removeEventListener('change', handleChange); |
| 3394 | select.addEventListener('change', handleChange); |
| 3395 | }); |
| 3396 | clearTimeout(debounceTimer.current); |
| 3397 | debounceTimer.current = setTimeout(() => { |
| 3398 | if (isActive) { |
| 3399 | setPendingChange($form); |
| 3400 | } |
| 3401 | }, 300); |
| 3402 | }; |
| 3403 | |
| 3404 | // Observe DOM changes to detect field additions/removals |
| 3405 | const domObserver = new MutationObserver(scheduleChange); |
| 3406 | |
| 3407 | // Observe iframe content changes (for WYSIWYG editors) |
| 3408 | const iframeObserver = new MutationObserver(() => { |
| 3409 | if (isActive) { |
| 3410 | setUserInteracted(true); |
| 3411 | scheduleChange(); |
| 3412 | } |
| 3413 | }); |
| 3414 | const observerConfig = { |
| 3415 | attributes: true, |
| 3416 | childList: true, |
| 3417 | subtree: true, |
| 3418 | characterData: true |
| 3419 | }; |
| 3420 | domObserver.observe(formElement, observerConfig); |
| 3421 | |
| 3422 | // Watch for changes in iframes (WYSIWYG fields) |
| 3423 | [...formElement.querySelectorAll('iframe')].forEach(iframe => { |
| 3424 | if (iframe && iframe.contentDocument) { |
| 3425 | const iframeBody = iframe.contentDocument.body; |
| 3426 | if (iframeBody) { |
| 3427 | iframeObserver.observe(iframeBody, observerConfig); |
| 3428 | } |
| 3429 | } |
| 3430 | }); |
| 3431 | |
| 3432 | // Attach event listeners to form inputs |
| 3433 | formElement.querySelectorAll('input, textarea').forEach(input => { |
| 3434 | input.addEventListener('input', handleChange); |
| 3435 | input.addEventListener('change', handleChange); |
| 3436 | }); |
| 3437 | formElement.querySelectorAll('select').forEach(select => { |
| 3438 | select.addEventListener('change', handleChange); |
| 3439 | }); |
| 3440 | if (userHasInteractedWithForm) { |
| 3441 | clearTimeout(debounceTimer.current); |
| 3442 | debounceTimer.current = setTimeout(() => { |
| 3443 | if (isActive) { |
| 3444 | setPendingChange($form); |
| 3445 | } |
| 3446 | }, 300); |
| 3447 | } |
| 3448 | |
| 3449 | // Cleanup function |
| 3450 | return () => { |
| 3451 | isActive = false; |
| 3452 | domObserver.disconnect(); |
| 3453 | iframeObserver.disconnect(); |
| 3454 | clearTimeout(debounceTimer.current); |
| 3455 | if (formElement) { |
| 3456 | formElement.querySelectorAll('input, textarea').forEach(input => { |
| 3457 | input.removeEventListener('input', handleChange); |
| 3458 | input.removeEventListener('change', handleChange); |
| 3459 | }); |
| 3460 | formElement.querySelectorAll('select').forEach(select => { |
| 3461 | select.removeEventListener('change', handleChange); |
| 3462 | }); |
| 3463 | } |
| 3464 | }; |
| 3465 | }, [acfFormRef, attributes, formHtml, onMount, userHasInteractedWithForm]); |
| 3466 | return /*#__PURE__*/React.createElement("div", { |
| 3467 | ref: acfFormRef, |
| 3468 | className: "acf-block-component acf-block-panel", |
| 3469 | style: { |
| 3470 | display: hideFieldsInSidebar ? 'none' : null |
| 3471 | }, |
| 3472 | dangerouslySetInnerHTML: { |
| 3473 | __html: acf.applyFilters('blocks/form/render', formHtml, true) |
| 3474 | } |
| 3475 | }); |
| 3476 | }; |
| 3477 | |
| 3478 | /***/ }), |
| 3479 | |
| 3480 | /***/ "./assets/src/js/pro/blocks-v3/components/block-placeholder.js": |
| 3481 | /*!*********************************************************************!*\ |
| 3482 | !*** ./assets/src/js/pro/blocks-v3/components/block-placeholder.js ***! |
| 3483 | \*********************************************************************/ |
| 3484 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 3485 | |
| 3486 | "use strict"; |
| 3487 | __webpack_require__.r(__webpack_exports__); |
| 3488 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 3489 | /* harmony export */ BlockPlaceholder: () => (/* binding */ BlockPlaceholder) |
| 3490 | /* harmony export */ }); |
| 3491 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components"); |
| 3492 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_0__); |
| 3493 | /** |
| 3494 | * BlockPlaceholder Component |
| 3495 | * Displays a placeholder UI when block has no preview HTML |
| 3496 | */ |
| 3497 | |
| 3498 | |
| 3499 | /** |
| 3500 | * SVG icon for the block placeholder |
| 3501 | * Represents a generic block/form icon |
| 3502 | */ |
| 3503 | const blockIcon = /*#__PURE__*/React.createElement("svg", { |
| 3504 | xmlns: "http://www.w3.org/2000/svg", |
| 3505 | viewBox: "0 0 24 24", |
| 3506 | width: "24", |
| 3507 | height: "24", |
| 3508 | "aria-hidden": "true", |
| 3509 | focusable: "false" |
| 3510 | }, /*#__PURE__*/React.createElement("path", { |
| 3511 | d: "M19 8h-1V6h-5v2h-2V6H6v2H5c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-8c0-1.1-.9-2-2-2zm.5 10c0 .3-.2.5-.5.5H5c-.3 0-.5-.2-.5-.5v-8c0-.3.2-.5.5-.5h14c.3 0 .5.2.5.5v8z" |
| 3512 | })); |
| 3513 | |
| 3514 | /** |
| 3515 | * BlockPlaceholder component |
| 3516 | * Shows when a block has no preview HTML available |
| 3517 | * Prompts user to open the block form to edit fields |
| 3518 | * |
| 3519 | * @param {Object} props - Component props |
| 3520 | * @param {Function} props.setBlockFormModalOpen - Function to open the block form modal |
| 3521 | * @param {string} props.blockLabel - The block's title/label |
| 3522 | * @returns {JSX.Element} - Rendered placeholder |
| 3523 | */ |
| 3524 | const BlockPlaceholder = ({ |
| 3525 | setBlockFormModalOpen, |
| 3526 | blockLabel, |
| 3527 | instructions |
| 3528 | }) => { |
| 3529 | return /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_0__.Placeholder, { |
| 3530 | icon: /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_0__.Icon, { |
| 3531 | icon: blockIcon |
| 3532 | }), |
| 3533 | label: blockLabel, |
| 3534 | instructions: instructions |
| 3535 | }, /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_0__.Button, { |
| 3536 | variant: "primary", |
| 3537 | onClick: () => { |
| 3538 | setBlockFormModalOpen(true); |
| 3539 | } |
| 3540 | }, acf.__('Edit Block'))); |
| 3541 | }; |
| 3542 | |
| 3543 | /***/ }), |
| 3544 | |
| 3545 | /***/ "./assets/src/js/pro/blocks-v3/components/block-preview.js": |
| 3546 | /*!*****************************************************************!*\ |
| 3547 | !*** ./assets/src/js/pro/blocks-v3/components/block-preview.js ***! |
| 3548 | \*****************************************************************/ |
| 3549 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 3550 | |
| 3551 | "use strict"; |
| 3552 | __webpack_require__.r(__webpack_exports__); |
| 3553 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 3554 | /* harmony export */ BlockPreview: () => (/* binding */ BlockPreview) |
| 3555 | /* harmony export */ }); |
| 3556 | /** |
| 3557 | * BlockPreview Component |
| 3558 | * Simple wrapper component that renders block preview HTML with block props |
| 3559 | */ |
| 3560 | |
| 3561 | /** |
| 3562 | * BlockPreview component |
| 3563 | * Wraps block preview content with the appropriate block props from useBlockProps |
| 3564 | * |
| 3565 | * @param {Object} props - Component props |
| 3566 | * @param {React.ReactNode} props.children - Child elements to render |
| 3567 | * @param {Object} props.blockProps - Block props from useBlockProps hook |
| 3568 | * @returns {JSX.Element} - Rendered preview wrapper |
| 3569 | */ |
| 3570 | const BlockPreview = ({ |
| 3571 | children, |
| 3572 | blockProps |
| 3573 | }) => /*#__PURE__*/React.createElement("div", blockProps, children); |
| 3574 | |
| 3575 | /***/ }), |
| 3576 | |
| 3577 | /***/ "./assets/src/js/pro/blocks-v3/components/block-toolbar-fields.js": |
| 3578 | /*!************************************************************************!*\ |
| 3579 | !*** ./assets/src/js/pro/blocks-v3/components/block-toolbar-fields.js ***! |
| 3580 | \************************************************************************/ |
| 3581 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 3582 | |
| 3583 | "use strict"; |
| 3584 | __webpack_require__.r(__webpack_exports__); |
| 3585 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 3586 | /* harmony export */ BlockToolbarFields: () => (/* binding */ BlockToolbarFields) |
| 3587 | /* harmony export */ }); |
| 3588 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); |
| 3589 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__); |
| 3590 | /* harmony import */ var _wordpress_blockEditor__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/blockEditor */ "@wordpress/block-editor"); |
| 3591 | /* harmony import */ var _wordpress_blockEditor__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_blockEditor__WEBPACK_IMPORTED_MODULE_1__); |
| 3592 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components"); |
| 3593 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__); |
| 3594 | /* harmony import */ var _popover_wrapper__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./popover-wrapper */ "./assets/src/js/pro/blocks-v3/components/popover-wrapper.js"); |
| 3595 | /** |
| 3596 | * BlockToolbarFields Component |
| 3597 | * Renders field buttons in the WordPress block toolbar (top toolbar) |
| 3598 | * Allows quick access to edit specific fields from the block toolbar |
| 3599 | */ |
| 3600 | |
| 3601 | /* global acf */ |
| 3602 | |
| 3603 | |
| 3604 | |
| 3605 | |
| 3606 | |
| 3607 | |
| 3608 | /** |
| 3609 | * BlockToolbarFields component |
| 3610 | * Displays field editing buttons in the WordPress block toolbar |
| 3611 | * |
| 3612 | * @param {Object} props - Component props |
| 3613 | * @param {Array} props.blockToolbarFields - Array of field names or field config objects to show in toolbar |
| 3614 | * @param {Array} props.blockFieldInfo - Array of all field information |
| 3615 | * @param {Function} props.setCurrentBlockFormContainer - Setter for form container ref |
| 3616 | * @param {Document|HTMLIFrameElement} props.gutenbergIframeOrDocument - Document or iframe reference |
| 3617 | * @param {Function} props.setBlockFormModalOpen - Setter for block form modal state |
| 3618 | * @param {boolean} props.blockFormModalOpen - Whether block form modal is open |
| 3619 | * @param {boolean} props.hideExpandedEditorBtnInToolbar - Whether to hide the expanded editor button in the toolbar |
| 3620 | * @return {JSX.Element} - Rendered toolbar controls |
| 3621 | */ |
| 3622 | const BlockToolbarFields = ({ |
| 3623 | blockToolbarFields, |
| 3624 | blockFieldInfo, |
| 3625 | setCurrentBlockFormContainer, |
| 3626 | gutenbergIframeOrDocument, |
| 3627 | setBlockFormModalOpen, |
| 3628 | blockFormModalOpen, |
| 3629 | hideExpandedEditorBtnInToolbar |
| 3630 | }) => { |
| 3631 | const [selectedFieldKey, setSelectedFieldKey] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(null); |
| 3632 | const [selectedFieldButtonRef, setSelectedFieldButtonRef] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(); |
| 3633 | const [usePopover, setUsePopover] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(true); |
| 3634 | const fieldPopoverContainerRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useRef)(); |
| 3635 | |
| 3636 | /** |
| 3637 | * Get field type class name from field name |
| 3638 | * |
| 3639 | * @param {string} fieldName Field name. |
| 3640 | * @return {string} Field type class name. |
| 3641 | */ |
| 3642 | const getFieldTypeClassName = fieldName => { |
| 3643 | if (!fieldName || !blockFieldInfo) { |
| 3644 | return ''; |
| 3645 | } |
| 3646 | const field = blockFieldInfo.find(f => f.name === fieldName); |
| 3647 | return field?.type ? field.type.replace(/_/g, '-') : ''; |
| 3648 | }; |
| 3649 | |
| 3650 | /** |
| 3651 | * Get field info object from field name |
| 3652 | * |
| 3653 | * @param {string} fieldName Field name. |
| 3654 | * @return {Object|null} Field info object. |
| 3655 | */ |
| 3656 | const getFieldInfo = fieldName => { |
| 3657 | return fieldName && blockFieldInfo ? blockFieldInfo.find(f => f.name === fieldName) : null; |
| 3658 | }; |
| 3659 | |
| 3660 | /** |
| 3661 | * Get field label from field name |
| 3662 | * |
| 3663 | * @param {string} fieldName Field name. |
| 3664 | * @return {string} Field label. |
| 3665 | */ |
| 3666 | const getFieldLabel = fieldName => { |
| 3667 | if (!fieldName || !blockFieldInfo) { |
| 3668 | return fieldName || ''; |
| 3669 | } |
| 3670 | const field = blockFieldInfo.find(f => f.name === fieldName); |
| 3671 | // Fallback to fieldName when label not found to ensure toolbar shows a title |
| 3672 | return field?.label || fieldName || ''; |
| 3673 | }; |
| 3674 | return /*#__PURE__*/React.createElement(_wordpress_blockEditor__WEBPACK_IMPORTED_MODULE_1__.BlockControls, null, !hideExpandedEditorBtnInToolbar && /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.ToolbarGroup, null, /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.ToolbarButton, { |
| 3675 | className: "components-icon-button components-toolbar__control", |
| 3676 | label: acf.__('Edit Block'), |
| 3677 | icon: "edit", |
| 3678 | onClick: () => { |
| 3679 | setBlockFormModalOpen(true); |
| 3680 | }, |
| 3681 | isPressed: blockFormModalOpen |
| 3682 | })), blockToolbarFields.length > 0 && /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.ToolbarGroup, null, (() => { |
| 3683 | const styleContent = `[data-name="${selectedFieldKey}"]{ display: block!important; }`; |
| 3684 | return /*#__PURE__*/React.createElement("style", null, styleContent); |
| 3685 | })(), blockToolbarFields && blockToolbarFields.map(field => { |
| 3686 | let fieldName = ''; |
| 3687 | let fieldIconSvg = null; |
| 3688 | let fieldLabel = null; |
| 3689 | |
| 3690 | // Handle field config object or simple string |
| 3691 | if (typeof field === 'object') { |
| 3692 | fieldName = field.fieldName ? field.fieldName : field.index; |
| 3693 | fieldIconSvg = field.fieldIcon ? window.atob(field.fieldIcon) : null; |
| 3694 | fieldLabel = field.fieldLabel ? field.fieldLabel : fieldName; |
| 3695 | } else { |
| 3696 | fieldName = field; |
| 3697 | } |
| 3698 | return /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.ToolbarButton, { |
| 3699 | key: fieldName, |
| 3700 | icon: fieldIconSvg ? /*#__PURE__*/React.createElement("i", { |
| 3701 | dangerouslySetInnerHTML: { |
| 3702 | __html: fieldIconSvg |
| 3703 | } |
| 3704 | }) : /*#__PURE__*/React.createElement("i", { |
| 3705 | className: `field-type-icon field-type-icon-${getFieldTypeClassName(fieldName)}` |
| 3706 | }), |
| 3707 | label: fieldLabel || getFieldLabel(fieldName), |
| 3708 | isPressed: fieldName === selectedFieldKey, |
| 3709 | ref: fieldName === selectedFieldKey ? setSelectedFieldButtonRef : null, |
| 3710 | onMouseDown: () => { |
| 3711 | if (selectedFieldKey === fieldName) { |
| 3712 | setSelectedFieldKey(null); |
| 3713 | } else { |
| 3714 | setSelectedFieldKey(null); |
| 3715 | setTimeout(() => { |
| 3716 | const fieldInfo = getFieldInfo(fieldName); |
| 3717 | // Use modal for complex field types |
| 3718 | if (fieldInfo?.type === 'flexible_content' || fieldInfo?.type === 'repeater') { |
| 3719 | setUsePopover(false); |
| 3720 | } else { |
| 3721 | setUsePopover(true); |
| 3722 | } |
| 3723 | setSelectedFieldKey(fieldName); |
| 3724 | }); |
| 3725 | } |
| 3726 | } |
| 3727 | }); |
| 3728 | }), selectedFieldKey && selectedFieldButtonRef && usePopover && /*#__PURE__*/React.createElement(_popover_wrapper__WEBPACK_IMPORTED_MODULE_3__.PopoverWrapper, { |
| 3729 | focusOnMount: false, |
| 3730 | className: "acf-inline-fields-popover", |
| 3731 | anchor: selectedFieldButtonRef, |
| 3732 | animate: true, |
| 3733 | onClose: event => { |
| 3734 | // Don't close on certain events |
| 3735 | if (event.key !== 'Escape' && (event?.target.closest('.media-modal') || event?.target.closest('.acf-tooltip') || event?.target && fieldPopoverContainerRef?.current && fieldPopoverContainerRef?.current.contains(event.target) || selectedFieldButtonRef?.current && selectedFieldButtonRef?.current.contains(event?.target))) { |
| 3736 | return false; |
| 3737 | } |
| 3738 | setSelectedFieldKey(null); |
| 3739 | return true; |
| 3740 | }, |
| 3741 | variant: "unstyled", |
| 3742 | gutenbergIframeOrDocument: gutenbergIframeOrDocument |
| 3743 | }, /*#__PURE__*/React.createElement("div", { |
| 3744 | ref: fieldPopoverContainerRef |
| 3745 | }, /*#__PURE__*/React.createElement("div", { |
| 3746 | className: "acf-inline-fields-popover-inner", |
| 3747 | style: { |
| 3748 | minWidth: '300px' |
| 3749 | }, |
| 3750 | ref: setCurrentBlockFormContainer |
| 3751 | }))), selectedFieldKey && selectedFieldButtonRef && !usePopover && /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.Modal, { |
| 3752 | className: "acf-block-form-modal", |
| 3753 | isFullScreen: true, |
| 3754 | title: getFieldInfo(selectedFieldKey)?.label, |
| 3755 | onRequestClose: () => { |
| 3756 | setSelectedFieldKey(null); |
| 3757 | } |
| 3758 | }, /*#__PURE__*/React.createElement("div", { |
| 3759 | ref: fieldPopoverContainerRef |
| 3760 | }, /*#__PURE__*/React.createElement("div", { |
| 3761 | className: "acf-inline-fields-popover-inner", |
| 3762 | style: { |
| 3763 | minWidth: '300px' |
| 3764 | }, |
| 3765 | ref: setCurrentBlockFormContainer |
| 3766 | }))))); |
| 3767 | }; |
| 3768 | |
| 3769 | /***/ }), |
| 3770 | |
| 3771 | /***/ "./assets/src/js/pro/blocks-v3/components/error-boundary.js": |
| 3772 | /*!******************************************************************!*\ |
| 3773 | !*** ./assets/src/js/pro/blocks-v3/components/error-boundary.js ***! |
| 3774 | \******************************************************************/ |
| 3775 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 3776 | |
| 3777 | "use strict"; |
| 3778 | __webpack_require__.r(__webpack_exports__); |
| 3779 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 3780 | /* harmony export */ BlockPreviewErrorFallback: () => (/* binding */ BlockPreviewErrorFallback), |
| 3781 | /* harmony export */ ErrorBoundary: () => (/* binding */ ErrorBoundary), |
| 3782 | /* harmony export */ ErrorBoundaryContext: () => (/* binding */ ErrorBoundaryContext) |
| 3783 | /* harmony export */ }); |
| 3784 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); |
| 3785 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__); |
| 3786 | /* harmony import */ var _block_placeholder__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./block-placeholder */ "./assets/src/js/pro/blocks-v3/components/block-placeholder.js"); |
| 3787 | |
| 3788 | |
| 3789 | |
| 3790 | // Create context outside the class |
| 3791 | const ErrorBoundaryContext = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.createContext)(null); |
| 3792 | |
| 3793 | // Initial state constant |
| 3794 | const initialState = { |
| 3795 | didCatch: false, |
| 3796 | error: null |
| 3797 | }; |
| 3798 | |
| 3799 | // Error Boundary Component |
| 3800 | class ErrorBoundary extends _wordpress_element__WEBPACK_IMPORTED_MODULE_0__.Component { |
| 3801 | constructor(props) { |
| 3802 | super(props); |
| 3803 | this.resetErrorBoundary = this.resetErrorBoundary.bind(this); |
| 3804 | this.state = initialState; |
| 3805 | } |
| 3806 | static getDerivedStateFromError(error) { |
| 3807 | return { |
| 3808 | didCatch: true, |
| 3809 | error: error |
| 3810 | }; |
| 3811 | } |
| 3812 | resetErrorBoundary() { |
| 3813 | const { |
| 3814 | error |
| 3815 | } = this.state; |
| 3816 | if (error !== null) { |
| 3817 | // Collect all arguments passed to reset |
| 3818 | const args = Array.from(arguments); |
| 3819 | |
| 3820 | // Call optional onReset callback with context |
| 3821 | if (this.props.onReset) { |
| 3822 | this.props.onReset({ |
| 3823 | args: args, |
| 3824 | reason: 'imperative-api' |
| 3825 | }); |
| 3826 | } |
| 3827 | this.setState(initialState); |
| 3828 | } |
| 3829 | } |
| 3830 | componentDidCatch(error, errorInfo) { |
| 3831 | if (this.props.onError) { |
| 3832 | this.props.onError(error, errorInfo); |
| 3833 | } |
| 3834 | } |
| 3835 | componentDidUpdate(prevProps, prevState) { |
| 3836 | const { |
| 3837 | didCatch |
| 3838 | } = this.state; |
| 3839 | const { |
| 3840 | resetKeys |
| 3841 | } = this.props; |
| 3842 | |
| 3843 | // Auto-reset if resetKeys prop changed |
| 3844 | if (didCatch && prevState.error !== null && hasResetKeysChanged(prevProps.resetKeys, resetKeys)) { |
| 3845 | if (this.props.onReset) { |
| 3846 | this.props.onReset({ |
| 3847 | next: resetKeys, |
| 3848 | prev: prevProps.resetKeys, |
| 3849 | reason: 'keys' |
| 3850 | }); |
| 3851 | } |
| 3852 | this.setState(initialState); |
| 3853 | } |
| 3854 | } |
| 3855 | render() { |
| 3856 | const { |
| 3857 | children, |
| 3858 | fallbackRender, |
| 3859 | FallbackComponent, |
| 3860 | fallback |
| 3861 | } = this.props; |
| 3862 | const { |
| 3863 | didCatch, |
| 3864 | error |
| 3865 | } = this.state; |
| 3866 | let content = children; |
| 3867 | if (didCatch) { |
| 3868 | const errorProps = { |
| 3869 | error: error, |
| 3870 | resetErrorBoundary: this.resetErrorBoundary |
| 3871 | }; |
| 3872 | if (typeof fallbackRender === 'function') { |
| 3873 | content = fallbackRender(errorProps); |
| 3874 | } else if (FallbackComponent) { |
| 3875 | content = /*#__PURE__*/React.createElement(FallbackComponent, errorProps); |
| 3876 | } else if (fallback !== undefined) { |
| 3877 | content = fallback; |
| 3878 | } else { |
| 3879 | throw error; |
| 3880 | } |
| 3881 | } |
| 3882 | return /*#__PURE__*/React.createElement(ErrorBoundaryContext.Provider, { |
| 3883 | value: { |
| 3884 | didCatch, |
| 3885 | error, |
| 3886 | resetErrorBoundary: this.resetErrorBoundary |
| 3887 | } |
| 3888 | }, content); |
| 3889 | } |
| 3890 | } |
| 3891 | |
| 3892 | // Helper function to check if reset keys changed |
| 3893 | function hasResetKeysChanged(prevKeys = [], nextKeys = []) { |
| 3894 | return prevKeys.length !== nextKeys.length || prevKeys.some((key, index) => !Object.is(key, nextKeys[index])); |
| 3895 | } |
| 3896 | const BlockPreviewErrorFallback = ({ |
| 3897 | setBlockFormModalOpen, |
| 3898 | blockLabel, |
| 3899 | error |
| 3900 | }) => { |
| 3901 | let errorMessage = null; |
| 3902 | if (error) { |
| 3903 | acf.debug('Block preview error:', error); |
| 3904 | errorMessage = acf.__('Error previewing block v3'); |
| 3905 | } |
| 3906 | return /*#__PURE__*/React.createElement(_block_placeholder__WEBPACK_IMPORTED_MODULE_1__.BlockPlaceholder, { |
| 3907 | setBlockFormModalOpen: setBlockFormModalOpen, |
| 3908 | blockLabel: blockLabel, |
| 3909 | instructions: errorMessage |
| 3910 | }); |
| 3911 | }; |
| 3912 | |
| 3913 | /***/ }), |
| 3914 | |
| 3915 | /***/ "./assets/src/js/pro/blocks-v3/components/inline-editing-toolbar.js": |
| 3916 | /*!**************************************************************************!*\ |
| 3917 | !*** ./assets/src/js/pro/blocks-v3/components/inline-editing-toolbar.js ***! |
| 3918 | \**************************************************************************/ |
| 3919 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 3920 | |
| 3921 | "use strict"; |
| 3922 | __webpack_require__.r(__webpack_exports__); |
| 3923 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 3924 | /* harmony export */ InlineEditingToolbar: () => (/* binding */ InlineEditingToolbar) |
| 3925 | /* harmony export */ }); |
| 3926 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); |
| 3927 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__); |
| 3928 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components"); |
| 3929 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__); |
| 3930 | /* harmony import */ var _popover_wrapper__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./popover-wrapper */ "./assets/src/js/pro/blocks-v3/components/popover-wrapper.js"); |
| 3931 | /** |
| 3932 | * InlineEditingToolbar Component |
| 3933 | * Main inline editing toolbar for ACF blocks |
| 3934 | * Handles field selection and editing for inline editable elements |
| 3935 | */ |
| 3936 | |
| 3937 | |
| 3938 | |
| 3939 | |
| 3940 | |
| 3941 | /** |
| 3942 | * InlineEditingToolbar component |
| 3943 | * Displays a toolbar with field buttons for inline editing |
| 3944 | * |
| 3945 | * @param {Object} props - Component props |
| 3946 | * @param {Object} props.blockIcon - Block icon configuration |
| 3947 | * @param {Array} props.blockFieldInfo - Array of field information |
| 3948 | * @param {Function} props.setInlineEditingToolbarHasFocus - Setter for toolbar focus state |
| 3949 | * @param {Element|null} props.currentContentEditableElement - Current content editable element |
| 3950 | * @param {Element|null} props.currentInlineEditingElement - Current inline editing element |
| 3951 | * @param {string|null} props.currentInlineEditingElementUid - Current element UID |
| 3952 | * @param {Document|HTMLIFrameElement} props.gutenbergIframeOrDocument - Document or iframe reference |
| 3953 | * @param {Function} props.setCurrentBlockFormContainer - Setter for form container |
| 3954 | * @param {boolean} props.contentEditableChangeInProgress - Whether content change is in progress |
| 3955 | * @returns {JSX.Element|null} - Rendered toolbar or null |
| 3956 | */ |
| 3957 | const InlineEditingToolbar = ({ |
| 3958 | blockIcon, |
| 3959 | blockFieldInfo, |
| 3960 | setInlineEditingToolbarHasFocus, |
| 3961 | currentContentEditableElement, |
| 3962 | currentInlineEditingElement, |
| 3963 | currentInlineEditingElementUid, |
| 3964 | gutenbergIframeOrDocument, |
| 3965 | setCurrentBlockFormContainer, |
| 3966 | contentEditableChangeInProgress |
| 3967 | }) => { |
| 3968 | const [selectedFieldKey, setSelectedFieldKey] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(null); |
| 3969 | const [selectedFieldConfig, setSelectedFieldConfig] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(); |
| 3970 | const [selectedFieldButtonRef, setSelectedFieldButtonRef] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(); |
| 3971 | const [usePopover, setUsePopover] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useState)(true); |
| 3972 | const fieldPopoverContainerRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useRef)(); |
| 3973 | |
| 3974 | // Get inline fields from data attribute |
| 3975 | const inlineFieldsAttr = currentInlineEditingElement ? currentInlineEditingElement.getAttribute('data-acf-inline-fields') : null; |
| 3976 | let inlineFields = []; |
| 3977 | try { |
| 3978 | inlineFields = JSON.parse(inlineFieldsAttr); |
| 3979 | } catch (e) { |
| 3980 | acf.debug('Inline fields were not a properly formatted JSON array', inlineFieldsAttr); |
| 3981 | } |
| 3982 | |
| 3983 | /** |
| 3984 | * Get field type class name from field name |
| 3985 | */ |
| 3986 | function getFieldTypeClassName(fieldName) { |
| 3987 | if (!fieldName || !blockFieldInfo) return ''; |
| 3988 | const field = blockFieldInfo.find(f => f.name === fieldName); |
| 3989 | return field?.type ? field.type.replace(/_/g, '-') : ''; |
| 3990 | } |
| 3991 | |
| 3992 | /** |
| 3993 | * Get field label from field name |
| 3994 | */ |
| 3995 | function getFieldLabel(fieldName) { |
| 3996 | if (!fieldName || !blockFieldInfo) return ''; |
| 3997 | const field = blockFieldInfo.find(f => f.name === fieldName); |
| 3998 | return field ? field.label : ''; |
| 3999 | } |
| 4000 | |
| 4001 | // Clear selected field when content editable changes |
| 4002 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { |
| 4003 | setSelectedFieldKey(null); |
| 4004 | }, [contentEditableChangeInProgress]); |
| 4005 | |
| 4006 | // Generate toolbar icon |
| 4007 | const toolbarIcon = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => { |
| 4008 | let icon = currentContentEditableElement && !currentInlineEditingElement ? currentContentEditableElement.getAttribute('data-acf-toolbar-icon') : null; |
| 4009 | if (!icon && currentInlineEditingElement) { |
| 4010 | icon = currentInlineEditingElement ? currentInlineEditingElement.getAttribute('data-acf-toolbar-icon') : null; |
| 4011 | } |
| 4012 | if (icon) { |
| 4013 | icon = /*#__PURE__*/React.createElement("i", { |
| 4014 | dangerouslySetInnerHTML: { |
| 4015 | __html: icon |
| 4016 | } |
| 4017 | }); |
| 4018 | } |
| 4019 | if (!icon && currentContentEditableElement && !currentInlineEditingElement) { |
| 4020 | const fieldSlug = currentContentEditableElement.getAttribute('data-acf-inline-contenteditable-field-slug'); |
| 4021 | icon = /*#__PURE__*/React.createElement("i", { |
| 4022 | className: `field-type-icon field-type-icon-${getFieldTypeClassName(fieldSlug)}` |
| 4023 | }); |
| 4024 | } |
| 4025 | if (!icon) { |
| 4026 | icon = React.isValidElement(blockIcon) ? blockIcon : /*#__PURE__*/React.createElement("span", { |
| 4027 | className: `dashicon dashicons dashicons-${blockIcon}` |
| 4028 | }); |
| 4029 | } |
| 4030 | return icon; |
| 4031 | }, [blockFieldInfo, currentContentEditableElement, currentInlineEditingElement]); |
| 4032 | |
| 4033 | // Generate toolbar title |
| 4034 | const toolbarTitle = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useMemo)(() => { |
| 4035 | let fieldName; |
| 4036 | if (currentContentEditableElement && !currentInlineEditingElement) { |
| 4037 | const title = currentContentEditableElement.getAttribute('data-acf-toolbar-title'); |
| 4038 | if (title) return title; |
| 4039 | fieldName = currentContentEditableElement.getAttribute('data-acf-inline-contenteditable-field-slug'); |
| 4040 | } else if (currentInlineEditingElement) { |
| 4041 | const title = currentInlineEditingElement.getAttribute('data-acf-toolbar-title'); |
| 4042 | if (title) return title; |
| 4043 | if (inlineFields.length > 1) { |
| 4044 | const elementTypeLabels = { |
| 4045 | A: 'Link', |
| 4046 | DIV: 'Division', |
| 4047 | P: 'Paragraph', |
| 4048 | SPAN: 'Span', |
| 4049 | INPUT: 'Input', |
| 4050 | BUTTON: 'Button', |
| 4051 | IMG: 'Image', |
| 4052 | UL: 'Unordered List', |
| 4053 | OL: 'Ordered List', |
| 4054 | LI: 'List Item', |
| 4055 | H1: 'Heading 1', |
| 4056 | H2: 'Heading 2', |
| 4057 | H3: 'Heading 3', |
| 4058 | H4: 'Heading 4', |
| 4059 | H5: 'Heading 5', |
| 4060 | H6: 'Heading 6', |
| 4061 | TABLE: 'Table', |
| 4062 | TR: 'Table Row', |
| 4063 | TD: 'Table Cell', |
| 4064 | TH: 'Table Header', |
| 4065 | FORM: 'Form', |
| 4066 | TEXTAREA: 'Text Area', |
| 4067 | SELECT: 'Select', |
| 4068 | OPTION: 'Option' |
| 4069 | }; |
| 4070 | return elementTypeLabels[currentInlineEditingElement.tagName]; |
| 4071 | } |
| 4072 | fieldName = typeof inlineFields[0] === 'object' ? inlineFields[0].fieldName : inlineFields[0]; |
| 4073 | } |
| 4074 | return getFieldLabel(fieldName); |
| 4075 | }, [currentInlineEditingElement, currentContentEditableElement, blockFieldInfo]); |
| 4076 | return /*#__PURE__*/React.createElement(React.Fragment, null, selectedFieldKey && selectedFieldButtonRef && usePopover && currentInlineEditingElementUid && /*#__PURE__*/React.createElement(_popover_wrapper__WEBPACK_IMPORTED_MODULE_2__.PopoverWrapper, { |
| 4077 | focusOnMount: false, |
| 4078 | className: "acf-inline-fields-popover", |
| 4079 | anchor: selectedFieldButtonRef, |
| 4080 | onClose: event => { |
| 4081 | if (event.key === 'Escape') { |
| 4082 | setSelectedFieldKey(null); |
| 4083 | return true; |
| 4084 | } |
| 4085 | // Don't close if clicking inside the popover or anchor |
| 4086 | if (event?.target && fieldPopoverContainerRef?.current && fieldPopoverContainerRef?.current.contains(event.target) || selectedFieldButtonRef?.current && selectedFieldButtonRef?.current.contains(event?.target)) { |
| 4087 | return false; |
| 4088 | } |
| 4089 | return undefined; |
| 4090 | }, |
| 4091 | variant: usePopover ? 'toolbar' : 'unstyled', |
| 4092 | gutenbergIframeOrDocument: gutenbergIframeOrDocument, |
| 4093 | hidePrimaryBlockToolbar: true, |
| 4094 | animate: true |
| 4095 | }, /*#__PURE__*/React.createElement("div", { |
| 4096 | ref: fieldPopoverContainerRef, |
| 4097 | onClick: () => { |
| 4098 | setInlineEditingToolbarHasFocus(true); |
| 4099 | } |
| 4100 | }, /*#__PURE__*/React.createElement("div", { |
| 4101 | className: "acf-inline-fields-popover-inner", |
| 4102 | style: { |
| 4103 | minWidth: selectedFieldConfig?.popoverMinWidth ? selectedFieldConfig?.popoverMinWidth : '300px' |
| 4104 | }, |
| 4105 | ref: setCurrentBlockFormContainer |
| 4106 | }))), selectedFieldKey && selectedFieldButtonRef && !usePopover && currentInlineEditingElementUid && /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Modal, { |
| 4107 | className: "acf-block-form-modal", |
| 4108 | isFullScreen: true, |
| 4109 | title: blockFieldInfo && selectedFieldKey ? blockFieldInfo.find(f => f.name === selectedFieldKey)?.label : '', |
| 4110 | onRequestClose: () => { |
| 4111 | setSelectedFieldKey(null); |
| 4112 | } |
| 4113 | }, /*#__PURE__*/React.createElement("div", { |
| 4114 | ref: fieldPopoverContainerRef, |
| 4115 | onClick: () => { |
| 4116 | setInlineEditingToolbarHasFocus(true); |
| 4117 | } |
| 4118 | }, /*#__PURE__*/React.createElement("div", { |
| 4119 | className: "acf-inline-fields-popover-inner", |
| 4120 | style: { |
| 4121 | minWidth: selectedFieldConfig?.popoverMinWidth ? selectedFieldConfig?.popoverMinWidth : '300px' |
| 4122 | }, |
| 4123 | ref: setCurrentBlockFormContainer |
| 4124 | }))), /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Toolbar, { |
| 4125 | orientation: "horizontal", |
| 4126 | className: "components-accessible-toolbar block-editor-block-contextual-toolbar", |
| 4127 | style: { |
| 4128 | width: 'max-content' |
| 4129 | } |
| 4130 | }, /*#__PURE__*/React.createElement("div", { |
| 4131 | className: "block-editor-block-toolbar" |
| 4132 | }, /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.ToolbarGroup, { |
| 4133 | style: { |
| 4134 | alignItems: 'center' |
| 4135 | } |
| 4136 | }, /*#__PURE__*/React.createElement("div", { |
| 4137 | className: "acf-blocks-toolbar-icon components-toolbar-group block-editor-block-toolbar__block-controls", |
| 4138 | label: toolbarTitle |
| 4139 | }, toolbarIcon, /*#__PURE__*/React.createElement("span", null, toolbarTitle))), /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.ToolbarGroup, null, (() => { |
| 4140 | if (!inlineFields || inlineFields.length === 0) { |
| 4141 | return null; |
| 4142 | } |
| 4143 | const buttons = inlineFields.map((field, index) => { |
| 4144 | let fieldName = ''; |
| 4145 | let fieldIconSvg = null; |
| 4146 | let fieldLabel = null; |
| 4147 | if (typeof field === 'object') { |
| 4148 | fieldName = field.fieldName ? field.fieldName : index; |
| 4149 | fieldIconSvg = field.fieldIcon ? window.atob(field.fieldIcon) : null; |
| 4150 | fieldLabel = field.fieldLabel ? field.fieldLabel : fieldName; |
| 4151 | } else { |
| 4152 | fieldName = field; |
| 4153 | } |
| 4154 | |
| 4155 | // Use 'edit' icon if field has useExpandedEditor flag |
| 4156 | if (!fieldIconSvg && field?.useExpandedEditor) { |
| 4157 | fieldIconSvg = 'edit'; |
| 4158 | } |
| 4159 | return /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.ToolbarButton, { |
| 4160 | key: fieldName, |
| 4161 | disabled: contentEditableChangeInProgress, |
| 4162 | className: "acf-toolbar-button", |
| 4163 | icon: fieldIconSvg ? typeof fieldIconSvg === 'string' && fieldIconSvg === 'edit' ? 'edit' : /*#__PURE__*/React.createElement("i", { |
| 4164 | dangerouslySetInnerHTML: { |
| 4165 | __html: fieldIconSvg |
| 4166 | } |
| 4167 | }) : /*#__PURE__*/React.createElement("i", { |
| 4168 | className: `field-type-icon field-type-icon-${getFieldTypeClassName(fieldName)}` |
| 4169 | }), |
| 4170 | label: fieldLabel || getFieldLabel(fieldName), |
| 4171 | isPressed: fieldName === selectedFieldKey, |
| 4172 | ref: fieldName === selectedFieldKey ? setSelectedFieldButtonRef : null, |
| 4173 | onClick: () => { |
| 4174 | setInlineEditingToolbarHasFocus(true); |
| 4175 | if (selectedFieldKey === fieldName) { |
| 4176 | setSelectedFieldKey(null); |
| 4177 | } else { |
| 4178 | // Determine if we should use modal or popover |
| 4179 | setUsePopover(!field?.useExpandedEditor); |
| 4180 | setSelectedFieldKey(fieldName); |
| 4181 | setSelectedFieldConfig(field); |
| 4182 | } |
| 4183 | } |
| 4184 | }); |
| 4185 | }); |
| 4186 | return buttons; |
| 4187 | })()))), (() => { |
| 4188 | const styleContent = `[data-name="${selectedFieldKey}"]{ display: block!important; }`; |
| 4189 | return /*#__PURE__*/React.createElement("style", null, styleContent); |
| 4190 | })()); |
| 4191 | }; |
| 4192 | |
| 4193 | /***/ }), |
| 4194 | |
| 4195 | /***/ "./assets/src/js/pro/blocks-v3/components/jsx-parser.js": |
| 4196 | /*!**************************************************************!*\ |
| 4197 | !*** ./assets/src/js/pro/blocks-v3/components/jsx-parser.js ***! |
| 4198 | \**************************************************************/ |
| 4199 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 4200 | |
| 4201 | "use strict"; |
| 4202 | __webpack_require__.r(__webpack_exports__); |
| 4203 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 4204 | /* harmony export */ parseJSX: () => (/* binding */ parseJSX) |
| 4205 | /* harmony export */ }); |
| 4206 | /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! jquery */ "jquery"); |
| 4207 | /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__); |
| 4208 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); |
| 4209 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_1__); |
| 4210 | /** |
| 4211 | * JSX Parser for ACF Blocks - Based on 6.7.0.2 |
| 4212 | * Converts HTML strings to React/JSX elements for rendering in the block editor |
| 4213 | */ |
| 4214 | |
| 4215 | /* global acf, React, Text */ |
| 4216 | |
| 4217 | // eslint-disable-next-line import/no-unresolved -- WordPress provides jquery as an external script dependency. |
| 4218 | |
| 4219 | |
| 4220 | const useInnerBlocksProps = wp.blockEditor.__experimentalUseInnerBlocksProps || wp.blockEditor.useInnerBlocksProps; |
| 4221 | |
| 4222 | /** |
| 4223 | * Gets the JSX-compatible name for an HTML attribute |
| 4224 | * |
| 4225 | * @param {string} attrName Attribute name. |
| 4226 | * @return {string} JSX-compatible attribute name. |
| 4227 | */ |
| 4228 | function getJSXNameReplacement(attrName) { |
| 4229 | return acf.isget(acf, 'jsxNameReplacements', attrName) || attrName; |
| 4230 | } |
| 4231 | |
| 4232 | /** |
| 4233 | * ACF InnerBlocks wrapper component |
| 4234 | * |
| 4235 | * @param {Object} props Component props. |
| 4236 | * @return {JSX.Element} InnerBlocks wrapper element. |
| 4237 | */ |
| 4238 | function ACFInnerBlocksComponent(props) { |
| 4239 | const { |
| 4240 | className = 'acf-innerblocks-container' |
| 4241 | } = props; |
| 4242 | const innerBlocksProps = useInnerBlocksProps({ |
| 4243 | className |
| 4244 | }, props); |
| 4245 | return (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.createElement)('div', { |
| 4246 | ...innerBlocksProps, |
| 4247 | children: innerBlocksProps.children |
| 4248 | }); |
| 4249 | } |
| 4250 | |
| 4251 | /** |
| 4252 | * Script component for handling <script> tags |
| 4253 | */ |
| 4254 | class ScriptComponent extends React.Component { |
| 4255 | render() { |
| 4256 | return (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.createElement)('div', { |
| 4257 | ref: element => this.el = element |
| 4258 | }); |
| 4259 | } |
| 4260 | setHTML(scriptContent) { |
| 4261 | jquery__WEBPACK_IMPORTED_MODULE_0___default()(this.el).html(`<script>${scriptContent}</script>`); |
| 4262 | } |
| 4263 | componentDidUpdate() { |
| 4264 | this.setHTML(this.props.children); |
| 4265 | } |
| 4266 | componentDidMount() { |
| 4267 | this.setHTML(this.props.children); |
| 4268 | } |
| 4269 | } |
| 4270 | |
| 4271 | /** |
| 4272 | * Helper function to parse style attribute string into object |
| 4273 | * |
| 4274 | * @param {string} styleString Style attribute value. |
| 4275 | * @return {Object} Parsed style object. |
| 4276 | */ |
| 4277 | function parseStyleAttribute(styleString) { |
| 4278 | const styleObj = {}; |
| 4279 | if (!styleString) { |
| 4280 | return styleObj; |
| 4281 | } |
| 4282 | styleString.split(';').forEach(rule => { |
| 4283 | const colonIndex = rule.indexOf(':'); |
| 4284 | if (colonIndex > 0) { |
| 4285 | let property = rule.substr(0, colonIndex).trim(); |
| 4286 | const value = rule.substr(colonIndex + 1).trim(); |
| 4287 | |
| 4288 | // Convert to camelCase |
| 4289 | if (property.charAt(0) !== '-') { |
| 4290 | property = acf.strCamelCase(property); |
| 4291 | } |
| 4292 | styleObj[property] = value; |
| 4293 | } |
| 4294 | }); |
| 4295 | return styleObj; |
| 4296 | } |
| 4297 | |
| 4298 | /** |
| 4299 | * Parses and transforms a DOM attribute to React props format |
| 4300 | * Based on 6.7.0.2's implementation |
| 4301 | * |
| 4302 | * @param {Attr} attribute DOM attribute. |
| 4303 | * @return {Object} React prop name and value. |
| 4304 | */ |
| 4305 | function parseAttribute(attribute) { |
| 4306 | let attrName = attribute.name; |
| 4307 | let attrValue = attribute.value; |
| 4308 | |
| 4309 | // Allow custom filtering |
| 4310 | const customParsed = acf.applyFilters('acf_blocks_parse_node_attr', false, attribute); |
| 4311 | if (customParsed) { |
| 4312 | return customParsed; |
| 4313 | } |
| 4314 | switch (attrName) { |
| 4315 | case 'class': |
| 4316 | attrName = 'className'; |
| 4317 | break; |
| 4318 | case 'style': |
| 4319 | const styleObj = {}; |
| 4320 | attrValue.split(';').forEach(rule => { |
| 4321 | const colonIndex = rule.indexOf(':'); |
| 4322 | if (colonIndex > 0) { |
| 4323 | let property = rule.substr(0, colonIndex).trim(); |
| 4324 | const value = rule.substr(colonIndex + 1).trim(); |
| 4325 | if (property.charAt(0) !== '-') { |
| 4326 | property = acf.strCamelCase(property); |
| 4327 | } |
| 4328 | styleObj[property] = value; |
| 4329 | } |
| 4330 | }); |
| 4331 | attrValue = styleObj; |
| 4332 | break; |
| 4333 | default: |
| 4334 | // Skip data- attributes processing, keep them as-is |
| 4335 | if (attrName.indexOf('data-') === 0) { |
| 4336 | break; |
| 4337 | } |
| 4338 | attrName = getJSXNameReplacement(attrName); |
| 4339 | // Ignore values that merely start with a JSON-like character but |
| 4340 | // aren't valid JSON (e.g. an oEmbed title beginning with "[" or "{"). |
| 4341 | const firstChar = attrValue.charAt(0); |
| 4342 | if (firstChar === '[' || firstChar === '{') { |
| 4343 | try { |
| 4344 | attrValue = JSON.parse(attrValue); |
| 4345 | } catch (err) {} |
| 4346 | } |
| 4347 | if (attrValue === 'true' || attrValue === 'false') { |
| 4348 | attrValue = attrValue === 'true'; |
| 4349 | } |
| 4350 | } |
| 4351 | return { |
| 4352 | name: attrName, |
| 4353 | value: attrValue |
| 4354 | }; |
| 4355 | } |
| 4356 | |
| 4357 | /** |
| 4358 | * Main parseNodeToJSX function - Based on 6.7.0.2's function `O` |
| 4359 | * Recursively converts DOM nodes to React/JSX elements |
| 4360 | * |
| 4361 | * @param {Node} node DOM node. |
| 4362 | * @param {number} depth Recursion depth. |
| 4363 | * @return {JSX.Element|null} Parsed JSX element. |
| 4364 | */ |
| 4365 | function parseNodeToJSX(node, depth = 0, callbacks = {}) { |
| 4366 | const { |
| 4367 | onNewInlineEditingElementSelected, |
| 4368 | onNewContentEditableElementSelected, |
| 4369 | blockFieldInfo |
| 4370 | } = callbacks; |
| 4371 | const selectInlineEditingElement = (uid, element = null) => { |
| 4372 | if (onNewInlineEditingElementSelected) { |
| 4373 | onNewInlineEditingElementSelected(uid); |
| 4374 | return; |
| 4375 | } |
| 4376 | if (acf.blockEdit?.setCurrentInlineEditingElementUid) { |
| 4377 | acf.blockEdit.setCurrentInlineEditingElementUid(uid); |
| 4378 | } |
| 4379 | if (acf.blockEdit?.setCurrentInlineEditingElement) { |
| 4380 | acf.blockEdit.setCurrentInlineEditingElement(element); |
| 4381 | } |
| 4382 | }; |
| 4383 | const selectContentEditableElement = (fieldSlug, element = null) => { |
| 4384 | if (onNewContentEditableElementSelected) { |
| 4385 | onNewContentEditableElementSelected(fieldSlug); |
| 4386 | return; |
| 4387 | } |
| 4388 | if (acf.blockEdit?.setCurrentContentEditableElement) { |
| 4389 | acf.blockEdit.setCurrentContentEditableElement(element); |
| 4390 | } |
| 4391 | }; |
| 4392 | |
| 4393 | // Determine component type |
| 4394 | const nodeName = node.nodeName.toLowerCase(); |
| 4395 | let componentType; |
| 4396 | switch (nodeName) { |
| 4397 | case 'innerblocks': |
| 4398 | componentType = 'ACFInnerBlocks'; |
| 4399 | break; |
| 4400 | case 'script': |
| 4401 | componentType = ScriptComponent; |
| 4402 | break; |
| 4403 | case '#comment': |
| 4404 | return null; |
| 4405 | default: |
| 4406 | componentType = getJSXNameReplacement(nodeName); |
| 4407 | } |
| 4408 | if (!componentType) { |
| 4409 | return null; |
| 4410 | } |
| 4411 | const props = {}; |
| 4412 | |
| 4413 | // Add ref to first-level elements (except ACFInnerBlocks) |
| 4414 | if (depth === 1 && componentType !== 'ACFInnerBlocks') { |
| 4415 | props.ref = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.createRef)(); |
| 4416 | } |
| 4417 | |
| 4418 | // Parse attributes |
| 4419 | acf.arrayArgs(node.attributes).map(parseAttribute).forEach(({ |
| 4420 | name, |
| 4421 | value |
| 4422 | }) => { |
| 4423 | props[name] = value; |
| 4424 | }); |
| 4425 | |
| 4426 | // Handle data-acf-inline-fields attributes |
| 4427 | if (node.hasAttribute('data-acf-inline-fields')) { |
| 4428 | props.style = { |
| 4429 | ...parseStyleAttribute(node.getAttribute('style') || ''), |
| 4430 | pointerEvents: 'all' |
| 4431 | }; |
| 4432 | props.role = 'button'; |
| 4433 | props.tabIndex = 0; |
| 4434 | props.onFocus = event => { |
| 4435 | event.stopPropagation(); |
| 4436 | const uid = node.attributes.getNamedItem('data-acf-inline-fields-uid').value; |
| 4437 | selectInlineEditingElement(uid, event.currentTarget); |
| 4438 | }; |
| 4439 | props.onMouseDown = event => event.stopPropagation(); |
| 4440 | props.onClick = event => { |
| 4441 | event.stopPropagation(); |
| 4442 | const link = event.target.closest('a'); |
| 4443 | if (link && link.tagName === 'A') { |
| 4444 | event.preventDefault(); |
| 4445 | acf.debug(`Navigation prevented for ${link.href}`); |
| 4446 | } |
| 4447 | if (!event.target.hasAttribute('data-acf-inline-contenteditable')) { |
| 4448 | const uid = node.attributes.getNamedItem('data-acf-inline-fields-uid').value; |
| 4449 | selectInlineEditingElement(uid, event.currentTarget); |
| 4450 | } |
| 4451 | }; |
| 4452 | props.onKeyDown = event => { |
| 4453 | if (event.key === 'Tab' && event.shiftKey) { |
| 4454 | event.preventDefault(); |
| 4455 | const toolbar = document.querySelector('.acf-inline-editing-toolbar'); |
| 4456 | const button = toolbar?.querySelector('button'); |
| 4457 | if (button) { |
| 4458 | button.focus(); |
| 4459 | const uid = node.attributes.getNamedItem('data-acf-inline-fields-uid').value; |
| 4460 | selectInlineEditingElement(uid, event.currentTarget); |
| 4461 | } |
| 4462 | } |
| 4463 | if (event.key === 'Enter') { |
| 4464 | event.stopPropagation(); |
| 4465 | const link = event.target.closest('a'); |
| 4466 | if (link && link.tagName === 'A') { |
| 4467 | event.preventDefault(); |
| 4468 | acf.debug(`Navigation prevented for ${link.href}`); |
| 4469 | } |
| 4470 | const uid = node.attributes.getNamedItem('data-acf-inline-fields-uid').value; |
| 4471 | selectInlineEditingElement(uid, event.currentTarget); |
| 4472 | } |
| 4473 | }; |
| 4474 | } |
| 4475 | |
| 4476 | // Handle data-acf-inline-contenteditable attributes |
| 4477 | if (node.hasAttribute('data-acf-inline-contenteditable')) { |
| 4478 | const fieldSlug = node.attributes.getNamedItem('data-acf-inline-contenteditable-field-slug').value; |
| 4479 | const fieldInfo = blockFieldInfo || acf.blockEdit?.getBlockFieldInfo?.(); |
| 4480 | const editableFields = fieldInfo ? fieldInfo.filter(field => field.name === fieldSlug && (field.type === 'text' || field.type === 'textarea')) : []; |
| 4481 | if (editableFields.length > 0) { |
| 4482 | props.contentEditable = true; |
| 4483 | props.suppressContentEditableWarning = true; |
| 4484 | props.role = 'input'; |
| 4485 | props.tabIndex = 0; |
| 4486 | props.onFocus = event => { |
| 4487 | const link = event.target.closest('a'); |
| 4488 | if (link && link.tagName === 'A') { |
| 4489 | event.preventDefault(); |
| 4490 | acf.debug(`Navigation prevented for ${link.href}`); |
| 4491 | } |
| 4492 | event.stopPropagation(); |
| 4493 | selectContentEditableElement(fieldSlug, event.currentTarget); |
| 4494 | if (node.hasAttribute('data-acf-inline-fields')) { |
| 4495 | const uid = node.attributes.getNamedItem('data-acf-inline-fields-uid').value; |
| 4496 | selectInlineEditingElement(uid, event.currentTarget); |
| 4497 | } else { |
| 4498 | selectInlineEditingElement(null); |
| 4499 | } |
| 4500 | }; |
| 4501 | props.onPaste = event => { |
| 4502 | event.preventDefault(); |
| 4503 | const text = event.clipboardData.getData('text/plain'); |
| 4504 | event.currentTarget.textContent = event.currentTarget.textContent + text; |
| 4505 | }; |
| 4506 | } else { |
| 4507 | // Remove invalid contentEditable attributes |
| 4508 | delete props['data-acf-inline-contenteditable-field-slug']; |
| 4509 | delete props['data-acf-inline-contenteditable']; |
| 4510 | } |
| 4511 | } |
| 4512 | |
| 4513 | // Add click handler to clear selection if clicking outside inline fields |
| 4514 | if (!node.hasAttribute('data-acf-inline-fields') && !node.hasAttribute('data-acf-inline-contenteditable')) { |
| 4515 | props.onClick = event => { |
| 4516 | if (event.target === event.currentTarget) { |
| 4517 | selectInlineEditingElement(null); |
| 4518 | selectContentEditableElement(null); |
| 4519 | } |
| 4520 | }; |
| 4521 | } |
| 4522 | |
| 4523 | // Handle ACFInnerBlocks component |
| 4524 | if (componentType === 'ACFInnerBlocks') { |
| 4525 | return (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_1__.createElement)(ACFInnerBlocksComponent, { |
| 4526 | ...props |
| 4527 | }); |
| 4528 | } |
| 4529 | |
| 4530 | // Build element with children |
| 4531 | const elementArgs = [componentType, props]; |
| 4532 | acf.arrayArgs(node.childNodes).forEach(childNode => { |
| 4533 | if (childNode instanceof Text) { |
| 4534 | const textContent = childNode.textContent; |
| 4535 | if (textContent) { |
| 4536 | elementArgs.push(textContent); |
| 4537 | } |
| 4538 | } else { |
| 4539 | elementArgs.push(parseNodeToJSX(childNode, depth + 1, callbacks)); |
| 4540 | } |
| 4541 | }); |
| 4542 | const element = _wordpress_element__WEBPACK_IMPORTED_MODULE_1__.createElement.apply(this, elementArgs); |
| 4543 | return element; |
| 4544 | } |
| 4545 | |
| 4546 | // Preserve the legacy parser for v1/v2 blocks, which pass the block version |
| 4547 | // as the second argument. |
| 4548 | const legacyParseJSX = acf.parseJSX; |
| 4549 | |
| 4550 | /** |
| 4551 | * Main parseJSX function exposed on the acf global object |
| 4552 | * Matches 6.7.0.2's implementation exactly |
| 4553 | * |
| 4554 | * @param {string} htmlString HTML string. |
| 4555 | * @param {Function} onNewInlineEditingElementSelected Inline element selection callback or jQuery parser. |
| 4556 | * @param {Function} onContentEditableChange ContentEditable change callback. |
| 4557 | * @param {Function} onNewContentEditableElementSelected ContentEditable selection callback. |
| 4558 | * @param {Array} blockFieldInfo Field metadata. |
| 4559 | * @param {Function} $ jQuery-compatible parser. |
| 4560 | * @return {JSX.Element|Array} Parsed JSX children. |
| 4561 | */ |
| 4562 | function parseJSX(htmlString, onNewInlineEditingElementSelected = (jquery__WEBPACK_IMPORTED_MODULE_0___default()), onContentEditableChange = null, onNewContentEditableElementSelected = null, blockFieldInfo = null, $ = null) { |
| 4563 | if (typeof onNewInlineEditingElementSelected === 'number' && typeof legacyParseJSX === 'function') { |
| 4564 | return legacyParseJSX(htmlString, onNewInlineEditingElementSelected); |
| 4565 | } |
| 4566 | const isJQueryParser = typeof onNewInlineEditingElementSelected === 'function' && (arguments.length === 2 || onNewInlineEditingElementSelected.fn && onNewInlineEditingElementSelected.fn.jquery); |
| 4567 | const parser = isJQueryParser ? onNewInlineEditingElementSelected : $ || (jquery__WEBPACK_IMPORTED_MODULE_0___default()); |
| 4568 | const callbacks = isJQueryParser ? {} : { |
| 4569 | onNewInlineEditingElementSelected, |
| 4570 | onContentEditableChange, |
| 4571 | onNewContentEditableElementSelected, |
| 4572 | blockFieldInfo |
| 4573 | }; |
| 4574 | |
| 4575 | // Wrap in div to ensure valid HTML structure |
| 4576 | htmlString = '<div>' + htmlString + '</div>'; |
| 4577 | |
| 4578 | // Handle self-closing InnerBlocks tags |
| 4579 | htmlString = htmlString.replace(/<InnerBlocks([^>]+)?\/>/, '<InnerBlocks$1></InnerBlocks>'); |
| 4580 | |
| 4581 | // Parse with jQuery, convert to React, and extract children from wrapper div |
| 4582 | const parsedElement = parseNodeToJSX(parser(htmlString)[0], 0, callbacks); |
| 4583 | return parsedElement.props.children; |
| 4584 | } |
| 4585 | acf.parseJSXV3 = parseJSX; |
| 4586 | acf.parseJSX = parseJSX; |
| 4587 | |
| 4588 | /***/ }), |
| 4589 | |
| 4590 | /***/ "./assets/src/js/pro/blocks-v3/components/popover-wrapper.js": |
| 4591 | /*!*******************************************************************!*\ |
| 4592 | !*** ./assets/src/js/pro/blocks-v3/components/popover-wrapper.js ***! |
| 4593 | \*******************************************************************/ |
| 4594 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 4595 | |
| 4596 | "use strict"; |
| 4597 | __webpack_require__.r(__webpack_exports__); |
| 4598 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 4599 | /* harmony export */ PopoverWrapper: () => (/* binding */ PopoverWrapper) |
| 4600 | /* harmony export */ }); |
| 4601 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element"); |
| 4602 | /* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__); |
| 4603 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @wordpress/components */ "@wordpress/components"); |
| 4604 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__); |
| 4605 | /** |
| 4606 | * PopoverWrapper Component |
| 4607 | * Custom Popover wrapper that handles inline editing toolbar behavior |
| 4608 | * - Escape key to close |
| 4609 | * - Click outside to close |
| 4610 | * - Focus management |
| 4611 | * - Hiding primary block toolbar when active |
| 4612 | */ |
| 4613 | |
| 4614 | |
| 4615 | |
| 4616 | |
| 4617 | /** |
| 4618 | * PopoverWrapper component |
| 4619 | * Wraps the WordPress Popover component with custom event handlers |
| 4620 | * |
| 4621 | * @param {Object} props - Component props |
| 4622 | * @param {React.ReactNode} props.children - Child elements to render inside popover |
| 4623 | * @param {string} props.className - CSS class for the popover |
| 4624 | * @param {Element|null} props.anchor - Anchor element for positioning |
| 4625 | * @param {string} props.placement - Placement relative to anchor (e.g., 'top-start') |
| 4626 | * @param {Function} props.onClose - Callback when popover should close |
| 4627 | * @param {boolean|string} props.focusOnMount - Whether to focus on mount |
| 4628 | * @param {string} props.variant - Popover variant (e.g., 'unstyled') |
| 4629 | * @param {boolean} props.animate - Whether to animate popover |
| 4630 | * @param {Document|HTMLIFrameElement} props.gutenbergIframeOrDocument - Document or iframe reference |
| 4631 | * @param {boolean} props.hidePrimaryBlockToolbar - Whether to hide the primary block toolbar |
| 4632 | * @returns {JSX.Element} - Wrapped Popover component |
| 4633 | */ |
| 4634 | const PopoverWrapper = ({ |
| 4635 | children, |
| 4636 | className, |
| 4637 | anchor, |
| 4638 | placement, |
| 4639 | onClose, |
| 4640 | focusOnMount, |
| 4641 | variant, |
| 4642 | animate = false, |
| 4643 | gutenbergIframeOrDocument, |
| 4644 | hidePrimaryBlockToolbar = false |
| 4645 | }) => { |
| 4646 | (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { |
| 4647 | const doc = gutenbergIframeOrDocument?.contentDocument ? gutenbergIframeOrDocument.contentDocument : gutenbergIframeOrDocument || document; |
| 4648 | const handleEscapeKey = event => { |
| 4649 | if (event.key === 'Escape') { |
| 4650 | onClose?.(event); |
| 4651 | } |
| 4652 | }; |
| 4653 | const handleClickOutside = event => { |
| 4654 | if (event?.key) { |
| 4655 | return; |
| 4656 | } |
| 4657 | const popoverSelector = className ? `.${className.split(' ').filter(Boolean).join('.')}` : null; |
| 4658 | const popoverElement = popoverSelector ? event.target.closest(popoverSelector) : null; |
| 4659 | if (!popoverElement) { |
| 4660 | onClose?.(event); |
| 4661 | } |
| 4662 | }; |
| 4663 | doc.addEventListener('keydown', handleEscapeKey, true); |
| 4664 | doc.addEventListener('mousedown', handleClickOutside, true); |
| 4665 | if (hidePrimaryBlockToolbar) { |
| 4666 | const toolbar = doc.querySelector('.block-editor-block-list__block.is-selected > .block-editor-block-contextual-toolbar'); |
| 4667 | if (toolbar) { |
| 4668 | toolbar.style.display = 'none'; |
| 4669 | } |
| 4670 | } |
| 4671 | return () => { |
| 4672 | doc.removeEventListener('keydown', handleEscapeKey, true); |
| 4673 | doc.removeEventListener('mousedown', handleClickOutside, true); |
| 4674 | if (hidePrimaryBlockToolbar) { |
| 4675 | const toolbar = doc.querySelector('.block-editor-block-list__block.is-selected > .block-editor-block-contextual-toolbar'); |
| 4676 | if (toolbar) { |
| 4677 | toolbar.style.display = ''; |
| 4678 | } |
| 4679 | } |
| 4680 | }; |
| 4681 | }, [gutenbergIframeOrDocument, onClose, className, hidePrimaryBlockToolbar]); |
| 4682 | return /*#__PURE__*/React.createElement(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__.Popover, { |
| 4683 | focusOnMount: focusOnMount, |
| 4684 | variant: variant, |
| 4685 | anchor: anchor, |
| 4686 | className: className, |
| 4687 | placement: placement, |
| 4688 | animate: animate |
| 4689 | }, hidePrimaryBlockToolbar && /*#__PURE__*/React.createElement("style", null, ` |
| 4690 | .components-popover.block-editor-block-popover.block-editor-block-list__block-popover{ |
| 4691 | display: none!important; |
| 4692 | } |
| 4693 | `), children); |
| 4694 | }; |
| 4695 | |
| 4696 | /***/ }), |
| 4697 | |
| 4698 | /***/ "./assets/src/js/pro/blocks-v3/high-order-components/with-align-content.js": |
| 4699 | /*!*********************************************************************************!*\ |
| 4700 | !*** ./assets/src/js/pro/blocks-v3/high-order-components/with-align-content.js ***! |
| 4701 | \*********************************************************************************/ |
| 4702 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 4703 | |
| 4704 | "use strict"; |
| 4705 | __webpack_require__.r(__webpack_exports__); |
| 4706 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 4707 | /* harmony export */ withAlignContent: () => (/* binding */ withAlignContent) |
| 4708 | /* harmony export */ }); |
| 4709 | /** |
| 4710 | * withAlignContent Higher-Order Component |
| 4711 | * Adds content alignment toolbar controls to ACF blocks |
| 4712 | * Supports both vertical alignment and matrix alignment (horizontal + vertical) |
| 4713 | */ |
| 4714 | |
| 4715 | const { |
| 4716 | Fragment, |
| 4717 | Component |
| 4718 | } = wp.element; |
| 4719 | const { |
| 4720 | BlockControls, |
| 4721 | BlockVerticalAlignmentToolbar |
| 4722 | } = wp.blockEditor; |
| 4723 | |
| 4724 | // Matrix alignment control (experimental) |
| 4725 | const BlockAlignmentMatrixControl = wp.blockEditor.__experimentalBlockAlignmentMatrixControl || wp.blockEditor.BlockAlignmentMatrixControl; |
| 4726 | const BlockAlignmentMatrixToolbar = wp.blockEditor.__experimentalBlockAlignmentMatrixToolbar || wp.blockEditor.BlockAlignmentMatrixToolbar; |
| 4727 | |
| 4728 | /** |
| 4729 | * Normalizes vertical alignment value |
| 4730 | * |
| 4731 | * @param {string} alignment - Alignment value |
| 4732 | * @returns {string} - Normalized alignment (top, center, or bottom) |
| 4733 | */ |
| 4734 | const normalizeVerticalAlignment = alignment => { |
| 4735 | return ['top', 'center', 'bottom'].includes(alignment) ? alignment : 'top'; |
| 4736 | }; |
| 4737 | |
| 4738 | /** |
| 4739 | * Gets the default horizontal alignment based on RTL setting |
| 4740 | * |
| 4741 | * @param {string} alignment - Current alignment value |
| 4742 | * @returns {string} - Normalized alignment value (left, center, or right) |
| 4743 | */ |
| 4744 | const getDefaultHorizontalAlignment = alignment => { |
| 4745 | const defaultAlign = acf.get('rtl') ? 'right' : 'left'; |
| 4746 | return ['left', 'center', 'right'].includes(alignment) ? alignment : defaultAlign; |
| 4747 | }; |
| 4748 | |
| 4749 | /** |
| 4750 | * Normalizes matrix alignment value (vertical + horizontal) |
| 4751 | * Format: "top left", "center center", etc. |
| 4752 | * |
| 4753 | * @param {string} alignment - Alignment value |
| 4754 | * @returns {string} - Normalized matrix alignment |
| 4755 | */ |
| 4756 | const normalizeMatrixAlignment = alignment => { |
| 4757 | if (alignment) { |
| 4758 | const [vertical, horizontal] = alignment.split(' '); |
| 4759 | return `${normalizeVerticalAlignment(vertical)} ${getDefaultHorizontalAlignment(horizontal)}`; |
| 4760 | } |
| 4761 | return 'center center'; |
| 4762 | }; |
| 4763 | |
| 4764 | /** |
| 4765 | * Higher-order component that adds content alignment controls |
| 4766 | * Supports either vertical-only or matrix (2D) alignment based on block config |
| 4767 | * |
| 4768 | * @param {React.Component} BlockComponent - The component to wrap |
| 4769 | * @param {Object} blockConfig - ACF block configuration |
| 4770 | * @returns {React.Component} - Enhanced component with content alignment controls |
| 4771 | */ |
| 4772 | const withAlignContent = (BlockComponent, blockConfig) => { |
| 4773 | let AlignmentControl; |
| 4774 | let normalizeAlignment; |
| 4775 | |
| 4776 | // Determine which alignment control to use based on block supports |
| 4777 | if (blockConfig.supports.align_content === 'matrix' || blockConfig.supports.alignContent === 'matrix') { |
| 4778 | // Use matrix control (horizontal + vertical) |
| 4779 | AlignmentControl = BlockAlignmentMatrixControl || BlockAlignmentMatrixToolbar; |
| 4780 | normalizeAlignment = normalizeMatrixAlignment; |
| 4781 | } else { |
| 4782 | // Use vertical-only control |
| 4783 | AlignmentControl = BlockVerticalAlignmentToolbar; |
| 4784 | normalizeAlignment = normalizeVerticalAlignment; |
| 4785 | } |
| 4786 | |
| 4787 | // If alignment control is not available, return original component |
| 4788 | if (AlignmentControl === undefined) { |
| 4789 | return BlockComponent; |
| 4790 | } |
| 4791 | |
| 4792 | // Set default alignment on block config |
| 4793 | blockConfig.alignContent = normalizeAlignment(blockConfig.alignContent); |
| 4794 | return class extends Component { |
| 4795 | render() { |
| 4796 | const { |
| 4797 | attributes, |
| 4798 | setAttributes |
| 4799 | } = this.props; |
| 4800 | const { |
| 4801 | alignContent |
| 4802 | } = attributes; |
| 4803 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockControls, { |
| 4804 | group: "block" |
| 4805 | }, /*#__PURE__*/React.createElement(AlignmentControl, { |
| 4806 | label: acf.__('Change content alignment'), |
| 4807 | value: normalizeAlignment(alignContent), |
| 4808 | onChange: function (newAlignment) { |
| 4809 | setAttributes({ |
| 4810 | alignContent: normalizeAlignment(newAlignment) |
| 4811 | }); |
| 4812 | } |
| 4813 | })), /*#__PURE__*/React.createElement(BlockComponent, this.props)); |
| 4814 | } |
| 4815 | }; |
| 4816 | }; |
| 4817 | |
| 4818 | /***/ }), |
| 4819 | |
| 4820 | /***/ "./assets/src/js/pro/blocks-v3/high-order-components/with-align-text.js": |
| 4821 | /*!******************************************************************************!*\ |
| 4822 | !*** ./assets/src/js/pro/blocks-v3/high-order-components/with-align-text.js ***! |
| 4823 | \******************************************************************************/ |
| 4824 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 4825 | |
| 4826 | "use strict"; |
| 4827 | __webpack_require__.r(__webpack_exports__); |
| 4828 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 4829 | /* harmony export */ withAlignText: () => (/* binding */ withAlignText) |
| 4830 | /* harmony export */ }); |
| 4831 | /** |
| 4832 | * withAlignText Higher-Order Component |
| 4833 | * Adds text alignment toolbar controls to ACF blocks |
| 4834 | */ |
| 4835 | |
| 4836 | const { |
| 4837 | Fragment, |
| 4838 | Component |
| 4839 | } = wp.element; |
| 4840 | const { |
| 4841 | BlockControls, |
| 4842 | AlignmentToolbar |
| 4843 | } = wp.blockEditor; |
| 4844 | |
| 4845 | /** |
| 4846 | * Gets the default text alignment based on RTL setting |
| 4847 | * |
| 4848 | * @param {string} alignment - Current alignment value |
| 4849 | * @returns {string} - Normalized alignment value (left, center, or right) |
| 4850 | */ |
| 4851 | const getDefaultAlignment = alignment => { |
| 4852 | const defaultAlign = acf.get('rtl') ? 'right' : 'left'; |
| 4853 | return ['left', 'center', 'right'].includes(alignment) ? alignment : defaultAlign; |
| 4854 | }; |
| 4855 | |
| 4856 | /** |
| 4857 | * Higher-order component that adds text alignment controls |
| 4858 | * Wraps a block component and adds AlignmentToolbar to BlockControls |
| 4859 | * |
| 4860 | * @param {React.Component} BlockComponent - The component to wrap |
| 4861 | * @param {Object} blockConfig - ACF block configuration |
| 4862 | * @returns {React.Component} - Enhanced component with text alignment controls |
| 4863 | */ |
| 4864 | const withAlignText = (BlockComponent, blockConfig) => { |
| 4865 | const normalizeAlignment = getDefaultAlignment; |
| 4866 | |
| 4867 | // Set default alignment on block config |
| 4868 | blockConfig.alignText = normalizeAlignment(blockConfig.alignText); |
| 4869 | return class extends Component { |
| 4870 | render() { |
| 4871 | const { |
| 4872 | attributes, |
| 4873 | setAttributes |
| 4874 | } = this.props; |
| 4875 | const { |
| 4876 | alignText |
| 4877 | } = attributes; |
| 4878 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockControls, { |
| 4879 | group: "block" |
| 4880 | }, /*#__PURE__*/React.createElement(AlignmentToolbar, { |
| 4881 | value: normalizeAlignment(alignText), |
| 4882 | onChange: function (newAlignment) { |
| 4883 | setAttributes({ |
| 4884 | alignText: normalizeAlignment(newAlignment) |
| 4885 | }); |
| 4886 | } |
| 4887 | })), /*#__PURE__*/React.createElement(BlockComponent, this.props)); |
| 4888 | } |
| 4889 | }; |
| 4890 | }; |
| 4891 | |
| 4892 | /***/ }), |
| 4893 | |
| 4894 | /***/ "./assets/src/js/pro/blocks-v3/high-order-components/with-full-height.js": |
| 4895 | /*!*******************************************************************************!*\ |
| 4896 | !*** ./assets/src/js/pro/blocks-v3/high-order-components/with-full-height.js ***! |
| 4897 | \*******************************************************************************/ |
| 4898 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 4899 | |
| 4900 | "use strict"; |
| 4901 | __webpack_require__.r(__webpack_exports__); |
| 4902 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 4903 | /* harmony export */ withFullHeight: () => (/* binding */ withFullHeight) |
| 4904 | /* harmony export */ }); |
| 4905 | /** |
| 4906 | * withFullHeight Higher-Order Component |
| 4907 | * Adds full height toggle control to ACF blocks |
| 4908 | */ |
| 4909 | |
| 4910 | const { |
| 4911 | Fragment, |
| 4912 | Component |
| 4913 | } = wp.element; |
| 4914 | const { |
| 4915 | BlockControls |
| 4916 | } = wp.blockEditor; |
| 4917 | |
| 4918 | // Full height control (experimental) |
| 4919 | const BlockFullHeightAlignmentControl = wp.blockEditor.__experimentalBlockFullHeightAligmentControl || wp.blockEditor.__experimentalBlockFullHeightAlignmentControl || wp.blockEditor.BlockFullHeightAlignmentControl; |
| 4920 | |
| 4921 | /** |
| 4922 | * Higher-order component that adds full height toggle controls |
| 4923 | * Allows blocks to expand to full available height |
| 4924 | * |
| 4925 | * @param {React.Component} BlockComponent - The component to wrap |
| 4926 | * @returns {React.Component} - Enhanced component with full height controls |
| 4927 | */ |
| 4928 | const withFullHeight = BlockComponent => { |
| 4929 | // If control is not available, return original component |
| 4930 | if (!BlockFullHeightAlignmentControl) { |
| 4931 | return BlockComponent; |
| 4932 | } |
| 4933 | return class extends Component { |
| 4934 | render() { |
| 4935 | const { |
| 4936 | attributes, |
| 4937 | setAttributes |
| 4938 | } = this.props; |
| 4939 | const { |
| 4940 | fullHeight |
| 4941 | } = attributes; |
| 4942 | return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(BlockControls, { |
| 4943 | group: "block" |
| 4944 | }, /*#__PURE__*/React.createElement(BlockFullHeightAlignmentControl, { |
| 4945 | isActive: fullHeight, |
| 4946 | onToggle: function (newValue) { |
| 4947 | setAttributes({ |
| 4948 | fullHeight: newValue |
| 4949 | }); |
| 4950 | } |
| 4951 | })), /*#__PURE__*/React.createElement(BlockComponent, this.props)); |
| 4952 | } |
| 4953 | }; |
| 4954 | }; |
| 4955 | |
| 4956 | /***/ }), |
| 4957 | |
| 4958 | /***/ "./assets/src/js/pro/blocks-v3/register-block-type-v3.js": |
| 4959 | /*!***************************************************************!*\ |
| 4960 | !*** ./assets/src/js/pro/blocks-v3/register-block-type-v3.js ***! |
| 4961 | \***************************************************************/ |
| 4962 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 4963 | |
| 4964 | "use strict"; |
| 4965 | __webpack_require__.r(__webpack_exports__); |
| 4966 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 4967 | /* harmony export */ getRegisteredBlock: () => (/* binding */ getRegisteredBlock), |
| 4968 | /* harmony export */ registerACFBlockType: () => (/* binding */ registerACFBlockType) |
| 4969 | /* harmony export */ }); |
| 4970 | /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! jquery */ "jquery"); |
| 4971 | /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__); |
| 4972 | /* harmony import */ var _components_block_edit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/block-edit */ "./assets/src/js/pro/blocks-v3/components/block-edit.js"); |
| 4973 | /* harmony import */ var _high_order_components_with_align_text__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./high-order-components/with-align-text */ "./assets/src/js/pro/blocks-v3/high-order-components/with-align-text.js"); |
| 4974 | /* harmony import */ var _high_order_components_with_align_content__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./high-order-components/with-align-content */ "./assets/src/js/pro/blocks-v3/high-order-components/with-align-content.js"); |
| 4975 | /* harmony import */ var _high_order_components_with_full_height__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./high-order-components/with-full-height */ "./assets/src/js/pro/blocks-v3/high-order-components/with-full-height.js"); |
| 4976 | function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } |
| 4977 | /** |
| 4978 | * ACF Block Type Registration - Version 3 |
| 4979 | * Handles registration of ACF blocks (version 3) with WordPress Gutenberg |
| 4980 | * Includes attribute setup, higher-order component composition, and block filtering |
| 4981 | */ |
| 4982 | |
| 4983 | |
| 4984 | |
| 4985 | |
| 4986 | |
| 4987 | |
| 4988 | const { |
| 4989 | InnerBlocks |
| 4990 | } = wp.blockEditor; |
| 4991 | const { |
| 4992 | Component |
| 4993 | } = wp.element; |
| 4994 | const { |
| 4995 | createHigherOrderComponent |
| 4996 | } = wp.compose; |
| 4997 | |
| 4998 | // Registry to store registered block configurations |
| 4999 | const registeredBlocks = {}; |
| 5000 | |
| 5001 | /** |
| 5002 | * Adds an attribute to the block configuration |
| 5003 | * |
| 5004 | * @param {Object} attributes - Existing attributes object |
| 5005 | * @param {string} attributeName - Name of the attribute to add |
| 5006 | * @param {string} attributeType - Type of the attribute (string, boolean, etc.) |
| 5007 | * @returns {Object} - Updated attributes object |
| 5008 | */ |
| 5009 | const addAttribute = (attributes, attributeName, attributeType) => { |
| 5010 | attributes[attributeName] = { |
| 5011 | type: attributeType |
| 5012 | }; |
| 5013 | return attributes; |
| 5014 | }; |
| 5015 | |
| 5016 | /** |
| 5017 | * Checks if block should be registered for current post type |
| 5018 | * |
| 5019 | * @param {Object} blockConfig - Block configuration |
| 5020 | * @returns {boolean} - True if block should be registered |
| 5021 | */ |
| 5022 | function shouldRegisterBlock(blockConfig) { |
| 5023 | const allowedPostTypes = blockConfig.post_types || []; |
| 5024 | if (allowedPostTypes.length) { |
| 5025 | // Always allow in reusable blocks |
| 5026 | allowedPostTypes.push('wp_block'); |
| 5027 | const currentPostType = acf.get('postType'); |
| 5028 | if (!allowedPostTypes.includes(currentPostType)) { |
| 5029 | return false; |
| 5030 | } |
| 5031 | } |
| 5032 | return true; |
| 5033 | } |
| 5034 | |
| 5035 | /** |
| 5036 | * Processes and normalizes block icon |
| 5037 | * |
| 5038 | * @param {Object} blockConfig - Block configuration |
| 5039 | */ |
| 5040 | function processBlockIcon(blockConfig) { |
| 5041 | // Convert SVG string to JSX element |
| 5042 | if (typeof blockConfig.icon === 'string' && blockConfig.icon.substr(0, 4) === '<svg') { |
| 5043 | const iconSvg = blockConfig.icon; |
| 5044 | blockConfig.icon = /*#__PURE__*/React.createElement("div", { |
| 5045 | dangerouslySetInnerHTML: { |
| 5046 | __html: iconSvg |
| 5047 | } |
| 5048 | }); |
| 5049 | } |
| 5050 | |
| 5051 | // Remove icon if empty/invalid |
| 5052 | if (!blockConfig.icon) { |
| 5053 | delete blockConfig.icon; |
| 5054 | } |
| 5055 | } |
| 5056 | |
| 5057 | /** |
| 5058 | * Validates and normalizes block category |
| 5059 | * Falls back to 'common' if category doesn't exist |
| 5060 | * |
| 5061 | * @param {Object} blockConfig - Block configuration |
| 5062 | */ |
| 5063 | function validateBlockCategory(blockConfig) { |
| 5064 | const categoryExists = wp.blocks.getCategories().filter(({ |
| 5065 | slug |
| 5066 | }) => slug === blockConfig.category).pop(); |
| 5067 | if (!categoryExists) { |
| 5068 | blockConfig.category = 'common'; |
| 5069 | } |
| 5070 | } |
| 5071 | |
| 5072 | /** |
| 5073 | * Sets default values for block configuration |
| 5074 | * |
| 5075 | * @param {Object} blockConfig - Block configuration |
| 5076 | * @returns {Object} - Block configuration with defaults applied |
| 5077 | */ |
| 5078 | function applyBlockDefaults(blockConfig) { |
| 5079 | return acf.parseArgs(blockConfig, { |
| 5080 | title: '', |
| 5081 | name: '', |
| 5082 | category: '', |
| 5083 | api_version: 2, |
| 5084 | acf_block_version: 3, |
| 5085 | attributes: {}, |
| 5086 | supports: {} |
| 5087 | }); |
| 5088 | } |
| 5089 | |
| 5090 | /** |
| 5091 | * Cleans up block attributes |
| 5092 | * Removes empty default values |
| 5093 | * |
| 5094 | * @param {Object} blockConfig - Block configuration |
| 5095 | */ |
| 5096 | function cleanBlockAttributes(blockConfig) { |
| 5097 | for (const attributeName in blockConfig.attributes) { |
| 5098 | if ('default' in blockConfig.attributes[attributeName] && blockConfig.attributes[attributeName].default.length === 0) { |
| 5099 | delete blockConfig.attributes[attributeName].default; |
| 5100 | } |
| 5101 | } |
| 5102 | } |
| 5103 | |
| 5104 | /** |
| 5105 | * Configures anchor support if enabled |
| 5106 | * |
| 5107 | * @param {Object} blockConfig - Block configuration |
| 5108 | */ |
| 5109 | function configureAnchorSupport(blockConfig) { |
| 5110 | if (blockConfig.supports && blockConfig.supports.anchor) { |
| 5111 | blockConfig.attributes.anchor = { |
| 5112 | type: 'string' |
| 5113 | }; |
| 5114 | } |
| 5115 | } |
| 5116 | |
| 5117 | /** |
| 5118 | * Applies higher-order components based on block supports |
| 5119 | * |
| 5120 | * @param {React.Component} EditComponent - Base edit component |
| 5121 | * @param {Object} blockConfig - Block configuration |
| 5122 | * @returns {React.Component} - Enhanced edit component |
| 5123 | */ |
| 5124 | function applyHigherOrderComponents(EditComponent, blockConfig) { |
| 5125 | let enhancedComponent = EditComponent; |
| 5126 | |
| 5127 | // Add text alignment support |
| 5128 | if (blockConfig.supports.alignText || blockConfig.supports.align_text) { |
| 5129 | blockConfig.attributes = addAttribute(blockConfig.attributes, 'align_text', 'string'); |
| 5130 | enhancedComponent = (0,_high_order_components_with_align_text__WEBPACK_IMPORTED_MODULE_2__.withAlignText)(enhancedComponent, blockConfig); |
| 5131 | } |
| 5132 | |
| 5133 | // Add content alignment support |
| 5134 | if (blockConfig.supports.alignContent || blockConfig.supports.align_content) { |
| 5135 | blockConfig.attributes = addAttribute(blockConfig.attributes, 'align_content', 'string'); |
| 5136 | enhancedComponent = (0,_high_order_components_with_align_content__WEBPACK_IMPORTED_MODULE_3__.withAlignContent)(enhancedComponent, blockConfig); |
| 5137 | } |
| 5138 | |
| 5139 | // Add full height support |
| 5140 | if (blockConfig.supports.fullHeight || blockConfig.supports.full_height) { |
| 5141 | blockConfig.attributes = addAttribute(blockConfig.attributes, 'full_height', 'boolean'); |
| 5142 | enhancedComponent = (0,_high_order_components_with_full_height__WEBPACK_IMPORTED_MODULE_4__.withFullHeight)(enhancedComponent); |
| 5143 | } |
| 5144 | return enhancedComponent; |
| 5145 | } |
| 5146 | |
| 5147 | /** |
| 5148 | * Registers an ACF block type (version 3) with WordPress |
| 5149 | * |
| 5150 | * @param {Object} blockConfig - ACF block configuration object |
| 5151 | * @returns {Object|boolean} - Registered block type or false if not registered |
| 5152 | */ |
| 5153 | function registerACFBlockType(blockConfig) { |
| 5154 | // Check if block should be registered for current post type |
| 5155 | if (!shouldRegisterBlock(blockConfig)) { |
| 5156 | return false; |
| 5157 | } |
| 5158 | |
| 5159 | // Process icon |
| 5160 | processBlockIcon(blockConfig); |
| 5161 | |
| 5162 | // Validate category |
| 5163 | validateBlockCategory(blockConfig); |
| 5164 | |
| 5165 | // Apply default values |
| 5166 | blockConfig = applyBlockDefaults(blockConfig); |
| 5167 | |
| 5168 | // Clean up attributes |
| 5169 | cleanBlockAttributes(blockConfig); |
| 5170 | |
| 5171 | // Configure anchor support |
| 5172 | configureAnchorSupport(blockConfig); |
| 5173 | |
| 5174 | // Start with base BlockEdit component |
| 5175 | let EditComponent = _components_block_edit__WEBPACK_IMPORTED_MODULE_1__.BlockEdit; |
| 5176 | |
| 5177 | // Apply higher-order components based on supports |
| 5178 | EditComponent = applyHigherOrderComponents(EditComponent, blockConfig); |
| 5179 | |
| 5180 | // Create edit function that passes blockConfig and jQuery |
| 5181 | blockConfig.edit = function (props) { |
| 5182 | return /*#__PURE__*/React.createElement(EditComponent, _extends({}, props, { |
| 5183 | blockType: blockConfig, |
| 5184 | $: (jquery__WEBPACK_IMPORTED_MODULE_0___default()) |
| 5185 | })); |
| 5186 | }; |
| 5187 | |
| 5188 | // Create save function (ACF blocks save to post content as HTML comments) |
| 5189 | blockConfig.save = () => /*#__PURE__*/React.createElement(InnerBlocks.Content, null); |
| 5190 | |
| 5191 | // Store in registry |
| 5192 | registeredBlocks[blockConfig.name] = blockConfig; |
| 5193 | |
| 5194 | // Register with WordPress |
| 5195 | const registeredBlockType = wp.blocks.registerBlockType(blockConfig.name, blockConfig); |
| 5196 | |
| 5197 | // Ensure anchor attribute is properly configured |
| 5198 | if (registeredBlockType && registeredBlockType.attributes && registeredBlockType.attributes.anchor) { |
| 5199 | registeredBlockType.attributes.anchor = { |
| 5200 | type: 'string' |
| 5201 | }; |
| 5202 | } |
| 5203 | return registeredBlockType; |
| 5204 | } |
| 5205 | |
| 5206 | /** |
| 5207 | * Retrieves a registered block configuration by name |
| 5208 | * |
| 5209 | * @param {string} blockName - Name of the block |
| 5210 | * @returns {Object|boolean} - Block configuration or false |
| 5211 | */ |
| 5212 | function getRegisteredBlock(blockName) { |
| 5213 | return registeredBlocks[blockName] || false; |
| 5214 | } |
| 5215 | |
| 5216 | /** |
| 5217 | * Higher-order component to migrate legacy attribute names to new format |
| 5218 | * Handles backward compatibility for align_text -> alignText, etc. |
| 5219 | */ |
| 5220 | const withDefaultAttributes = createHigherOrderComponent(BlockListBlock => class extends Component { |
| 5221 | constructor(props) { |
| 5222 | super(props); |
| 5223 | const { |
| 5224 | name, |
| 5225 | attributes |
| 5226 | } = this.props; |
| 5227 | const blockConfig = getRegisteredBlock(name); |
| 5228 | if (!blockConfig) return; |
| 5229 | |
| 5230 | // Remove empty string attributes |
| 5231 | Object.keys(attributes).forEach(key => { |
| 5232 | if (attributes[key] === '') { |
| 5233 | delete attributes[key]; |
| 5234 | } |
| 5235 | }); |
| 5236 | |
| 5237 | // Map old attribute names to new camelCase names |
| 5238 | const attributeMap = { |
| 5239 | full_height: 'fullHeight', |
| 5240 | align_content: 'alignContent', |
| 5241 | align_text: 'alignText' |
| 5242 | }; |
| 5243 | Object.keys(attributeMap).forEach(oldKey => { |
| 5244 | const newKey = attributeMap[oldKey]; |
| 5245 | if (attributes[oldKey] !== undefined) { |
| 5246 | // Migrate old key to new key |
| 5247 | attributes[newKey] = attributes[oldKey]; |
| 5248 | } else if (attributes[newKey] === undefined && blockConfig[oldKey] !== undefined) { |
| 5249 | // Set default from block config if not present |
| 5250 | attributes[newKey] = blockConfig[oldKey]; |
| 5251 | } |
| 5252 | |
| 5253 | // Clean up old attribute names |
| 5254 | delete blockConfig[oldKey]; |
| 5255 | delete attributes[oldKey]; |
| 5256 | }); |
| 5257 | |
| 5258 | // Apply default values from block config for missing attributes |
| 5259 | for (let key in blockConfig.attributes) { |
| 5260 | if (attributes[key] === undefined && blockConfig[key] !== undefined) { |
| 5261 | attributes[key] = blockConfig[key]; |
| 5262 | } |
| 5263 | } |
| 5264 | } |
| 5265 | render() { |
| 5266 | return /*#__PURE__*/React.createElement(BlockListBlock, this.props); |
| 5267 | } |
| 5268 | }, 'withDefaultAttributes'); |
| 5269 | |
| 5270 | /** |
| 5271 | * Initialize ACF blocks on the 'prepare' action |
| 5272 | * Registers all ACF blocks with version 3 or higher |
| 5273 | */ |
| 5274 | acf.addAction('prepare', function () { |
| 5275 | // Ensure wp.blockEditor exists (backward compatibility) |
| 5276 | if (!wp.blockEditor) { |
| 5277 | wp.blockEditor = wp.editor; |
| 5278 | } |
| 5279 | const blockTypes = acf.get('blockTypes'); |
| 5280 | if (blockTypes) { |
| 5281 | blockTypes.forEach(blockType => { |
| 5282 | // Only register blocks with version 3 or higher |
| 5283 | if (parseInt(blockType.acf_block_version) >= 3) { |
| 5284 | registerACFBlockType(blockType); |
| 5285 | } |
| 5286 | }); |
| 5287 | } |
| 5288 | }); |
| 5289 | |
| 5290 | /** |
| 5291 | * Register WordPress filter for attribute migration |
| 5292 | * Ensures backward compatibility with legacy attribute names |
| 5293 | */ |
| 5294 | wp.hooks.addFilter('editor.BlockListBlock', 'acf/with-default-attributes', withDefaultAttributes); |
| 5295 | |
| 5296 | // Export for testing/external use |
| 5297 | |
| 5298 | |
| 5299 | /***/ }), |
| 5300 | |
| 5301 | /***/ "./assets/src/js/pro/blocks-v3/utils/post-locking.js": |
| 5302 | /*!***********************************************************!*\ |
| 5303 | !*** ./assets/src/js/pro/blocks-v3/utils/post-locking.js ***! |
| 5304 | \***********************************************************/ |
| 5305 | /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { |
| 5306 | |
| 5307 | "use strict"; |
| 5308 | __webpack_require__.r(__webpack_exports__); |
| 5309 | /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
| 5310 | /* harmony export */ isPostSavingLocked: () => (/* binding */ isPostSavingLocked), |
| 5311 | /* harmony export */ lockPostSaving: () => (/* binding */ lockPostSaving), |
| 5312 | /* harmony export */ lockPostSavingByName: () => (/* binding */ lockPostSavingByName), |
| 5313 | /* harmony export */ sortObjectKeys: () => (/* binding */ sortObjectKeys), |
| 5314 | /* harmony export */ unlockPostSaving: () => (/* binding */ unlockPostSaving), |
| 5315 | /* harmony export */ unlockPostSavingByName: () => (/* binding */ unlockPostSavingByName) |
| 5316 | /* harmony export */ }); |
| 5317 | /** |
| 5318 | * WordPress post locking utilities for ACF blocks |
| 5319 | * Handles locking/unlocking post saving during block operations |
| 5320 | */ |
| 5321 | |
| 5322 | /** |
| 5323 | * Locks post saving in the WordPress editor for a specific block |
| 5324 | * Used when block operations are in progress for a specific block instance |
| 5325 | * |
| 5326 | * @param {string} clientId - The block's client ID |
| 5327 | */ |
| 5328 | const lockPostSaving = clientId => { |
| 5329 | const dispatch = wp.data.dispatch('core/editor'); |
| 5330 | if (dispatch) { |
| 5331 | dispatch.lockPostSaving('acf/block/' + clientId); |
| 5332 | } |
| 5333 | }; |
| 5334 | |
| 5335 | /** |
| 5336 | * Unlocks post saving in the WordPress editor for a specific block |
| 5337 | * Called when block operations are complete for a specific block instance |
| 5338 | * |
| 5339 | * @param {string} clientId - The block's client ID |
| 5340 | */ |
| 5341 | const unlockPostSaving = clientId => { |
| 5342 | const dispatch = wp.data.dispatch('core/editor'); |
| 5343 | if (dispatch) { |
| 5344 | dispatch.unlockPostSaving('acf/block/' + clientId); |
| 5345 | } |
| 5346 | }; |
| 5347 | |
| 5348 | /** |
| 5349 | * Checks if post saving is currently locked for a specific block |
| 5350 | * |
| 5351 | * @param {string} clientId - The block's client ID |
| 5352 | * @returns {boolean} - True if post saving is locked for this block |
| 5353 | */ |
| 5354 | const isPostSavingLocked = clientId => { |
| 5355 | const dispatch = wp.data.dispatch('core/editor'); |
| 5356 | if (!dispatch) { |
| 5357 | return false; |
| 5358 | } |
| 5359 | return wp.data.select('core/editor').isPostSavingLocked(`acf/block/${clientId}`); |
| 5360 | }; |
| 5361 | |
| 5362 | /** |
| 5363 | * Locks post saving with a custom lock name |
| 5364 | * Used for global operations that aren't tied to a specific block |
| 5365 | * |
| 5366 | * @param {string} lockName - The name of the lock |
| 5367 | */ |
| 5368 | const lockPostSavingByName = lockName => { |
| 5369 | const dispatch = wp.data.dispatch('core/editor'); |
| 5370 | if (dispatch) { |
| 5371 | dispatch.lockPostSaving('acf/block/' + lockName); |
| 5372 | } |
| 5373 | }; |
| 5374 | |
| 5375 | /** |
| 5376 | * Unlocks post saving with a custom lock name |
| 5377 | * Used for global operations that aren't tied to a specific block |
| 5378 | * |
| 5379 | * @param {string} lockName - The name of the lock |
| 5380 | */ |
| 5381 | const unlockPostSavingByName = lockName => { |
| 5382 | const dispatch = wp.data.dispatch('core/editor'); |
| 5383 | if (dispatch) { |
| 5384 | dispatch.unlockPostSaving('acf/block/' + lockName); |
| 5385 | } |
| 5386 | }; |
| 5387 | |
| 5388 | /** |
| 5389 | * Sorts an object's keys alphabetically and returns a new object |
| 5390 | * Used for consistent object serialization and comparison |
| 5391 | * Ensures that objects with same properties in different order produce same hash |
| 5392 | * |
| 5393 | * @param {Object} obj - Object to sort |
| 5394 | * @returns {Object} - New object with sorted keys in alphabetical order |
| 5395 | */ |
| 5396 | const sortObjectKeys = obj => { |
| 5397 | return Object.keys(obj).sort().reduce((sortedObj, key) => { |
| 5398 | sortedObj[key] = obj[key]; |
| 5399 | return sortedObj; |
| 5400 | }, {}); |
| 5401 | }; |
| 5402 | |
| 5403 | /***/ }), |
| 5404 | |
| 5405 | /***/ "./node_modules/charenc/charenc.js": |
| 5406 | /*!*****************************************!*\ |
| 5407 | !*** ./node_modules/charenc/charenc.js ***! |
| 5408 | \*****************************************/ |
| 5409 | /***/ ((module) => { |
| 5410 | |
| 5411 | var charenc = { |
| 5412 | // UTF-8 encoding |
| 5413 | utf8: { |
| 5414 | // Convert a string to a byte array |
| 5415 | stringToBytes: function(str) { |
| 5416 | return charenc.bin.stringToBytes(unescape(encodeURIComponent(str))); |
| 5417 | }, |
| 5418 | |
| 5419 | // Convert a byte array to a string |
| 5420 | bytesToString: function(bytes) { |
| 5421 | return decodeURIComponent(escape(charenc.bin.bytesToString(bytes))); |
| 5422 | } |
| 5423 | }, |
| 5424 | |
| 5425 | // Binary encoding |
| 5426 | bin: { |
| 5427 | // Convert a string to a byte array |
| 5428 | stringToBytes: function(str) { |
| 5429 | for (var bytes = [], i = 0; i < str.length; i++) |
| 5430 | bytes.push(str.charCodeAt(i) & 0xFF); |
| 5431 | return bytes; |
| 5432 | }, |
| 5433 | |
| 5434 | // Convert a byte array to a string |
| 5435 | bytesToString: function(bytes) { |
| 5436 | for (var str = [], i = 0; i < bytes.length; i++) |
| 5437 | str.push(String.fromCharCode(bytes[i])); |
| 5438 | return str.join(''); |
| 5439 | } |
| 5440 | } |
| 5441 | }; |
| 5442 | |
| 5443 | module.exports = charenc; |
| 5444 | |
| 5445 | |
| 5446 | /***/ }), |
| 5447 | |
| 5448 | /***/ "./node_modules/crypt/crypt.js": |
| 5449 | /*!*************************************!*\ |
| 5450 | !*** ./node_modules/crypt/crypt.js ***! |
| 5451 | \*************************************/ |
| 5452 | /***/ ((module) => { |
| 5453 | |
| 5454 | (function() { |
| 5455 | var base64map |
| 5456 | = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', |
| 5457 | |
| 5458 | crypt = { |
| 5459 | // Bit-wise rotation left |
| 5460 | rotl: function(n, b) { |
| 5461 | return (n << b) | (n >>> (32 - b)); |
| 5462 | }, |
| 5463 | |
| 5464 | // Bit-wise rotation right |
| 5465 | rotr: function(n, b) { |
| 5466 | return (n << (32 - b)) | (n >>> b); |
| 5467 | }, |
| 5468 | |
| 5469 | // Swap big-endian to little-endian and vice versa |
| 5470 | endian: function(n) { |
| 5471 | // If number given, swap endian |
| 5472 | if (n.constructor == Number) { |
| 5473 | return crypt.rotl(n, 8) & 0x00FF00FF | crypt.rotl(n, 24) & 0xFF00FF00; |
| 5474 | } |
| 5475 | |
| 5476 | // Else, assume array and swap all items |
| 5477 | for (var i = 0; i < n.length; i++) |
| 5478 | n[i] = crypt.endian(n[i]); |
| 5479 | return n; |
| 5480 | }, |
| 5481 | |
| 5482 | // Generate an array of any length of random bytes |
| 5483 | randomBytes: function(n) { |
| 5484 | for (var bytes = []; n > 0; n--) |
| 5485 | bytes.push(Math.floor(Math.random() * 256)); |
| 5486 | return bytes; |
| 5487 | }, |
| 5488 | |
| 5489 | // Convert a byte array to big-endian 32-bit words |
| 5490 | bytesToWords: function(bytes) { |
| 5491 | for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) |
| 5492 | words[b >>> 5] |= bytes[i] << (24 - b % 32); |
| 5493 | return words; |
| 5494 | }, |
| 5495 | |
| 5496 | // Convert big-endian 32-bit words to a byte array |
| 5497 | wordsToBytes: function(words) { |
| 5498 | for (var bytes = [], b = 0; b < words.length * 32; b += 8) |
| 5499 | bytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF); |
| 5500 | return bytes; |
| 5501 | }, |
| 5502 | |
| 5503 | // Convert a byte array to a hex string |
| 5504 | bytesToHex: function(bytes) { |
| 5505 | for (var hex = [], i = 0; i < bytes.length; i++) { |
| 5506 | hex.push((bytes[i] >>> 4).toString(16)); |
| 5507 | hex.push((bytes[i] & 0xF).toString(16)); |
| 5508 | } |
| 5509 | return hex.join(''); |
| 5510 | }, |
| 5511 | |
| 5512 | // Convert a hex string to a byte array |
| 5513 | hexToBytes: function(hex) { |
| 5514 | for (var bytes = [], c = 0; c < hex.length; c += 2) |
| 5515 | bytes.push(parseInt(hex.substr(c, 2), 16)); |
| 5516 | return bytes; |
| 5517 | }, |
| 5518 | |
| 5519 | // Convert a byte array to a base-64 string |
| 5520 | bytesToBase64: function(bytes) { |
| 5521 | for (var base64 = [], i = 0; i < bytes.length; i += 3) { |
| 5522 | var triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; |
| 5523 | for (var j = 0; j < 4; j++) |
| 5524 | if (i * 8 + j * 6 <= bytes.length * 8) |
| 5525 | base64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F)); |
| 5526 | else |
| 5527 | base64.push('='); |
| 5528 | } |
| 5529 | return base64.join(''); |
| 5530 | }, |
| 5531 | |
| 5532 | // Convert a base-64 string to a byte array |
| 5533 | base64ToBytes: function(base64) { |
| 5534 | // Remove non-base-64 characters |
| 5535 | base64 = base64.replace(/[^A-Z0-9+\/]/ig, ''); |
| 5536 | |
| 5537 | for (var bytes = [], i = 0, imod4 = 0; i < base64.length; |
| 5538 | imod4 = ++i % 4) { |
| 5539 | if (imod4 == 0) continue; |
| 5540 | bytes.push(((base64map.indexOf(base64.charAt(i - 1)) |
| 5541 | & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |
| 5542 | | (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2))); |
| 5543 | } |
| 5544 | return bytes; |
| 5545 | } |
| 5546 | }; |
| 5547 | |
| 5548 | module.exports = crypt; |
| 5549 | })(); |
| 5550 | |
| 5551 | |
| 5552 | /***/ }), |
| 5553 | |
| 5554 | /***/ "./node_modules/is-buffer/index.js": |
| 5555 | /*!*****************************************!*\ |
| 5556 | !*** ./node_modules/is-buffer/index.js ***! |
| 5557 | \*****************************************/ |
| 5558 | /***/ ((module) => { |
| 5559 | |
| 5560 | /*! |
| 5561 | * Determine if an object is a Buffer |
| 5562 | * |
| 5563 | * @author Feross Aboukhadijeh <https://feross.org> |
| 5564 | * @license MIT |
| 5565 | */ |
| 5566 | |
| 5567 | // The _isBuffer check is for Safari 5-7 support, because it's missing |
| 5568 | // Object.prototype.constructor. Remove this eventually |
| 5569 | module.exports = function (obj) { |
| 5570 | return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) |
| 5571 | } |
| 5572 | |
| 5573 | function isBuffer (obj) { |
| 5574 | return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) |
| 5575 | } |
| 5576 | |
| 5577 | // For Node v0.10 support. Remove this eventually. |
| 5578 | function isSlowBuffer (obj) { |
| 5579 | return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) |
| 5580 | } |
| 5581 | |
| 5582 | |
| 5583 | /***/ }), |
| 5584 | |
| 5585 | /***/ "./node_modules/md5/md5.js": |
| 5586 | /*!*********************************!*\ |
| 5587 | !*** ./node_modules/md5/md5.js ***! |
| 5588 | \*********************************/ |
| 5589 | /***/ ((module, __unused_webpack_exports, __webpack_require__) => { |
| 5590 | |
| 5591 | (function(){ |
| 5592 | var crypt = __webpack_require__(/*! crypt */ "./node_modules/crypt/crypt.js"), |
| 5593 | utf8 = (__webpack_require__(/*! charenc */ "./node_modules/charenc/charenc.js").utf8), |
| 5594 | isBuffer = __webpack_require__(/*! is-buffer */ "./node_modules/is-buffer/index.js"), |
| 5595 | bin = (__webpack_require__(/*! charenc */ "./node_modules/charenc/charenc.js").bin), |
| 5596 | |
| 5597 | // The core |
| 5598 | md5 = function (message, options) { |
| 5599 | // Convert to byte array |
| 5600 | if (message.constructor == String) |
| 5601 | if (options && options.encoding === 'binary') |
| 5602 | message = bin.stringToBytes(message); |
| 5603 | else |
| 5604 | message = utf8.stringToBytes(message); |
| 5605 | else if (isBuffer(message)) |
| 5606 | message = Array.prototype.slice.call(message, 0); |
| 5607 | else if (!Array.isArray(message) && message.constructor !== Uint8Array) |
| 5608 | message = message.toString(); |
| 5609 | // else, assume byte array already |
| 5610 | |
| 5611 | var m = crypt.bytesToWords(message), |
| 5612 | l = message.length * 8, |
| 5613 | a = 1732584193, |
| 5614 | b = -271733879, |
| 5615 | c = -1732584194, |
| 5616 | d = 271733878; |
| 5617 | |
| 5618 | // Swap endian |
| 5619 | for (var i = 0; i < m.length; i++) { |
| 5620 | m[i] = ((m[i] << 8) | (m[i] >>> 24)) & 0x00FF00FF | |
| 5621 | ((m[i] << 24) | (m[i] >>> 8)) & 0xFF00FF00; |
| 5622 | } |
| 5623 | |
| 5624 | // Padding |
| 5625 | m[l >>> 5] |= 0x80 << (l % 32); |
| 5626 | m[(((l + 64) >>> 9) << 4) + 14] = l; |
| 5627 | |
| 5628 | // Method shortcuts |
| 5629 | var FF = md5._ff, |
| 5630 | GG = md5._gg, |
| 5631 | HH = md5._hh, |
| 5632 | II = md5._ii; |
| 5633 | |
| 5634 | for (var i = 0; i < m.length; i += 16) { |
| 5635 | |
| 5636 | var aa = a, |
| 5637 | bb = b, |
| 5638 | cc = c, |
| 5639 | dd = d; |
| 5640 | |
| 5641 | a = FF(a, b, c, d, m[i+ 0], 7, -680876936); |
| 5642 | d = FF(d, a, b, c, m[i+ 1], 12, -389564586); |
| 5643 | c = FF(c, d, a, b, m[i+ 2], 17, 606105819); |
| 5644 | b = FF(b, c, d, a, m[i+ 3], 22, -1044525330); |
| 5645 | a = FF(a, b, c, d, m[i+ 4], 7, -176418897); |
| 5646 | d = FF(d, a, b, c, m[i+ 5], 12, 1200080426); |
| 5647 | c = FF(c, d, a, b, m[i+ 6], 17, -1473231341); |
| 5648 | b = FF(b, c, d, a, m[i+ 7], 22, -45705983); |
| 5649 | a = FF(a, b, c, d, m[i+ 8], 7, 1770035416); |
| 5650 | d = FF(d, a, b, c, m[i+ 9], 12, -1958414417); |
| 5651 | c = FF(c, d, a, b, m[i+10], 17, -42063); |
| 5652 | b = FF(b, c, d, a, m[i+11], 22, -1990404162); |
| 5653 | a = FF(a, b, c, d, m[i+12], 7, 1804603682); |
| 5654 | d = FF(d, a, b, c, m[i+13], 12, -40341101); |
| 5655 | c = FF(c, d, a, b, m[i+14], 17, -1502002290); |
| 5656 | b = FF(b, c, d, a, m[i+15], 22, 1236535329); |
| 5657 | |
| 5658 | a = GG(a, b, c, d, m[i+ 1], 5, -165796510); |
| 5659 | d = GG(d, a, b, c, m[i+ 6], 9, -1069501632); |
| 5660 | c = GG(c, d, a, b, m[i+11], 14, 643717713); |
| 5661 | b = GG(b, c, d, a, m[i+ 0], 20, -373897302); |
| 5662 | a = GG(a, b, c, d, m[i+ 5], 5, -701558691); |
| 5663 | d = GG(d, a, b, c, m[i+10], 9, 38016083); |
| 5664 | c = GG(c, d, a, b, m[i+15], 14, -660478335); |
| 5665 | b = GG(b, c, d, a, m[i+ 4], 20, -405537848); |
| 5666 | a = GG(a, b, c, d, m[i+ 9], 5, 568446438); |
| 5667 | d = GG(d, a, b, c, m[i+14], 9, -1019803690); |
| 5668 | c = GG(c, d, a, b, m[i+ 3], 14, -187363961); |
| 5669 | b = GG(b, c, d, a, m[i+ 8], 20, 1163531501); |
| 5670 | a = GG(a, b, c, d, m[i+13], 5, -1444681467); |
| 5671 | d = GG(d, a, b, c, m[i+ 2], 9, -51403784); |
| 5672 | c = GG(c, d, a, b, m[i+ 7], 14, 1735328473); |
| 5673 | b = GG(b, c, d, a, m[i+12], 20, -1926607734); |
| 5674 | |
| 5675 | a = HH(a, b, c, d, m[i+ 5], 4, -378558); |
| 5676 | d = HH(d, a, b, c, m[i+ 8], 11, -2022574463); |
| 5677 | c = HH(c, d, a, b, m[i+11], 16, 1839030562); |
| 5678 | b = HH(b, c, d, a, m[i+14], 23, -35309556); |
| 5679 | a = HH(a, b, c, d, m[i+ 1], 4, -1530992060); |
| 5680 | d = HH(d, a, b, c, m[i+ 4], 11, 1272893353); |
| 5681 | c = HH(c, d, a, b, m[i+ 7], 16, -155497632); |
| 5682 | b = HH(b, c, d, a, m[i+10], 23, -1094730640); |
| 5683 | a = HH(a, b, c, d, m[i+13], 4, 681279174); |
| 5684 | d = HH(d, a, b, c, m[i+ 0], 11, -358537222); |
| 5685 | c = HH(c, d, a, b, m[i+ 3], 16, -722521979); |
| 5686 | b = HH(b, c, d, a, m[i+ 6], 23, 76029189); |
| 5687 | a = HH(a, b, c, d, m[i+ 9], 4, -640364487); |
| 5688 | d = HH(d, a, b, c, m[i+12], 11, -421815835); |
| 5689 | c = HH(c, d, a, b, m[i+15], 16, 530742520); |
| 5690 | b = HH(b, c, d, a, m[i+ 2], 23, -995338651); |
| 5691 | |
| 5692 | a = II(a, b, c, d, m[i+ 0], 6, -198630844); |
| 5693 | d = II(d, a, b, c, m[i+ 7], 10, 1126891415); |
| 5694 | c = II(c, d, a, b, m[i+14], 15, -1416354905); |
| 5695 | b = II(b, c, d, a, m[i+ 5], 21, -57434055); |
| 5696 | a = II(a, b, c, d, m[i+12], 6, 1700485571); |
| 5697 | d = II(d, a, b, c, m[i+ 3], 10, -1894986606); |
| 5698 | c = II(c, d, a, b, m[i+10], 15, -1051523); |
| 5699 | b = II(b, c, d, a, m[i+ 1], 21, -2054922799); |
| 5700 | a = II(a, b, c, d, m[i+ 8], 6, 1873313359); |
| 5701 | d = II(d, a, b, c, m[i+15], 10, -30611744); |
| 5702 | c = II(c, d, a, b, m[i+ 6], 15, -1560198380); |
| 5703 | b = II(b, c, d, a, m[i+13], 21, 1309151649); |
| 5704 | a = II(a, b, c, d, m[i+ 4], 6, -145523070); |
| 5705 | d = II(d, a, b, c, m[i+11], 10, -1120210379); |
| 5706 | c = II(c, d, a, b, m[i+ 2], 15, 718787259); |
| 5707 | b = II(b, c, d, a, m[i+ 9], 21, -343485551); |
| 5708 | |
| 5709 | a = (a + aa) >>> 0; |
| 5710 | b = (b + bb) >>> 0; |
| 5711 | c = (c + cc) >>> 0; |
| 5712 | d = (d + dd) >>> 0; |
| 5713 | } |
| 5714 | |
| 5715 | return crypt.endian([a, b, c, d]); |
| 5716 | }; |
| 5717 | |
| 5718 | // Auxiliary functions |
| 5719 | md5._ff = function (a, b, c, d, x, s, t) { |
| 5720 | var n = a + (b & c | ~b & d) + (x >>> 0) + t; |
| 5721 | return ((n << s) | (n >>> (32 - s))) + b; |
| 5722 | }; |
| 5723 | md5._gg = function (a, b, c, d, x, s, t) { |
| 5724 | var n = a + (b & d | c & ~d) + (x >>> 0) + t; |
| 5725 | return ((n << s) | (n >>> (32 - s))) + b; |
| 5726 | }; |
| 5727 | md5._hh = function (a, b, c, d, x, s, t) { |
| 5728 | var n = a + (b ^ c ^ d) + (x >>> 0) + t; |
| 5729 | return ((n << s) | (n >>> (32 - s))) + b; |
| 5730 | }; |
| 5731 | md5._ii = function (a, b, c, d, x, s, t) { |
| 5732 | var n = a + (c ^ (b | ~d)) + (x >>> 0) + t; |
| 5733 | return ((n << s) | (n >>> (32 - s))) + b; |
| 5734 | }; |
| 5735 | |
| 5736 | // Package private blocksize |
| 5737 | md5._blocksize = 16; |
| 5738 | md5._digestsize = 16; |
| 5739 | |
| 5740 | module.exports = function (message, options) { |
| 5741 | if (message === undefined || message === null) |
| 5742 | throw new Error('Illegal argument ' + message); |
| 5743 | |
| 5744 | var digestbytes = crypt.wordsToBytes(md5(message, options)); |
| 5745 | return options && options.asBytes ? digestbytes : |
| 5746 | options && options.asString ? bin.bytesToString(digestbytes) : |
| 5747 | crypt.bytesToHex(digestbytes); |
| 5748 | }; |
| 5749 | |
| 5750 | })(); |
| 5751 | |
| 5752 | |
| 5753 | /***/ }), |
| 5754 | |
| 5755 | /***/ "@wordpress/block-editor": |
| 5756 | /*!*************************************!*\ |
| 5757 | !*** external ["wp","blockEditor"] ***! |
| 5758 | \*************************************/ |
| 5759 | /***/ ((module) => { |
| 5760 | |
| 5761 | "use strict"; |
| 5762 | module.exports = window["wp"]["blockEditor"]; |
| 5763 | |
| 5764 | /***/ }), |
| 5765 | |
| 5766 | /***/ "@wordpress/components": |
| 5767 | /*!************************************!*\ |
| 5768 | !*** external ["wp","components"] ***! |
| 5769 | \************************************/ |
| 5770 | /***/ ((module) => { |
| 5771 | |
| 5772 | "use strict"; |
| 5773 | module.exports = window["wp"]["components"]; |
| 5774 | |
| 5775 | /***/ }), |
| 5776 | |
| 5777 | /***/ "@wordpress/element": |
| 5778 | /*!*********************************!*\ |
| 5779 | !*** external ["wp","element"] ***! |
| 5780 | \*********************************/ |
| 5781 | /***/ ((module) => { |
| 5782 | |
| 5783 | "use strict"; |
| 5784 | module.exports = window["wp"]["element"]; |
| 5785 | |
| 5786 | /***/ }), |
| 5787 | |
| 5788 | /***/ "jquery": |
| 5789 | /*!*************************!*\ |
| 5790 | !*** external "jQuery" ***! |
| 5791 | \*************************/ |
| 5792 | /***/ ((module) => { |
| 5793 | |
| 5794 | "use strict"; |
| 5795 | module.exports = window["jQuery"]; |
| 5796 | |
| 5797 | /***/ }) |
| 5798 | |
| 5799 | /******/ }); |
| 5800 | /************************************************************************/ |
| 5801 | /******/ // The module cache |
| 5802 | /******/ var __webpack_module_cache__ = {}; |
| 5803 | /******/ |
| 5804 | /******/ // The require function |
| 5805 | /******/ function __webpack_require__(moduleId) { |
| 5806 | /******/ // Check if module is in cache |
| 5807 | /******/ var cachedModule = __webpack_module_cache__[moduleId]; |
| 5808 | /******/ if (cachedModule !== undefined) { |
| 5809 | /******/ return cachedModule.exports; |
| 5810 | /******/ } |
| 5811 | /******/ // Create a new module (and put it into the cache) |
| 5812 | /******/ var module = __webpack_module_cache__[moduleId] = { |
| 5813 | /******/ // no module.id needed |
| 5814 | /******/ // no module.loaded needed |
| 5815 | /******/ exports: {} |
| 5816 | /******/ }; |
| 5817 | /******/ |
| 5818 | /******/ // Execute the module function |
| 5819 | /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); |
| 5820 | /******/ |
| 5821 | /******/ // Return the exports of the module |
| 5822 | /******/ return module.exports; |
| 5823 | /******/ } |
| 5824 | /******/ |
| 5825 | /************************************************************************/ |
| 5826 | /******/ /* webpack/runtime/compat get default export */ |
| 5827 | /******/ (() => { |
| 5828 | /******/ // getDefaultExport function for compatibility with non-harmony modules |
| 5829 | /******/ __webpack_require__.n = (module) => { |
| 5830 | /******/ var getter = module && module.__esModule ? |
| 5831 | /******/ () => (module['default']) : |
| 5832 | /******/ () => (module); |
| 5833 | /******/ __webpack_require__.d(getter, { a: getter }); |
| 5834 | /******/ return getter; |
| 5835 | /******/ }; |
| 5836 | /******/ })(); |
| 5837 | /******/ |
| 5838 | /******/ /* webpack/runtime/define property getters */ |
| 5839 | /******/ (() => { |
| 5840 | /******/ // define getter functions for harmony exports |
| 5841 | /******/ __webpack_require__.d = (exports, definition) => { |
| 5842 | /******/ for(var key in definition) { |
| 5843 | /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { |
| 5844 | /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); |
| 5845 | /******/ } |
| 5846 | /******/ } |
| 5847 | /******/ }; |
| 5848 | /******/ })(); |
| 5849 | /******/ |
| 5850 | /******/ /* webpack/runtime/hasOwnProperty shorthand */ |
| 5851 | /******/ (() => { |
| 5852 | /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) |
| 5853 | /******/ })(); |
| 5854 | /******/ |
| 5855 | /******/ /* webpack/runtime/make namespace object */ |
| 5856 | /******/ (() => { |
| 5857 | /******/ // define __esModule on exports |
| 5858 | /******/ __webpack_require__.r = (exports) => { |
| 5859 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
| 5860 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
| 5861 | /******/ } |
| 5862 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); |
| 5863 | /******/ }; |
| 5864 | /******/ })(); |
| 5865 | /******/ |
| 5866 | /************************************************************************/ |
| 5867 | var __webpack_exports__ = {}; |
| 5868 | // This entry needs to be wrapped in an IIFE because it needs to be in strict mode. |
| 5869 | (() => { |
| 5870 | "use strict"; |
| 5871 | /*!*********************************************!*\ |
| 5872 | !*** ./assets/src/js/pro/acf-pro-blocks.js ***! |
| 5873 | \*********************************************/ |
| 5874 | __webpack_require__.r(__webpack_exports__); |
| 5875 | /* harmony import */ var _acf_jsx_names_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./_acf-jsx-names.js */ "./assets/src/js/pro/_acf-jsx-names.js"); |
| 5876 | /* harmony import */ var _acf_jsx_names_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_acf_jsx_names_js__WEBPACK_IMPORTED_MODULE_0__); |
| 5877 | /* harmony import */ var _acf_blocks_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./_acf-blocks.js */ "./assets/src/js/pro/_acf-blocks.js"); |
| 5878 | /* harmony import */ var _acf_blocks_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_acf_blocks_js__WEBPACK_IMPORTED_MODULE_1__); |
| 5879 | /* harmony import */ var _acf_blocks_v3_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./_acf-blocks-v3.js */ "./assets/src/js/pro/_acf-blocks-v3.js"); |
| 5880 | |
| 5881 | |
| 5882 | |
| 5883 | })(); |
| 5884 | |
| 5885 | /******/ })() |
| 5886 | ; |
| 5887 | //# sourceMappingURL=acf-pro-blocks.js.map |