/** * BLOCK: algori-image-video-slider * * Algori Image and Video Slider is a Gutenberg Block Plugin that enables you easily add image and video sliders to your website. */ /** * External dependencies */ import { filter, pick } from 'lodash'; import Slider from 'react-slick'; import classnames from 'classnames'; /** * WordPress dependencies */ const { IconButton, PanelBody, TextControl, Toolbar, Tooltip, ToggleControl, RadioControl, Button, Popover, RangeControl, Spinner, withNotices } = wp.components; // import { IconButton, PanelBody, RangeControl, ToggleControl, Toolbar, withNotices } from '@wordpress/components'; const { Fragment, createRef } = wp.element; // import { Fragment } from '@wordpress/element'; const { __ } = wp.i18n; // Import __() from wp.i18n const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks const { BlockControls, InspectorControls, BlockAlignmentToolbar, MediaPlaceholder, MediaUpload, MediaUploadCheck, AlignmentToolbar, RichText, URLInput, } = wp.editor; // Import * from @wordpress/editor const { isBlobURL } = wp.blob; /** * Internal dependencies * * Import CSS. */ import './style.scss'; import './editor.scss'; /** * Module Constants */ const ALLOWED_MEDIA_TYPES = [ 'video', 'image' ]; const blockAttributes = { title: { type: 'array', source: 'children', selector: 'p', }, url: { type: 'string', }, contentAlign: { type: 'string', default: 'center', }, id: { type: 'number', }, sliderImagesVideos: { type: 'array', default: [], }, settings: { type: 'object', default: { dots: true, arrows: true, autoplay: false, pauseOnFocus: false, rtl: false, vertical: false, fade: false, lazyLoad: false, centerMode: false, infinite: true, adaptiveHeight: true, speed: 500, autoplaySpeed: 3000, slidesToShow: 1, slidesToScroll: 1, rows: 1, slidesPerRow: 1 }, }, selectedDotsClass: { type: 'string', default: 'dots-style-1-off-slide', }, selectedArrowsClass: { type: 'string', default: 'arrows-style-1-off-slide', }, dotsOnTopOfSlide: { type: 'boolean', default: false, }, arrowsOnTopOfSlide: { type: 'boolean', default: false, }, textBlockVisible: { type: 'boolean', default: false, }, ctaButtonVisible: { type: 'boolean', default: true, }, dimRatio: { type: 'number', default: 0, }, content: { type: 'array', source: 'children', selector: 'h2', }, textBlockContent: { type: 'object', default: {} }, currentSlide: { type: 'number', default: 0, }, videoSettings: { type: 'object', default: { preload: true, controls: true, autoplay: true, muted: true, loop: true, } }, }; /** * Register: aa Gutenberg Block. * * Registers a new block provided a unique name and an object defining its * behavior. Once registered, the block is made editor as an option to any * editor interface where blocks are implemented. * * @link https://wordpress.org/gutenberg/handbook/block-api/ * @param {string} name Block name. * @param {Object} settings Block settings. * @return {?WPBlock} The block, if it has been successfully * registered; otherwise `undefined`. */ registerBlockType( 'cgb/block-algori-image-video-slider', { // Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block. title: __( 'Image & Video Slider' ), // Block title. description: __( 'Capture your site visitors\' attention with compelling image and video slideshows. Add an image/video slider.' ), // Block description that appears in the block inspector. Make it short preferably. icon: , // Block icon from Material Design Icons → https://material.io/tools/icons/ category: 'common', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed. keywords: [ // Block search keywords __( 'algori carousel slideshows' ), __( 'photo gallery' ), __( 'photos images videos' ), ], attributes: blockAttributes, // Block attributes for editing in the block inspector. /** * The edit function describes the structure of your block in the context of the editor. * This represents what the editor will render when the block is used. * * The "edit" property must be a valid function. * * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ */ edit: withNotices( ( { attributes, setAttributes, isSelected, className, noticeOperations, noticeUI } ) => { const { url, title, align, contentAlign, id, sliderImagesVideos, sliderDots, settings, selectedDotsClass, selectedArrowsClass, dotsOnTopOfSlide, arrowsOnTopOfSlide, textBlockVisible, ctaButtonVisible, dimRatio, content, textBlockContent, currentSlide, videoSettings } = attributes; const updateSliderDots = ( sliderDots ) => setAttributes( { settings: { ...settings, dots: sliderDots } } ); const updateSliderArrows = ( sliderArrows ) => setAttributes( { settings: { ...settings, arrows: sliderArrows } } ); const updateSliderAutoplay = ( sliderAutoplay ) => setAttributes( { settings: { ...settings, autoplay: sliderAutoplay } } ); const updateCurrentSlide = ( currentSlide ) => { setAttributes( { currentSlide: currentSlide } ); } const initialTextBlockContent = ( numOfImages ) => { for( let i=0; i < numOfImages; i++ ){ textBlockContent[`text-block-sub-heading-${i}`] = __('Sub Heading Goes Here...'); textBlockContent[`text-block-paragraph-${i}`] = __('Pargraph Text goes here...'); textBlockContent[`text-block-cta-text-${i}`] = __('Add Call To Action'); textBlockContent[`text-block-cta-link-${i}`] = 'http://www.example.com'; } return textBlockContent; } const onSelectImagesVideos = ( imagesVideos ) => { setAttributes( { sliderImagesVideos: imagesVideos.map( ( imageVideo ) => pick( imageVideo, [ 'alt', 'caption', 'id', 'link', 'url', 'type', 'media_type', 'mime', 'mime_type' ] ) ), textBlockContent: initialTextBlockContent( imagesVideos.length ), } ); } const classesForSlider = classnames( selectedDotsClass, selectedArrowsClass, ); const classesForTextBlockInSlider = classnames( "algori-image-video-slider-slide-text-block", dimRatioToClass( dimRatio ) ); const controls = ( // Set Block and Inspector Controls imgOrVid.id ) } render={ ( { open } ) => ( ) } /> { !! sliderImagesVideos.length && ( ) } ); if ( sliderImagesVideos.length === 0 ) { // Upload image if it doesn't exist return ( { controls } } className={ className } labels={ { title: __('\u00A0Image Slider' ), instructions: __( 'Drag images or videos, upload new ones or select files from your library.' ), } } onSelect={ onSelectImagesVideos } accept="video/*, image/*" allowedTypes={ ALLOWED_MEDIA_TYPES } multiple notices={ noticeUI } onError={ noticeOperations.createErrorNotice } /> ); } return ( // Return image & video slider with element settings (css classes) and block controls. Get image using either { url } or { id } { controls }
{ sliderImagesVideos.map( ( imgOrVid, index ) => (
{ isBlobURL( imgOrVid.url ) && }
{ ( imgOrVid.type === 'image' || imgOrVid.media_type === 'image' ) && // for image slides where media library type: "image" or formfileupload media_type: "image" { } { ( imgOrVid.type === 'video' || imgOrVid.media_type === 'file' ) && // for video slides where type: "video" or formfileupload media_type: "file". PS: it's "file" because we are trusting allowedTypes. } { !!textBlockVisible &&
setAttributes( { textBlockContent: { ...textBlockContent, [`text-block-sub-heading-${index}`] : subHeadingContent } } ) } inlineToolbar /> setAttributes( { textBlockContent: { ...textBlockContent, [`text-block-paragraph-${index}`] : paragraphContent } } ) } inlineToolbar /> { ctaButtonVisible && { ( currentSlide === index ) && // Confirm current slide then show CTA editor popover { event.stopPropagation() } } onKeyPress={ (event)=>{ event.stopPropagation() } } > setAttributes( { textBlockContent: { ...textBlockContent, [`text-block-cta-text-${index}`] : valueOfCTAText } } ) } /> setAttributes( { textBlockContent: { ...textBlockContent, [`text-block-cta-link-${index}`] : valueOfCTALink } } ) } /> } }
}
) ) }

); } ), /** * The save function defines the way in which the different attributes should be combined * into the final markup, which is then serialized by Gutenberg into post_content. * * The "save" property must be specified and must be a valid function. * * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ */ save: ( { attributes, className } ) => { const { url, title, align, contentAlign, id, sliderImagesVideos, settings, selectedDotsClass, selectedArrowsClass, textBlockVisible, ctaButtonVisible, dimRatio, content, textBlockContent, videoSettings } = attributes; const classesForSlider = classnames( selectedDotsClass, selectedArrowsClass, ); const classesForTextBlockInSlider = classnames( "algori-image-video-slider-slide-text-block", dimRatioToClass( dimRatio ) ); return (
{ sliderImagesVideos.map( ( imgOrVid, index ) => (
{ ( imgOrVid.type === 'image' || imgOrVid.media_type === 'image' ) && // for image slides where media library type: "image" or formfileupload media_type: "image" { } { ( imgOrVid.type === 'video' || imgOrVid.media_type === 'file' ) && // for video slides where type: "video" or formfileupload media_type: "file". PS: it's "file" because we are trusting allowedTypes. } { !!textBlockVisible &&
{ ctaButtonVisible && { textBlockContent[`text-block-cta-text-${index}`] } }
}
) ) }
); }, /** * Array of deprecated forms of this block. * * @link https://wordpress.org/gutenberg/handbook/block-api/deprecated-blocks/ */ deprecated: [ { save: ( { attributes, className } ) => { const { url, title, align, contentAlign, id, sliderImagesVideos, settings, selectedDotsClass, selectedArrowsClass, textBlockVisible, ctaButtonVisible, dimRatio, content, textBlockContent, videoSettings } = attributes; const classesForSlider = classnames( selectedDotsClass, selectedArrowsClass, ); const classesForTextBlockInSlider = classnames( "algori-image-video-slider-slide-text-block", dimRatioToClass( dimRatio ) ); return (
{ sliderImagesVideos.map( ( imgOrVid, index ) => (
{ ( imgOrVid.type === 'image' || imgOrVid.media_type === 'image' ) && // for image slides where media library type: "image" or formfileupload media_type: "image" { } { ( imgOrVid.type === 'video' || imgOrVid.media_type === 'file' ) && // for video slides where type: "video" or formfileupload media_type: "file". PS: it's "file" because we are trusting allowedTypes. } { !!textBlockVisible &&
{ ctaButtonVisible && { textBlockContent[`text-block-cta-text-${index}`] } }
}
) ) }
); }, }, { attributes: { ...blockAttributes, }, save: ( { attributes, className } ) => { const { url, title, align, contentAlign, id, sliderImagesVideos, settings, selectedDotsClass, selectedArrowsClass, textBlockVisible, ctaButtonVisible, dimRatio, content, textBlockContent, videoSettings } = attributes; const classesForSlider = classnames( selectedDotsClass, selectedArrowsClass, ); const classesForTextBlockInSlider = classnames( "algori-image-video-slider-slide-text-block", dimRatioToClass( dimRatio ) ); return (
{ sliderImagesVideos.map( ( imgOrVid, index ) => (
{ ( imgOrVid.type === 'image' ) && // for image slides where type: "image" { } { ( imgOrVid.type === 'video' ) && // for video slides where type: "video" } { !!textBlockVisible &&
{ ctaButtonVisible && { textBlockContent[`text-block-cta-text-${index}`] } }
}
) ) }
); }, } ], } ); function dimRatioToClass( ratio ) { return ( ratio === 0 ) ? null : 'algori-image-video-slider-slide-text-block-background-dim-' + ( 10 * Math.round( ratio / 10 ) ); }