| 1 |
import { select,dispatch, subscribe } from '@wordpress/data'; |
| 2 |
import { createBlock, parse, serialize } from '@wordpress/blocks'; |
| 3 |
import isInvalid from './isInvalid'; |
| 4 |
|
| 5 |
// Flag to Detect if At Least One Block was Recovered. |
| 6 |
let recoveryDone = false; |
| 7 |
|
| 8 |
// Create Recovery CSS to Hide All Errornous Blocks. |
| 9 |
const createRecoveryCSS = () => { |
| 10 |
const recoveryCSS = document.createElement( 'style' ); |
| 11 |
recoveryCSS.setAttribute( 'id', 'uagb-recovery-styles' ); |
| 12 |
recoveryCSS.innerHTML = '.has-warning[data-type^="uagb/"] { opacity: 0 !important; }'; |
| 13 |
document.body.appendChild( recoveryCSS ); |
| 14 |
}; |
| 15 |
|
| 16 |
// Destroy the Recovery CSS to Restore the Editor to its Original State. |
| 17 |
const destroyRecoveryCSS = () => { |
| 18 |
const recoveryCSS = document.querySelector( '#uagb-recovery-styles' ); |
| 19 |
if ( recoveryCSS ) { |
| 20 |
document.body.removeChild( recoveryCSS ); |
| 21 |
} |
| 22 |
}; |
| 23 |
|
| 24 |
// Start Block Recovery for all Spectra Blocks. |
| 25 |
const initBlockRecovery = ( blocks ) => { |
| 26 |
const curBlocks = [ ...blocks ]; |
| 27 |
let isRecovered = false; |
| 28 |
|
| 29 |
const recoverInnerBlocks = ( innerBlocks ) => { |
| 30 |
innerBlocks.forEach( ( block ) => { |
| 31 |
if ( isInvalid( block ) ) { |
| 32 |
isRecovered = true; |
| 33 |
const newBlock = recoverBlock( block ); |
| 34 |
for ( const key in newBlock ) { |
| 35 |
block[ key ] = newBlock[ key ]; |
| 36 |
} |
| 37 |
} |
| 38 |
|
| 39 |
if ( block.innerBlocks.length ) { |
| 40 |
recoverInnerBlocks( block.innerBlocks ); |
| 41 |
} |
| 42 |
} ); |
| 43 |
}; |
| 44 |
|
| 45 |
recoverInnerBlocks( curBlocks ); |
| 46 |
return [ curBlocks, isRecovered ]; |
| 47 |
}; |
| 48 |
|
| 49 |
// Create Replacement Blocks Based on the Fixed Variant. |
| 50 |
const recoverBlocks = ( allBlocks ) => ( |
| 51 |
allBlocks.map( ( block ) => { |
| 52 |
const curBlock = block; |
| 53 |
|
| 54 |
if ( 'core/block' === block.name ) { |
| 55 |
const { attributes: { ref } } = block; |
| 56 |
const reusableBlockPosts = select( 'core' ).getEntityRecords( |
| 57 |
'postType', |
| 58 |
'wp_block' |
| 59 |
); |
| 60 |
|
| 61 |
let reusableBlockPost = null; |
| 62 |
|
| 63 |
if ( reusableBlockPosts ) { |
| 64 |
reusableBlockPosts?.forEach( ( post ) => { |
| 65 |
if ( ref === post?.id ) { |
| 66 |
reusableBlockPost = post?.content?.raw; |
| 67 |
} |
| 68 |
} ); |
| 69 |
} |
| 70 |
|
| 71 |
if ( null === reusableBlockPost ) { |
| 72 |
return curBlock |
| 73 |
} |
| 74 |
|
| 75 |
const parsedBlocks = parse( reusableBlockPost ) || []; |
| 76 |
|
| 77 |
const [ recoveredBlocks, isRecovered ] = initBlockRecovery( parsedBlocks ); |
| 78 |
|
| 79 |
if ( isRecovered ) { |
| 80 |
recoveryDone = true; |
| 81 |
return { |
| 82 |
blocks: recoveredBlocks, |
| 83 |
isReusable: true, |
| 84 |
ref, |
| 85 |
}; |
| 86 |
} |
| 87 |
} |
| 88 |
|
| 89 |
if ( curBlock.innerBlocks && curBlock.innerBlocks.length ) { |
| 90 |
const newInnerBlocks = recoverBlocks( curBlock.innerBlocks ); |
| 91 |
if ( newInnerBlocks.some( ( innerBlock ) => innerBlock.recovered ) ) { |
| 92 |
curBlock.innerBlocks = newInnerBlocks; |
| 93 |
curBlock.replacedClientId = curBlock.clientId; |
| 94 |
curBlock.recovered = true; |
| 95 |
} |
| 96 |
} |
| 97 |
if ( isInvalid( curBlock ) ) { |
| 98 |
recoveryDone = true; |
| 99 |
const newBlock = recoverBlock( curBlock ); |
| 100 |
newBlock.replacedClientId = curBlock.clientId; |
| 101 |
newBlock.recovered = true; |
| 102 |
return newBlock; |
| 103 |
} |
| 104 |
|
| 105 |
return curBlock; |
| 106 |
} ) |
| 107 |
); |
| 108 |
|
| 109 |
// Recover Current Block. |
| 110 |
const recoverBlock = ( { name, attributes, innerBlocks } ) => ( createBlock( name, attributes, innerBlocks ) ); |
| 111 |
|
| 112 |
// Start with the Automatic Block Recovery Process. |
| 113 |
const autoBlockRecovery = () => { |
| 114 |
createRecoveryCSS(); |
| 115 |
setTimeout( () => { |
| 116 |
const unsubscribe = subscribe( () => { |
| 117 |
if ( select( 'core' ).getEntityRecords( 'postType', 'wp_block' ) !== null ) { |
| 118 |
unsubscribe(); |
| 119 |
const recoveredBlocks = recoverBlocks( select( 'core/block-editor' ).getBlocks() ); |
| 120 |
recoveredBlocks.forEach( ( block ) => { |
| 121 |
if ( block.isReusable && block.ref ) { |
| 122 |
dispatch( 'core' ).editEntityRecord( |
| 123 |
'postType', |
| 124 |
'wp_block', |
| 125 |
block.ref, |
| 126 |
{ content: serialize( block.blocks ) } |
| 127 |
).then(); |
| 128 |
} |
| 129 |
|
| 130 |
if ( block.recovered && block.replacedClientId ) { |
| 131 |
dispatch( 'core/block-editor' ).replaceBlock( block.replacedClientId, block ); |
| 132 |
} |
| 133 |
} ); |
| 134 |
if ( recoveryDone ) { |
| 135 |
console.log( '%cSpectra Auto Recovery Enabled: All Spectra Blocks on this page have been recovered!', 'border-radius: 6px; width: 100%; margin: 16px 0; padding: 16px; background-color: #007CBA; color: #fff; font-weight: bold; text-shadow: 2px 2px 2px #0063A1;' ); //eslint-disable-line no-console |
| 136 |
} |
| 137 |
destroyRecoveryCSS(); |
| 138 |
} |
| 139 |
} ); |
| 140 |
}, 0 ); |
| 141 |
}; |
| 142 |
|
| 143 |
export default autoBlockRecovery; |
| 144 |
|