Untitled

mail@pastecode.io avatar
unknown
plain_text
5 months ago
18 kB
2
Indexable
In below code we have a line 	if ( empty( $groupTitles ) ) here we are checking if we have empty group title then performance-data__actions will work else dropdown-container will work so we have javascript code that take performance-data__actions and performance-data__select in javascript so make same changes for dropdown conatiner that takes values from dropdown-group and dropdown-option in javascript so that dropdown condition works smootly.

<?php
/**
 * Server-side rendering of the Performance Data Gutenberg Block
 *
 * @package blackstone-main/gutenberg
 */

namespace BlackstoneCore\Gutenberg\Blocks;

use function BlackstoneCore\Utility\setup_multiple_gtm_attributes;

/**
 * Performance Data Block Attributes
 *
 * @return array Array of block attributes
 */
function performance_data_atts() {
	return [
		'title'        => [
			'type'    => 'string',
			'default' => '',
		],
		'heading'      => [
			'type'    => 'string',
			'default' => 'h2',
		],
		'margintop'    => [
			'type'    => 'string',
			'default' => '',
		],
		'marginbottom' => [
			'type'    => 'string',
			'default' => '',
		],
		'bringToFront' => [
			'type'    => 'boolean',
			'default' => false,
		],
		'sticky'       => [
			'type'    => 'boolean',
			'default' => false,
		],
		'enableGrp'       => [
			'type'    => 'boolean',
			'default' => false,
		],
	];
}

/**
 * Performance Data Item Block Attributes
 *
 * @return array Array of block attributes
 */
function performance_data_item_atts() {
	return [
		'title'  => [
			'type'    => 'string',
			'default' => '',
		],
		'groupTitle'  => [
			'type'    => 'string',
			'default' => '',
		],
		'states' => [
			'type'    => 'array',
			'default' => [],
		],
	];
}

/**
 * Render the Tabs block HTML
 *
 * @param array  $attributes Array of Block Attributes registered via Gutenberg
 * @param string $content    InnerBlock content
 * @return string            Block HTML markup for frontend
 */
function performance_data_html( $attributes, $content ) {

	$title   = $attributes['title'] ? $attributes['title'] : '';
	$groupTitle   = $attributes['groupTitle'] ? $attributes['groupTitle'] : '';
	$heading = $attributes['heading'] ? $attributes['heading'] : 'h2';
	$mt      = $attributes['margintop'] ? ' mt-' . $attributes['margintop'] : '';
	$mb      = $attributes['marginbottom'] ? ' mb-' . $attributes['marginbottom'] : '';

	$markup = sprintf(
		'<div class="performance-data%1$s%2$s" data-initially-hidden="false">',
		esc_attr( $mt ),
		esc_attr( $mb )
	);

	$markup .= '<div class="performance-data__inner">';
	$className = 'performance-data__toolbar ';
	
	if ( !empty( $attributes['sticky'] ) && $attributes['sticky'] === true ) {
		$className .= 'is-sticky ';
	}

	if ( !empty( $attributes['enableGrp'] ) && $attributes['enableGrp'] === true ) {
		$className .= 'performancedata-toolbar-gt';
	}
	$markup .= '<div class="'.$className.'">';

	if ( $title ) {
		$markup .= '<' . tag_escape( $heading ) . ' class="performance-data__toolbar-title mt-zero mb-zero">';
		$markup .= esc_html( $title );
		$markup .= '</' . tag_escape( $heading ) . '>';
	}

	$markup .= '<!-- Tabs Placeholder -->';
	$markup .= '</div>';

	$markup .= '<div class="performance-data__content">';
	/*
		* the content is the html generated from innerBlocks
		* it is being created from the save method in JS or the render_callback
		* in php and is sanitized.
		*
		* Re sanitizing it through `wp_kses_post` causes
		* embed blocks to break and other core filters don't apply.
		* therefore no additional sanitization is done and it is being output as is
		*/
	$markup .= $content;
	$markup .= '</div>';
	$markup .= '</div>';
	$markup .= '</div>';

	return $markup;
}

/**
 * Render the Tabs Item block HTML
 *
 * @param array  $attributes Array of Block Attributes registered via Gutenberg
 * @param string $content    InnerBlock content
 * @return string            Block HTML markup for frontend
 */
function performance_data_item_html( $attributes, $content ) {
	$tab_title = ! empty( $attributes['title'] ) ? $attributes['title'] : '';

	$markup = '<div class="performance-data__item performance-data-' . sanitize_title_with_dashes( $tab_title ) . '" role="tabpanel" aria-selected="false">';

	if ( $content ) {
		/*
		* the content is the html generated from innerBlocks
		* it is being created from the save method in JS or the render_callback
		* in php and is sanitized.
		*
		* Re sanitizing it through `wp_kses_post` causes
		* embed blocks to break and other core filters don't apply.
		* therefore no additional sanitization is done and it is being output as is
		*/
		$markup .= $content;
	}

	$markup .= '</div>';

	return $markup;
}

/**
 * Add select html tags and custom div attribute being used on the block to fix reusable content issue
 *
 * @param array  $tags Allowed tags, attributes, and/or entities.
 * @param string $context Context to judge allowed tags by. Allowed values are 'post'.
 */
add_filter(
	'wp_kses_allowed_html',
	function( $tags, $context ) {

		if ( 'post' === $context ) {
			$tags['select'] = array(
				'name'  => true,
				'class' => true,
			);
			$tags['option'] = array(
				'value'             => true,
				'data-gtm-category' => true,
				'data-gtm-label'    => true,
				'data-gtm-action'   => true,
			);
			$tags['div']    = isset( $tags['div'] ) ? $tags['div'] : [];
			$tags['div']    = array_merge(
				$tags['div'],
				[
					'role'          => true,
					'aria-selected' => true,
					'aria'          => true,
				]
			);
		}

		return $tags;
	},
	10,
	2
);

/**
 * Modify block rendering to add tab navigations
 *
 * @param string|null $pre_render   The pre-rendered content. Default null.
 * @param array       $parsed_block The block being rendered.
 */
add_filter(
	'render_block',
	function( $block_content, $block ) {
		if ( 'blackstone/performance-data' === $block['blockName'] ) {
			if ( $block['innerBlocks'] ) {

				$groupTitles = array(); 
				foreach( $block['innerBlocks'] as $inner_block ) {
					$groupTitle = $inner_block['attrs']['groupTitle'];
					if ( ! empty( $groupTitle ) && ! in_array( $groupTitle, $groupTitles, true ) ) {
						$groupTitles[] = $groupTitle;
					}
				}

				if ( empty( $groupTitles ) ) {
					$tabs  = '<div class="performance-data__action">';
					$tabs .= '<div class="custom-select">';
					$tabs .= '<select name="performance-class" class="performance-data__select">';
	
					$has_default_states = ! empty(
						array_filter(
							array_map(
								function( $inner_block ) {
									return ! empty( $inner_block['attrs']['states'] );
								},
								$block['innerBlocks']
							)
						)
					);
	
					if ( is_array( $block['innerBlocks'] ) ) {
						foreach ( $block['innerBlocks'] as $inner_block ) {
	
							$title    = $inner_block['attrs']['title'];
							$states   = ! empty( $inner_block['attrs']['states'] ) ? $inner_block['attrs']['states'] : [];
							$id       = sanitize_title_with_dashes( $title );
							$gtm_atts = setup_multiple_gtm_attributes(array("category"=>"Page Engagement", "action"=>"Filter Click", "label"=>'Performance Filter | ' . esc_attr( $title ), "component_type"=>"Chart tabs", "click_text"=>esc_attr( $title ), "tag_name"=>"Page Engagement Click"), false);
							$tabs    .= '<option ' . $gtm_atts . ' value="' . esc_attr( $id ) . '" data-default-in-states="' . esc_attr( implode( ' ', $states ) ) . '">' . esc_html( $title ) . '</option>';
						}
					}
	
					$tabs .= '</select>';
					$tabs .= '</div>';
					$tabs .= '</div>';
				} else {

					$shareClass = __( 'Share Class', 'blackstone' );

					$tabs = '<div class="dropdown-container">';
						$tabs .= '<div class="dropdown-header" onclick="toggleDropdown()">';
							$tabs .= '<div class="share">'. $shareClass .'</div>';
							$tabs .= '<div class="dropdown-button">Select an option</div>';
						$tabs .= '</div>';

						$has_default_states = ! empty(
							array_filter(	
								array_map(
									function( $inner_block ) {
										return ! empty( $inner_block['attrs']['states'] );
									},
									$block['innerBlocks']
								)
							)
						);

						if ( is_array( $block['innerBlocks'] ) ) {
							$groupsPerforamcenBars = array();

							foreach( $block['innerBlocks'] as $inner_block ) {
								$groupTitle = trim( $inner_block['attrs']['groupTitle'] );
								if ( ! isset( $groupsPerforamcenBars[ $groupTitle ] ) ) {
									$groupsPerforamcenBars[ $groupTitle ] = array();
								}

								$groupsPerforamcenBars[ $groupTitle ][] = $inner_block;
							}

							$tabs .= '<div class="dropdown-options" id="dropdown-options">';

									foreach ( $groupsPerforamcenBars as $groupTitle => $group_tabs ) {
										$tabs .= '<div class="dropdown-group">';
											$tabs .= '<div class="dropdown-group-title">'. $groupTitle .'</div>';
											foreach ( $group_tabs as $inner_block ) {
												$title    = $inner_block['attrs']['title'];
												$states   = ! empty( $inner_block['attrs']['states'] ) ? $inner_block['attrs']['states'] : [];
												$id       = sanitize_title_with_dashes( $title );
												$groupTitles = $inner_block['attrs']['groupTitle'] ? explode("\n", $inner_block['attrs']['groupTitle']) : [];
												$gtm_atts = setup_multiple_gtm_attributes(array("category"=>"Page Engagement", "action"=>"Filter Click", "label"=>'Performance Filter | ' . esc_attr( $title ), "component_type"=>"Chart tabs", "click_text"=>esc_attr( $title ), "tag_name"=>"Page Engagement Click"), false);
												$tabs .= '<div class="dropdown-option" onclick="selectOption(\'' . esc_js( $title ) . '\')" ' . $gtm_atts . ' value="' . esc_attr( $id ) . '" data-default-in-states="' . esc_attr( implode( ' ', $states ) ) . '">' . esc_html( $title ) . '</div>';
											}
										$tabs .= '</div>';
									}
							$tabs .= '</div>';
						}
					$tabs .= '</div>';


					$tabs .='<script>
							document.addEventListener("DOMContentLoaded", function() {
								// Set the initial value of the dropdown button to the first option
								var firstOption = document.querySelector(".dropdown-option");
								var dropdownButton = document.querySelector(".dropdown-button");
								if (firstOption) {
									dropdownButton.innerText = firstOption.innerText;
								}
							});
							
							function toggleDropdown() {
								var dropdownOptions = document.getElementById("dropdown-options");
								var dropdownContainer = document.querySelector(".dropdown-container");
								
								dropdownOptions.classList.toggle("show");
								dropdownContainer.classList.toggle("selected");
							}

							function selectOption(value) {
								document.querySelector(".dropdown-button").innerText = value;
								document.getElementById("dropdown-options").classList.remove("show");
								document.querySelector(".dropdown-container").classList.remove("selected");
							}

							// Close the dropdown if the user clicks outside of it
							window.onclick = function(event) {
								var dropdownContainer = document.querySelector(".dropdown-container");
								var dropdownOptions = document.getElementById("dropdown-options");

								if (!event.target.closest(".dropdown-container")) {
									if (dropdownOptions.classList.contains("show")) {
										dropdownOptions.classList.remove("show");
										dropdownContainer.classList.remove("selected");
									}
								}
							}
						</script>';

				}

				// Add custom select.
				$block_content = str_replace( '<!-- Tabs Placeholder -->', $tabs, $block_content );

				$block_content = str_replace( 'data-component="chart-tabs-tab-item-link"', 'data-component="chart-tabs-tab-item-link" data-disable-ga-auto-tracking="true"', $block_content );

				if ( $has_default_states ) {
					$block_content = str_replace( 'data-initially-hidden="false"', 'data-initially-hidden="true"', $block_content );
				}

				// Make first item visible.
				$block_content = preg_replace( '/role=\"tabpanel\" aria-selected=\"false\"/', 'role="tabpanel" aria-selected="true"', $block_content, 1 );
			}
		}

		return $block_content;
	},
	10,
	2
);

/**
 * Add body class whenever Performance data block is available on the page
 */
add_filter(
	'body_class',
	function( $classes ) {

		if ( has_block( 'blackstone/performance-data' ) ) {
			$classes[] = 'has-performance-data-block';
		}

		return $classes;
	}
);


In below javascript code add functionality of dropdwon-container to work smootly as we have performance-data__select make sake for dropdown-option and dropdown-group

import { assignEventAction } from '../utils/analytics';
import { getSelectedStateFromLocalStorage } from '../utils/local-storage';

/**
 * Tabs
 */
export default class BlackstonePerformanceData {
	/**
	 * Component Constructor.
	 */
	constructor() {
		this.blocks = Array.from( document.querySelectorAll( '.performance-data' ) );
		this.selectedState = getSelectedStateFromLocalStorage();
		
		// Bail if tabs block is not on page
		if ( ! this.blocks.length ) {
			return;
		}

		this.blocks.forEach( block => this.initBlock( block ) );
	}

	/**
	 * Initialize the block.
	 */
	initBlock( block ) {
		const select = block.querySelector( '.performance-data__select' );
		const options  = Array.from( select.querySelectorAll( 'option' ) );
		const windowhashdata = window.location.hash ? window.location.hash : ''; // phpcs:ignore

		select.addEventListener( 'change', ( e ) => this.selectTab( e, block ) );

		document.addEventListener( 'setGatingState', () => {
			this.selectedState = getSelectedStateFromLocalStorage();
			this.updateTabs( select, options, windowhashdata );
			

		} );

		this.updateTabs( select, options );
		this.selectTabOnload( block, windowhashdata );

		block.dataset.initiallyHidden = false;
		
		if ( block.querySelector( '.is-sticky' ) ) {
			this.positionSelectDropdown( block );
		}
	}

	/**
	 * Update the tabs (for state change);
	 */
	updateTabs( select, options, windowhashdata ) {
		let defaultOption = null;

		if ( this.selectedState ) {
			const defaultOptions = options.filter( option => {
				const defaultInStates = option.dataset.defaultInStates?.split( ' ' );
				return defaultInStates.includes( this.selectedState );
			} ); 
			
			if ( defaultOptions.length && ! windowhashdata ) {
				[defaultOption] = defaultOptions;

				select.value = defaultOption.value;
				const changeEvent = new Event( 'change' );
				select.dispatchEvent( changeEvent );
			}
		}
	}

	/**
	 * Select Tab Logic.
	 */
	selectTab( e, block ) {
		const selected = e.target.options[ e.target.selectedIndex ].value;
		const target = block.querySelector( `.performance-data-${ selected }` );
		const items = Array.from( block.querySelectorAll( '.performance-data__item' ) );

		// Unselect selected items.
		items.forEach( item => item.setAttribute( 'aria-selected', false ) );

		// Select target one.
		if ( target ) {
			target.setAttribute( 'aria-selected', true );

			// Remove focus to prevent ipad issue with chart selection.
			e.target.blur();
		}

		/**
		 * Reset the first performance item chart tab to first.
		 * 10up/component-tabs does not provide an api for targetting each instance,
		 * therefore all tabs are updated on the page. `e.isTrusted` ensures it is
		 * an user action and not occuring as a result of `updateTabs` region updates,
		 * which causes onload issues.
		 */
		if ( e.isTrusted ) {
			const firstChartTab = target.querySelector( '.tab-item a[role=tab]' );
			if ( firstChartTab ) {
				firstChartTab.click();
			}
		}

		// Send GTM data
		assignEventAction( e );
	}

	/**
	* Scroll to selected class when hash is present .
	*/
	selectTabOnload(  block, windowhashdata ) {
		if ( windowhashdata ) {
			if ( window.history.scrollRestoration ) {
				window.history.scrollRestoration = 'manual';
			}
			const selecteddata  = windowhashdata.replace( '#', '' ).toLowerCase();
			const targetdata    = block.querySelector( `.performance-data-${ selecteddata }` );
			const itemsdata     = Array.from( block.querySelectorAll( '.performance-data__item' ) );
			const elem          = document.querySelector( '.performance-data' );
			
			const isAnchorAvailable = [...document.querySelector( '.performance-data__select' ).options]
				.filter( x => x.value === selecteddata )[0];
			if ( isAnchorAvailable ) {
				isAnchorAvailable.setAttribute( 'selected', true );
				//Unselect selected itemsdata.
				itemsdata.forEach( item => item.setAttribute( 'aria-selected', false ) );

				// Select target one.
				if ( targetdata ) {
					targetdata.setAttribute( 'aria-selected', true );
				
				}
				if ( elem ) {
					const yOffset = -100; 
					const y = elem.getBoundingClientRect().top + window.pageYOffset + yOffset;
					window.scrollTo( {top: y, behavior: 'smooth'} );
					
				}

			}
		}	
	}
	
	/**
	 * Just triggers a null change event on select dropdown when the page is scrolled without any change in class selector.
	 * 
	 * @return void
	 */
	positionSelectDropdown( block ){
		const selectElement = block.querySelector( '.performance-data__select' );

		document.addEventListener( 'scroll', () => {
			const isFocused = ( document.activeElement === selectElement );
			if ( isFocused ) {
				selectElement.dispatchEvent( new Event( 'change' ) );
			}
		} );
 	}
}
Leave a Comment