Skip to content

Commit

Permalink
Use interactivity API for Navigation and File blocks only in Gutenberg (
Browse files Browse the repository at this point in the history
#51694)

* Add conditional to navigation block

* Add conditional to file block

* Skip `view-modal` if `should_load_script` is false

* Fix typo

* Apply conditional in `block_type_metadata` filter
  • Loading branch information
SantosGuillamot committed Jun 20, 2023
1 parent 747e155 commit f2efd8a
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 73 deletions.
2 changes: 1 addition & 1 deletion packages/block-library/src/file/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
}
}
},
"viewScript": "file:./interactivity.min.js",
"viewScript": "file:./view.min.js",
"editorStyle": "wp-block-file-editor",
"style": "wp-block-file"
}
19 changes: 18 additions & 1 deletion packages/block-library/src/file/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@
* @package WordPress
*/

if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
/**
* Replaces view script for the File block with version using Interactivity API.
*
* @param array $metadata Block metadata as read in via block.json.
*
* @return array Filtered block type metadata.
*/
function gutenberg_block_core_file_update_interactive_view_script( $metadata ) {
if ( 'core/file' === $metadata['name'] ) {
$metadata['viewScript'] = array( 'file:./interactivity.min.js' );
}
return $metadata;
}
add_filter( 'block_type_metadata', 'gutenberg_block_core_file_update_interactive_view_script', 10, 1 );
}

/**
* When the `core/file` block is rendering, check if we need to enqueue the `'wp-block-file-view` script.
*
Expand Down Expand Up @@ -54,7 +71,7 @@ static function ( $matches ) {
);

// If it uses the Interactivity API, add the directives.
if ( $should_load_view_script ) {
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN && $should_load_view_script ) {
$processor = new WP_HTML_Tag_Processor( $content );
$processor->next_tag();
$processor->set_attribute( 'data-wp-interactive', '' );
Expand Down
9 changes: 9 additions & 0 deletions packages/block-library/src/file/view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Internal dependencies
*/
import { hidePdfEmbedsOnUnsupportedBrowsers } from './utils';

document.addEventListener(
'DOMContentLoaded',
hidePdfEmbedsOnUnsupportedBrowsers
);
2 changes: 1 addition & 1 deletion packages/block-library/src/navigation/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
}
}
},
"viewScript": "file:./interactivity.min.js",
"viewScript": [ "file:./view.min.js", "file:./view-modal.min.js" ],
"editorStyle": "wp-block-navigation-editor",
"style": "wp-block-navigation"
}
155 changes: 85 additions & 70 deletions packages/block-library/src/navigation/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,84 @@ function block_core_navigation_sort_menu_items_by_parent_id( $menu_items ) {

return $menu_items_by_parent_id;
}

/**
* Add Interactivity API directives to the navigation-submenu and page-list blocks markup using the Tag Processor
* The final HTML of the navigation-submenu and the page-list blocks will look similar to this:
*
* <li
* class="has-child"
* data-wp-context='{ "core": { "navigation": { "isMenuOpen": false, "overlay": false } } }'
* data-wp-effect="effects.core.navigation.initMenu"
* data-wp-on.keydown="actions.core.navigation.handleMenuKeydown"
* data-wp-on.focusout="actions.core.navigation.handleMenuFocusout"
* >
* <button
* class="wp-block-navigation-submenu__toggle"
* data-wp-on.click="actions.core.navigation.openMenu"
* data-wp-bind.aria-expanded="context.core.navigation.isMenuOpen"
* >
* </button>
* <span>Title</span>
* <ul class="wp-block-navigation__submenu-container">
* SUBMENU ITEMS
* </ul>
* </li>
*
* @param string $w Markup of the navigation block.
* @param array $block_attributes Block attributes.
*
* @return string Submenu markup with the directives injected.
*/
function gutenberg_block_core_navigation_add_directives_to_submenu( $w, $block_attributes ) {
while ( $w->next_tag(
array(
'tag_name' => 'LI',
'class_name' => 'has-child',
)
) ) {
// Add directives to the parent `<li>`.
$w->set_attribute( 'data-wp-interactive', true );
$w->set_attribute( 'data-wp-context', '{ "core": { "navigation": { "isMenuOpen": { "click": false, "hover": false }, "overlay": false } } }' );
$w->set_attribute( 'data-wp-effect', 'effects.core.navigation.initMenu' );
$w->set_attribute( 'data-wp-on--focusout', 'actions.core.navigation.handleMenuFocusout' );
$w->set_attribute( 'data-wp-on--keydown', 'actions.core.navigation.handleMenuKeydown' );
if ( ! isset( $block_attributes['openSubmenusOnClick'] ) || false === $block_attributes['openSubmenusOnClick'] ) {
$w->set_attribute( 'data-wp-on--mouseenter', 'actions.core.navigation.openMenuOnHover' );
$w->set_attribute( 'data-wp-on--mouseleave', 'actions.core.navigation.closeMenuOnHover' );
}

// Add directives to the toggle submenu button.
if ( $w->next_tag(
array(
'tag_name' => 'BUTTON',
'class_name' => 'wp-block-navigation-submenu__toggle',
)
) ) {
$w->set_attribute( 'data-wp-on--click', 'actions.core.navigation.toggleMenuOnClick' );
$w->set_attribute( 'data-wp-bind--aria-expanded', 'selectors.core.navigation.isMenuOpen' );
};

// Iterate through subitems if exist.
gutenberg_block_core_navigation_add_directives_to_submenu( $w, $block_attributes );
}
return $w->get_updated_html();
};

/**
* Replaces view script for the Navigation block with version using Interactivity API.
*
* @param array $metadata Block metadata as read in via block.json.
*
* @return array Filtered block type metadata.
*/
function gutenberg_block_core_navigation_update_interactive_view_script( $metadata ) {
if ( 'core/navigation' === $metadata['name'] ) {
$metadata['viewScript'] = array( 'file:./interactivity.min.js' );
}
return $metadata;
}
add_filter( 'block_type_metadata', 'gutenberg_block_core_navigation_update_interactive_view_script', 10, 1 );
}


Expand Down Expand Up @@ -584,16 +662,16 @@ function render_block_core_navigation( $attributes, $content, $block ) {

// If the script is not needed, and it is still in the `view_script_handles`, remove it.
if ( ! $should_load_view_script && in_array( $view_js_file, $script_handles, true ) ) {
$block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) );
$block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file, 'wp-block-navigation-view-2' ) );
}
// If the script is needed, but it was previously removed, add it again.
if ( $should_load_view_script && ! in_array( $view_js_file, $script_handles, true ) ) {
$block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) );
$block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file, 'wp-block-navigation-view-2' ) );
}
}

// Add directives to the submenu if needed.
if ( $has_submenus && $should_load_view_script ) {
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN && $has_submenus && $should_load_view_script ) {
$w = new WP_HTML_Tag_Processor( $inner_blocks_html );
$inner_blocks_html = gutenberg_block_core_navigation_add_directives_to_submenu( $w, $attributes );
}
Expand Down Expand Up @@ -641,7 +719,7 @@ function render_block_core_navigation( $attributes, $content, $block ) {
$responsive_container_directives = '';
$responsive_dialog_directives = '';
$close_button_directives = '';
if ( $should_load_view_script ) {
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN && $should_load_view_script ) {
$nav_element_directives = '
data-wp-interactive
data-wp-context=\'{ "core": { "navigation": { "isMenuOpen": { "click": false, "hover": false }, "overlay": true, "roleAttribute": "" } } }\'
Expand Down Expand Up @@ -669,11 +747,11 @@ function render_block_core_navigation( $attributes, $content, $block ) {
}

$responsive_container_markup = sprintf(
'<button aria-haspopup="true" %3$s class="%6$s" %11$s>%9$s</button>
'<button aria-haspopup="true" %3$s class="%6$s" data-micromodal-trigger="%1$s" %11$s>%9$s</button>
<div class="%5$s" style="%7$s" id="%1$s" %12$s>
<div class="wp-block-navigation__responsive-close" tabindex="-1">
<div class="wp-block-navigation__responsive-close" tabindex="-1" data-micromodal-close>
<div class="wp-block-navigation__responsive-dialog" aria-label="%8$s" %13$s>
<button %4$s class="wp-block-navigation__responsive-container-close" %14$s>%10$s</button>
<button %4$s data-micromodal-close class="wp-block-navigation__responsive-container-close" %14$s>%10$s</button>
<div class="wp-block-navigation__responsive-container-content" id="%1$s-content">
%2$s
</div>
Expand Down Expand Up @@ -963,66 +1041,3 @@ function block_core_navigation_get_most_recently_published_navigation() {

return null;
}

/**
* Add Interactivity API directives to the navigation-submenu and page-list blocks markup using the Tag Processor
* The final HTML of the navigation-submenu and the page-list blocks will look similar to this:
*
* <li
* class="has-child"
* data-wp-context='{ "core": { "navigation": { "isMenuOpen": false, "overlay": false } } }'
* data-wp-effect="effects.core.navigation.initMenu"
* data-wp-on.keydown="actions.core.navigation.handleMenuKeydown"
* data-wp-on.focusout="actions.core.navigation.handleMenuFocusout"
* >
* <button
* class="wp-block-navigation-submenu__toggle"
* data-wp-on.click="actions.core.navigation.openMenu"
* data-wp-bind.aria-expanded="context.core.navigation.isMenuOpen"
* >
* </button>
* <span>Title</span>
* <ul class="wp-block-navigation__submenu-container">
* SUBMENU ITEMS
* </ul>
* </li>
*
* @param string $w Markup of the navigation block.
* @param array $block_attributes Block attributes.
*
* @return string Submenu markup with the directives injected.
*/
function gutenberg_block_core_navigation_add_directives_to_submenu( $w, $block_attributes ) {
while ( $w->next_tag(
array(
'tag_name' => 'LI',
'class_name' => 'has-child',
)
) ) {
// Add directives to the parent `<li>`.
$w->set_attribute( 'data-wp-interactive', true );
$w->set_attribute( 'data-wp-context', '{ "core": { "navigation": { "isMenuOpen": { "click": false, "hover": false }, "overlay": false } } }' );
$w->set_attribute( 'data-wp-effect', 'effects.core.navigation.initMenu' );
$w->set_attribute( 'data-wp-on--focusout', 'actions.core.navigation.handleMenuFocusout' );
$w->set_attribute( 'data-wp-on--keydown', 'actions.core.navigation.handleMenuKeydown' );
if ( ! isset( $block_attributes['openSubmenusOnClick'] ) || false === $block_attributes['openSubmenusOnClick'] ) {
$w->set_attribute( 'data-wp-on--mouseenter', 'actions.core.navigation.openMenuOnHover' );
$w->set_attribute( 'data-wp-on--mouseleave', 'actions.core.navigation.closeMenuOnHover' );
}

// Add directives to the toggle submenu button.
if ( $w->next_tag(
array(
'tag_name' => 'BUTTON',
'class_name' => 'wp-block-navigation-submenu__toggle',
)
) ) {
$w->set_attribute( 'data-wp-on--click', 'actions.core.navigation.toggleMenuOnClick' );
$w->set_attribute( 'data-wp-bind--aria-expanded', 'selectors.core.navigation.isMenuOpen' );
};

// Iterate through subitems if exist.
gutenberg_block_core_navigation_add_directives_to_submenu( $w, $block_attributes );
}
return $w->get_updated_html();
};
78 changes: 78 additions & 0 deletions packages/block-library/src/navigation/view-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* External dependencies
*/
import MicroModal from 'micromodal';

// Responsive navigation toggle.
function navigationToggleModal( modal ) {
const dialogContainer = modal.querySelector(
`.wp-block-navigation__responsive-dialog`
);

const isHidden = 'true' === modal.getAttribute( 'aria-hidden' );

modal.classList.toggle( 'has-modal-open', ! isHidden );
dialogContainer.toggleAttribute( 'aria-modal', ! isHidden );

if ( isHidden ) {
dialogContainer.removeAttribute( 'role' );
dialogContainer.removeAttribute( 'aria-modal' );
} else {
dialogContainer.setAttribute( 'role', 'dialog' );
dialogContainer.setAttribute( 'aria-modal', 'true' );
}

// Add a class to indicate the modal is open.
const htmlElement = document.documentElement;
htmlElement.classList.toggle( 'has-modal-open' );
}

function isLinkToAnchorOnCurrentPage( node ) {
return (
node.hash &&
node.protocol === window.location.protocol &&
node.host === window.location.host &&
node.pathname === window.location.pathname &&
node.search === window.location.search
);
}

window.addEventListener( 'load', () => {
MicroModal.init( {
onShow: navigationToggleModal,
onClose: navigationToggleModal,
openClass: 'is-menu-open',
} );

// Close modal automatically on clicking anchor links inside modal.
const navigationLinks = document.querySelectorAll(
'.wp-block-navigation-item__content'
);

navigationLinks.forEach( function ( link ) {
// Ignore non-anchor links and anchor links which open on a new tab.
if (
! isLinkToAnchorOnCurrentPage( link ) ||
link.attributes?.target === '_blank'
) {
return;
}

// Find the specific parent modal for this link
// since .close() won't work without an ID if there are
// multiple navigation menus in a post/page.
const modal = link.closest(
'.wp-block-navigation__responsive-container'
);
const modalId = modal?.getAttribute( 'id' );

link.addEventListener( 'click', () => {
// check if modal exists and is open before trying to close it
// otherwise Micromodal will toggle the `has-modal-open` class
// on the html tag which prevents scrolling
if ( modalId && modal.classList.contains( 'has-modal-open' ) ) {
MicroModal.close( modalId );
}
} );
} );
} );
Loading

0 comments on commit f2efd8a

Please sign in to comment.