actionHelper.js (10557B)
1 const { parse, createBlock } = wp.blocks; 2 const { apiFetch } = wp; 3 const { dispatch, select } = wp.data; 4 const { getBlockOrder } = select( 'core/block-editor' ); 5 const { getBlockTypes } = select('core/blocks'); 6 const { savePost, editPost } = dispatch('core/editor'); 7 const { insertBlocks, removeBlocks, multiSelect } = dispatch('core/block-editor'); 8 const { createSuccessNotice, createErrorNotice, createNotice, removeNotice } = dispatch('core/notices'); 9 import { __ } from '@wordpress/i18n' 10 import { ModalManager } from '~redux-templates/modal-manager'; 11 import PreviewModal from '../modal-preview'; 12 import FeedbackDialog from '~redux-templates/modal-feedback'; 13 14 15 // create Block to import template 16 export const handleBlock = (data, installedDependencies) => { 17 let block_data = null; 18 if ('template' in data) { 19 block_data = parse(data.template); 20 } else if ('attributes' in data) { 21 if (!('innerBlocks' in data)) { 22 data.innerBlocks = []; 23 } 24 if (!('name' in data)) { 25 errorCallback('Template malformed, `name` for block not specified.'); 26 } 27 // This kind of plugins are not ready to accept before reloading, thus, we save it into localStorage and just reload for now. 28 if (installedDependencies === true) { 29 window.redux_templates_tempdata = [...window.redux_templates_tempdata, data]; 30 return null; 31 } else { 32 block_data = createBlock(data.name, data.attributes, data.innerBlocks) 33 } 34 } else { 35 errorCallback('Template error. Please try again.'); 36 } 37 return block_data; 38 } 39 40 export const processImportHelper = () => { 41 const { setImportingTemplate, discardAllErrorMessages, clearSearch } = dispatch('redux-templates/sectionslist'); 42 const type = select('redux-templates/sectionslist').getActiveItemType() === 'section' ? 'sections' : 'pages'; 43 const data = select('redux-templates/sectionslist').getImportingTemplate(); 44 const installedDependencies = select('redux-templates/sectionslist').getInstalledDependencies(); 45 const isImportToAppend = select('redux-templates/sectionslist').getImportToAppend(); 46 47 if (type === 'pages') { 48 editPost({'template': 'redux-templates_full_width'}); 49 } else { 50 if ( '' === select( 'core/editor' ).getEditedPostAttribute( 'template' ) ) { 51 editPost({'template': 'redux-templates_contained'}); 52 } 53 } 54 55 discardAllErrorMessages(); 56 let the_url = 'redux/v1/templates/template?type=' + type + '&id=' + data.id + '&uid=' + window.userSettings.uid; 57 if ('source' in data) { 58 the_url += '&source=' + data.source; 59 } 60 61 const options = { 62 method: 'GET', 63 path: the_url, 64 headers: { 'Content-Type': 'application/json', 'Registered-Blocks': installedBlocksTypes() } 65 }; 66 67 if (dispatch('core/edit-post') && select('core/edit-post').getEditorMode() === 'text') { 68 const { switchEditorMode } = dispatch('core/edit-post'); 69 switchEditorMode() 70 } 71 window.redux_templates_tempdata = []; 72 73 apiFetch(options).then(response => { 74 // First, let's give user feedback. 75 displayNotice(response.data, {type: 'snackbar'}); 76 77 if (isImportToAppend === false) { 78 const rootBlocksClientIds = getBlockOrder(); 79 multiSelect( 80 rootBlocksClientIds[0], 81 rootBlocksClientIds[rootBlocksClientIds.length - 1] 82 ); 83 removeBlocks( rootBlocksClientIds ); 84 } 85 86 if (response.success && response.data) { 87 let responseBlockData = response.data; 88 89 // Important: Update left count from the response in case of no Redux PRO 90 if (redux_templates.mokama !== '1' && isNaN(responseBlockData.left) === false) 91 redux_templates.left = responseBlockData.left; 92 93 let handledData = []; 94 if (responseBlockData.hasOwnProperty('template') || responseBlockData.hasOwnProperty('attributes')) 95 handledData = handleBlock(responseBlockData, installedDependencies); 96 else 97 handledData = Object.keys(responseBlockData).filter(key => key !== 'cache') 98 .map(key => handleBlock(responseBlockData[key], installedDependencies)); 99 100 localStorage.setItem('importing_data', JSON.stringify(data)); 101 localStorage.setItem('block_data', JSON.stringify(redux_templates_tempdata)); 102 localStorage.setItem('is_appending', isImportToAppend); 103 104 insertBlocks(handledData); 105 createSuccessNotice('Template inserted', { type: 'snackbar' }); 106 107 if (installedDependencies === true) 108 savePost() 109 .then(() => window.location.reload()) 110 .catch(() => createErrorNotice('Error while saving the post', { type: 'snackbar' })); 111 else { 112 ModalManager.close(); 113 ModalManager.closeCustomizer(); 114 setImportingTemplate(null); 115 } 116 afterImportHandling(data, handledData); 117 118 } else { 119 if (response.success === false) 120 errorCallback(response.data.message); 121 else 122 errorCallback(response.data.error); 123 } 124 }).catch(error => { 125 errorCallback(error.code + ' : ' + error.message); 126 }); 127 } 128 129 const detectInvalidBlocks = (handleBlock) => { 130 if (Array.isArray(handleBlock) === true) return handleBlock.filter(block => block.isValid === false); 131 return handleBlock && handleBlock.isValid===false ? [handleBlock] : null; 132 } 133 134 // used for displaying notice from response data 135 const displayNotice = (data, options) => { 136 if (data && data.message) { 137 const noticeType = data.messageType || 'info'; 138 createNotice(noticeType, data.message, options) 139 } 140 } 141 142 // show notice or feedback modal dialog based on imported block valid status 143 export const afterImportHandling = (data, handledBlock) => { 144 const invalidBlocks = detectInvalidBlocks(handledBlock); 145 // get the description from the invalid blocks 146 let description = ''; 147 if (invalidBlocks && invalidBlocks.length < 1) 148 description = invalidBlocks.map(block => { 149 if (block.validationIssues && Array.isArray(block.validationIssues)) 150 return block.validationIssues.map(error => { 151 return sprintf(...error.args) 152 }).join('\n'); 153 else 154 return null; 155 }).join('\n'); 156 157 // Prepare Form schema object 158 const schema = { 159 type: 'object', 160 properties: { 161 theme_plugins: { 162 type: 'boolean', 163 title: __('Send theme and plugins', redux_templates.i18n), 164 default: true 165 }, 166 send_page_content: { 167 type: 'boolean', 168 title: __('Send page content', redux_templates.i18n), 169 default: true 170 }, 171 template_id: { 172 type: 'string', 173 default: data.hash, 174 title: __('Template ID', redux_templates.i18n) 175 }, 176 description: { 177 type: 'string', 178 default: description, 179 title: __('Description', redux_templates.i18n) 180 }, 181 182 } 183 } 184 const uiSchema = { 185 description: { 186 'ui:widget': 'textarea', 187 }, 188 template_id: { 189 'ui:disabled': true, 190 classNames: 'fixed-control' 191 } 192 }; 193 194 const feedbackData = { 195 content: handledBlock 196 }; 197 if (invalidBlocks && invalidBlocks.length > 0) { // in case there 198 createNotice('error', 'Please let us know if there was an issue importing this Redux template.', { 199 isDismissible: true, 200 id: 'redux-templatesimportfeedback', 201 actions: [ 202 { 203 onClick: () => ModalManager.openFeedback(<FeedbackDialog 204 title={__('Thank you for reporting an issue.', redux_templates.i18n)} 205 description={__('We want to make Redux perfect. Please send whatever you are comfortable sending, and we will do our best to resolve the problem.', redux_templates.i18n)} 206 schema={schema} 207 uiSchema={uiSchema} 208 data={feedbackData} 209 ignoreData={true} 210 headerImage={<img className="header-background" src={`${redux_templates.plugin}assets/img/popup-contact.png` } />} 211 buttonLabel={__('Submit Feedback', redux_templates.i18n)} 212 />), 213 label: 'Report an Issue', 214 isPrimary: true, 215 } 216 ], 217 }); 218 } 219 } 220 221 // reload library button handler 222 export const reloadLibrary = () => { 223 const { setLoading, setLibrary } = dispatch('redux-templates/sectionslist'); 224 setLoading(true); 225 apiFetch({ 226 path: 'redux/v1/templates/library?no_cache=1', 227 method: 'POST', 228 data: { 229 'registered_blocks': installedBlocksTypes(), 230 } 231 }).then((newLibrary) => { 232 setLoading(false); 233 setLibrary(newLibrary.data); 234 }).catch((error) => { 235 errorCallback(error); 236 }); 237 } 238 239 240 export const installedBlocks = () => { 241 let installed_blocks = getBlockTypes(); 242 return Object.keys(installed_blocks).map(key => { 243 return installed_blocks[key]['name']; 244 }) 245 } 246 export const installedBlocksTypes = () => { 247 let installed_blocks = getBlockTypes(); 248 249 let names = Object.keys(installed_blocks).map(key => { 250 if (!installed_blocks[key]['name'].includes('core')) { 251 return installed_blocks[key]['name'].split('/')[0]; 252 } 253 }) 254 let unique = [...new Set(names)]; 255 var filtered = unique.filter(function (el) { 256 return el; 257 }); 258 259 return filtered 260 } 261 262 export const openSitePreviewModal = (index, pageData) => { 263 ModalManager.openCustomizer( 264 <PreviewModal startIndex={index} currentPageData={pageData} /> 265 ) 266 } 267 268 const errorCallback = (errorMessage) => { 269 const { appendErrorMessage, setImportingTemplate, setActivateDialogDisplay } = dispatch('redux-templates/sectionslist'); 270 if (errorMessage === 'Please activate Redux') { 271 setActivateDialogDisplay(true); 272 redux_templates.left = 0; 273 } else { 274 appendErrorMessage(errorMessage); 275 setImportingTemplate(null); 276 } 277 }