first commit

This commit is contained in:
CHIEFSOFT\ameye
2023-11-30 13:20:54 -05:00
commit e9e5c0546c
5833 changed files with 1801865 additions and 0 deletions
File diff suppressed because one or more lines are too long
@@ -0,0 +1,40 @@
/**
* External dependencies
*/
const { flow } = window.lodash;
/**
* WordPress dependencies
*/
const { __ } = wp.i18n;
const { Dropdown, Button } = wp.components;
/**
* Internal dependencies
*/
import './style.scss';
import ImportForm from '../import-form';
function ImportDropdown( { onUpload } ) {
return (
<Dropdown
position="bottom right"
contentClassName="list-layout-blocks-import-dropdown__content"
renderToggle={ ( { isOpen, onToggle } ) => (
<Button
type="button"
aria-expanded={ isOpen }
onClick={ onToggle }
isPrimary
>
{ __( 'Import from JSON', 'canvas' ) }
</Button>
) }
renderContent={ ( { onClose } ) => (
<ImportForm onUpload={ flow( onClose, onUpload ) } />
) }
/>
);
}
export default ImportDropdown;
File diff suppressed because one or more lines are too long
@@ -0,0 +1,114 @@
/**
* WordPress dependencies
*/
const { Component } = wp.element;
const { withInstanceId } = wp.compose;
const { __ } = wp.i18n;
const { Button, Notice } = wp.components;
/**
* Internal dependencies
*/
import './style.scss';
import importLayoutBlock from '../../utils/import';
class ImportForm extends Component {
constructor() {
super( ...arguments );
this.state = {
isLoading: false,
error: null,
file: null,
};
this.isStillMounted = true;
this.onChangeFile = this.onChangeFile.bind( this );
this.onSubmit = this.onSubmit.bind( this );
}
componentWillUnmount() {
this.isStillMounted = false;
}
onChangeFile( event ) {
this.setState( { file: event.target.files[ 0 ] } );
}
onSubmit( event ) {
event.preventDefault();
const { file } = this.state;
const { onUpload } = this.props;
if ( ! file ) {
return;
}
this.setState( { isLoading: true } );
importLayoutBlock( file )
.then( ( layoutBlock ) => {
if ( ! this.isStillMounted ) {
return;
}
this.setState( { isLoading: false } );
onUpload( layoutBlock );
} )
.catch( ( error ) => {
if ( ! this.isStillMounted ) {
return;
}
let uiMessage;
switch ( error.message ) {
case 'Invalid JSON file':
uiMessage = __( 'Invalid JSON file', 'canvas' );
break;
case 'Invalid Layout Block JSON file':
uiMessage = __( 'Invalid Layout Block JSON file', 'canvas' );
break;
default:
uiMessage = __( 'Unknown error', 'canvas' );
}
this.setState( { isLoading: false, error: uiMessage } );
} );
}
render() {
const { instanceId } = this.props;
const { file, isLoading, error } = this.state;
const inputId = 'list-layout-blocks-import-form-' + instanceId;
return (
<form
className="list-layout-blocks-import-form"
onSubmit={ this.onSubmit }
>
{ error && (
<Notice status="error">
{ error }
</Notice>
) }
<label
htmlFor={ inputId }
className="list-layout-blocks-import-form__label"
>
{ __( 'File', 'canvas' ) }
</label>
<input
id={ inputId }
type="file"
onChange={ this.onChangeFile }
/>
<Button
type="submit"
isBusy={ isLoading }
disabled={ ! file || isLoading }
isDefault
className="list-layout-blocks-import-form__button"
>
{ __( 'Import', 'canvas' ) }
</Button>
</form>
);
}
}
export default withInstanceId( ImportForm );
File diff suppressed because one or more lines are too long
@@ -0,0 +1,63 @@
/**
* WordPress dependencies
*/
const {
jQuery: $,
} = window;
const { render } = wp.element;
const { __ } = wp.i18n;
/**
* Internal dependencies
*/
import exportLayoutBlock from './utils/export';
import ImportDropdown from './components/import-dropdown';
$( document ).on( 'DOMContentLoaded', () => {
// Setup Export Links
$( '.type-canvas_layout.status-publish > .column-title > .row-actions' ).each( function() {
const $this = $( this );
const $parent = $this.closest( '.type-canvas_layout.status-publish' );
let id = '';
if ( $parent.attr('id') ) {
id = $parent.attr('id').replace(/^post-/g, '');
}
$this.append( `
<span class="export">
|
<button type="button" class="wp-list-layout-blocks__export button-link" data-id="${ id }">${ __( 'Export as JSON', 'canvas' ) }</button>
</span>
` );
} );
$( document ).on( 'click', '.wp-list-layout-blocks__export', ( e ) => {
e.preventDefault();
exportLayoutBlock( e.target.dataset.id );
} );
// Setup Import Form
const button = document.querySelector( '.page-title-action' );
if ( ! button ) {
return;
}
const showNotice = () => {
const notice = document.createElement( 'div' );
notice.className = 'notice notice-success is-dismissible';
notice.innerHTML = `<p>${ __( 'Layout block imported successfully!', 'canvas' ) }</p>`;
const headerEnd = document.querySelector( '.wp-header-end' );
if ( ! headerEnd ) {
return;
}
headerEnd.parentNode.insertBefore( notice, headerEnd );
};
const container = document.createElement( 'div' );
container.className = 'list-layout-blocks__container';
button.parentNode.insertBefore( container, button );
render( <ImportDropdown onUpload={ showNotice } />, container );
} );
@@ -0,0 +1,40 @@
/**
* External dependencies
*/
const {
kebabCase,
} = window.lodash;
/**
* WordPress dependencies
*/
const {
apiFetch,
} = wp;
/**
* Internal dependencies
*/
import { download } from './file';
/**
* Export a layout block as a JSON file.
*
* @param {number} id
*/
async function exportLayoutBlock( id ) {
const postType = await apiFetch( { path: `/wp/v2/types/canvas_layout` } );
const post = await apiFetch( { path: `/wp/v2/${ postType.rest_base }/${ id }?context=edit` } );
const title = post.title.raw;
const content = post.content.raw;
const fileContent = JSON.stringify( {
__file: 'canvas_layout',
title,
content,
}, null, 2 );
const fileName = kebabCase( title ) + '.json';
download( fileName, fileContent, 'application/json' );
}
export default exportLayoutBlock;
@@ -0,0 +1,41 @@
/**
* Downloads a file.
*
* @param {string} fileName File Name.
* @param {string} content File Content.
* @param {string} contentType File mime type.
*/
export function download( fileName, content, contentType ) {
const file = new window.Blob( [ content ], { type: contentType } );
// IE11 can't use the click to download technique
// we use a specific IE11 technique instead.
if ( window.navigator.msSaveOrOpenBlob ) {
window.navigator.msSaveOrOpenBlob( file, fileName );
} else {
const a = document.createElement( 'a' );
a.href = URL.createObjectURL( file );
a.download = fileName;
a.style.display = 'none';
document.body.appendChild( a );
a.click();
document.body.removeChild( a );
}
}
/**
* Reads the textual content of the given file.
*
* @param {File} file File.
* @return {Promise<string>} Content of the file.
*/
export function readTextFile( file ) {
const reader = new window.FileReader();
return new Promise( ( resolve ) => {
reader.onload = function() {
resolve( reader.result );
};
reader.readAsText( file );
} );
}
@@ -0,0 +1,57 @@
/**
* External dependencies
*/
const {
isString,
} = window.lodash;
/**
* WordPress dependencies
*/
const {
apiFetch,
} = wp;
/**
* Internal dependencies
*/
import { readTextFile } from './file';
/**
* Import a layout block from a JSON file.
*
* @param {File} file File.
* @return {Promise} Promise returning the imported layout block.
*/
async function importLayoutBlock( file ) {
const fileContent = await readTextFile( file );
let parsedContent;
try {
parsedContent = JSON.parse( fileContent );
} catch ( e ) {
throw new Error( 'Invalid JSON file' );
}
if (
parsedContent.__file !== 'canvas_layout' ||
! parsedContent.title ||
! parsedContent.content ||
! isString( parsedContent.title ) ||
! isString( parsedContent.content )
) {
throw new Error( 'Invalid Canvas Layout JSON file' );
}
const postType = await apiFetch( { path: `/wp/v2/types/canvas_layout` } );
const layoutBlock = await apiFetch( {
path: `/wp/v2/${ postType.rest_base }`,
data: {
title: parsedContent.title,
content: parsedContent.content,
status: 'publish',
},
method: 'POST',
} );
return layoutBlock;
}
export default importLayoutBlock;
File diff suppressed because one or more lines are too long
@@ -0,0 +1,233 @@
/**
* Internal dependencies
*/
import './style.scss';
/**
* WordPress dependencies
*/
const {
jQuery: $,
canvasLayouts,
} = window;
const {
__,
} = wp.i18n;
const {
registerBlockType,
createBlock,
parse,
} = wp.blocks;
const {
Component,
} = wp.element;
const {
Modal,
SelectControl,
} = wp.components;
const {
compose,
} = wp.compose;
const {
withDispatch,
} = wp.data;
/**
* Add layouts button to Gutenberg toolbar
*/
$(document).on('DOMContentLoaded', () => {
wp.data.subscribe(function () {
setTimeout(function () {
if (!document.getElementById('canvas-toolbar-import-layout')) {
const $toolbar = $('.edit-post-header-toolbar');
if (Object.keys(canvasLayouts.layouts).length && $toolbar.length) {
$toolbar.append(`
<div>
<div id="canvas-toolbar-import-layout" class="canvas-toolbar-import-layout">
<button class="components-button components-icon-button" aria-label="${__('Import Layout', 'canvas')}">
<svg aria-hidden="true" role="img" focusable="false" class="dashicon dashicons-insert" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><path d="M10 1c-5 0-9 4-9 9s4 9 9 9 9-4 9-9-4-9-9-9zm0 16c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.1 7-7 7zm1-11H9v3H6v2h3v3h2v-3h3V9h-3V6z"></path></svg>
${__('Import Layout', 'canvas')}
</button>
</div>
</div>
` );
}
}
}, 1)
});
// Insert `canvas/layout` block.
$(document).on('click', '.canvas-toolbar-import-layout button', (e) => {
e.preventDefault();
const {
insertBlocks,
} = wp.data.dispatch('core/block-editor');
insertBlocks(createBlock('canvas/layouts'));
});
});
/**
* Component
*/
class LayoutsBlockEdit extends Component {
constructor() {
super(...arguments);
this.state = {
category: '',
};
this.getLayouts = this.getLayouts.bind(this);
}
getLayouts() {
const {
category,
} = this.state;
const result = {};
Object.keys(canvasLayouts.layouts).forEach((k) => {
const layout = canvasLayouts.layouts[k];
if (category) {
if (layout.category && layout.category.indexOf(category) > -1) {
result[k] = layout;
}
} else {
result[k] = layout;
}
})
return result;
}
render() {
const {
insertLayout,
closeModal,
} = this.props;
const categories = [
{
label: __('--- Select Category ---', 'canvas'),
value: '',
},
...Object.keys(canvasLayouts.categories).map((name) => {
return {
label: canvasLayouts.categories[name],
value: name,
};
}),
];
const layouts = this.getLayouts();
return (
<Modal
position="top"
title={__('Layouts', 'canvas')}
onRequestClose={() => {
closeModal();
}}
shouldCloseOnClickOutside={false}
className="cnvs-extension-layouts-modal"
>
<div className="cnvs-extension-layouts-content">
{categories.length > 1 ? (
<div className="cnvs-extension-layouts-categories">
<SelectControl
options={categories}
onChange={(val) => {
this.setState({
category: val,
});
}}
/>
</div>
) : ''}
{Object.keys(layouts).length ? (
<div className="cnvs-extension-layouts-count">
{ __('Layouts:', 'canvas')}
&nbsp;
<strong>{Object.keys(layouts).length}</strong>
</div>
) : ''}
{Object.keys(layouts).length ? (
<div className="cnvs-extension-layouts-list">
{ Object.keys(layouts).map((k) => {
return (
<button
key={k}
onClick={() => {
insertLayout(layouts[k].content);
closeModal();
}}
>
{ layouts[k].thumbnail ? (
<img src={layouts[k].thumbnail} />
) : ''}
<label>{layouts[k].title}</label>
</button>
);
})}
</div>
) : (
<p>{__('No layouts found.', 'canvas')}</p>
)}
</div>
</Modal>
);
}
}
const LayoutsBlockEditWithSelect = compose(
withDispatch((dispatch, ownProps) => {
const { clientId } = ownProps;
const {
replaceBlocks,
removeBlock,
} = dispatch('core/block-editor');
return {
closeModal() {
removeBlock(clientId);
},
insertLayout(content) {
const parsedBlocks = parse(content);
replaceBlocks(clientId, parsedBlocks);
},
};
}),
)(LayoutsBlockEdit);
/**
* Register block.
*/
registerBlockType('canvas/layouts', {
title: __('Canvas Layouts', 'canvas'),
description: __('Add a pre-configured layouts.', 'canvas'),
category: 'common',
supports: {
customClassName: false,
html: false,
inserter: false,
multiple: false,
reusable: false,
},
edit: LayoutsBlockEditWithSelect,
save: function () {
return null
}
});