Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding the initial Tooltip #5676

Open
wants to merge 16 commits into
base: trunk
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ module.exports = function(grunt) {
[ WORKING_DIR + 'wp-includes/js/wp-ajax-response.js' ]: [ './src/js/_enqueues/lib/ajax-response.js' ],
[ WORKING_DIR + 'wp-includes/js/wp-api.js' ]: [ './src/js/_enqueues/wp/api.js' ],
[ WORKING_DIR + 'wp-includes/js/wp-auth-check.js' ]: [ './src/js/_enqueues/lib/auth-check.js' ],
[ WORKING_DIR + 'wp-includes/js/wp-tooltip.js' ]: [ './src/js/_enqueues/lib/wp-tooltip.js' ],
[ WORKING_DIR + 'wp-includes/js/wp-backbone.js' ]: [ './src/js/_enqueues/wp/backbone.js' ],
[ WORKING_DIR + 'wp-includes/js/wp-custom-header.js' ]: [ './src/js/_enqueues/wp/custom-header.js' ],
[ WORKING_DIR + 'wp-includes/js/wp-embed-template.js' ]: [ './src/js/_enqueues/lib/embed-template.js' ],
Expand Down Expand Up @@ -914,6 +915,7 @@ module.exports = function(grunt) {
'src/wp-includes/js/wp-ajax-response.js': 'src/js/_enqueues/lib/ajax-response.js',
'src/wp-includes/js/wp-api.js': 'src/js/_enqueues/wp/api.js',
'src/wp-includes/js/wp-auth-check.js': 'src/js/_enqueues/lib/auth-check.js',
'src/wp-includes/js/wp-tooltip.js': 'src/js/_enqueues/lib/wp-tooltip.js',
'src/wp-includes/js/wp-backbone.js': 'src/js/_enqueues/wp/backbone.js',
'src/wp-includes/js/wp-custom-header.js': 'src/js/_enqueues/wp/custom-header.js',
'src/wp-includes/js/wp-embed-template.js': 'src/js/_enqueues/lib/embed-template.js',
Expand Down
124 changes: 124 additions & 0 deletions src/js/_enqueues/wp/wp-tooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* Tooltip functionality for WordPress.
*
* @version 6.7.0
* @output wp-includes/js/wp-tooltip.js
*/

document.addEventListener( 'DOMContentLoaded', function () {
var tooltipContainers = document.querySelectorAll(
'.wp-tooltip-container'
);

tooltipContainers.forEach( function ( tooltipContainer ) {
var tooltipButton =
tooltipContainer.querySelector( '.wp-tooltip-button' );
var tooltipContent = tooltipContainer.querySelector(
'.wp-tooltip-content'
);

function showTooltip() {
tooltipContent.style.display = 'block';
adjustTooltipPosition( tooltipContainer, tooltipContent );
}

function hideTooltip() {
tooltipContent.style.display = 'none';
}

// Event listeners for mouse and touch events
tooltipContainer.addEventListener( 'mouseenter', showTooltip );
tooltipContainer.addEventListener( 'mouseleave', hideTooltip );
tooltipButton.addEventListener( 'touchstart', showTooltip );
tooltipButton.addEventListener( 'touchend', hideTooltip );

tooltipButton.style.cursor = 'help';

tooltipButton.addEventListener( 'keydown', function ( event ) {
if ( event.key === 'Enter' ) {
// Toggle the display of the tooltip content.
tooltipContent.style.display =
tooltipContent.style.display === 'block' ? 'none' : 'block';
if ( tooltipContent.style.display === 'block' ) {
adjustTooltipPosition( tooltipContainer, tooltipContent );
}
}
} );

document.addEventListener( 'keydown', function ( event ) {
if (
event.key === 'Escape' &&
tooltipContent.style.display === 'block'
) {
// Hide the tooltip on Escape key press.
tooltipContent.style.display = 'none';
tooltipButton.focus();
}
} );

document.body.addEventListener( 'click', function ( event ) {
// Check if the clicked element is not within the tooltip container.
if (
! tooltipContent.contains( event.target ) &&
! tooltipButton.contains( event.target )
) {
tooltipContent.style.display = 'none';
}
} );

tooltipContainer.addEventListener( 'focusout', function ( event ) {
if ( ! tooltipContainer.contains( event.relatedTarget ) ) {
hideTooltip();
}
} );
} );

// Function to adjust tooltip position based on screen availability
function adjustTooltipPosition( container, content ) {
var containerRect = container.getBoundingClientRect();
var contentRect = content.getBoundingClientRect();
var viewportWidth = window.innerWidth;
var viewportHeight = window.innerHeight;

// Check if there's enough space in each direction
var fitsAbove = containerRect.top >= contentRect.height;
var fitsBelow =
viewportHeight - containerRect.bottom >= contentRect.height;
var fitsLeft = containerRect.left >= contentRect.width;
var fitsRight =
viewportWidth - containerRect.right >= contentRect.width;

var defaultPosition = 'right';

if ( container.classList.contains( 'position-top' ) ) {
defaultPosition = 'top';
} else if ( container.classList.contains( 'position-bottom' ) ) {
defaultPosition = 'bottom';
} else if ( container.classList.contains( 'position-left' ) ) {
defaultPosition = 'left';
}

var newPosition = defaultPosition;

if ( defaultPosition === 'top' && ! fitsAbove && fitsBelow ) {
newPosition = 'bottom';
} else if ( defaultPosition === 'bottom' && ! fitsBelow && fitsAbove ) {
newPosition = 'top';
} else if ( defaultPosition === 'left' && ! fitsLeft && fitsRight ) {
newPosition = 'right';
} else if ( defaultPosition === 'right' && ! fitsRight && fitsLeft ) {
newPosition = 'left';
}

// Apply position adjustments
container.classList.remove(
'adjusted-position-top',
'adjusted-position-bottom',
'adjusted-position-left',
'adjusted-position-right'
);

// Add the new position class
container.classList.add( 'adjusted-position-' + newPosition );
}
} );
102 changes: 102 additions & 0 deletions src/wp-includes/css/wp-tooltip.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
.wp-tooltip-container {
position: relative;
display: inline-block;
}

.wp-tooltip-button:focus {
outline: 1px solid black;
border-radius: 20px;
}

.wp-tooltip-button {
background: none;
border: none;
cursor: pointer;
}

.wp-tooltip-button-span {
vertical-align: top;
text-align: center;
}

.wp-tooltip-content {
display: none;
position: absolute;
background-color: #2271b1;
color: white;
border: 1px solid #ccc;
padding: 5px;
z-index: 1000;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 5px;
width: 200px;
height: auto;
text-align: center;
}

.wp-tooltip-content p {
all: unset;
overflow-wrap: break-word;
}

/* Styles for default positions. */
.wp-tooltip-container.position-top .wp-tooltip-content {
top: auto;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
}

.wp-tooltip-container.position-bottom .wp-tooltip-content {
top: 100%;
bottom: auto;
left: 50%;
transform: translateX(-50%);
}

.wp-tooltip-container.position-left .wp-tooltip-content {
top: 50%;
bottom: auto;
left: auto;
right: 100%;
transform: translateY(-50%);
}

.wp-tooltip-container.position-right .wp-tooltip-content {
top: 50%;
bottom: auto;
left: 100%;
right: auto;
transform: translateY(-50%);
}

/* Styles for Adjusted position. */
.wp-tooltip-container.adjusted-position-top .wp-tooltip-content {
top: auto;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
}

.wp-tooltip-container.adjusted-position-bottom .wp-tooltip-content {
top: 100%;
bottom: auto;
left: 50%;
transform: translateX(-50%);
}

.wp-tooltip-container.adjusted-position-left .wp-tooltip-content {
top: 50%;
bottom: auto;
left: auto;
right: 100%;
transform: translateY(-50%);
}

.wp-tooltip-container.adjusted-position-right .wp-tooltip-content {
top: 50%;
bottom: auto;
left: 100%;
right: auto;
transform: translateY(-50%);
}
135 changes: 135 additions & 0 deletions src/wp-includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -9012,3 +9012,138 @@

echo wp_kses_post( wp_get_admin_notice( $message, $args ) );
}

/**
* Outputs the tooltip for a specific field.
*
* @since 6.7.0
*
* @param string $field_id The unique identifier for the tooltip container.
* @param string $tooltip_text The text content to be displayed in the tooltip.
* @param string $tooltip_button_label Optional. The label for the tooltip button. Default is 'Help'.
* @param string $position Optional. The default position of the tooltip. Default is 'right'.
* Accepted values: 'right', 'left', 'up' and 'down'.
*/
function add_tooltip( $field_id, $tooltip_text, $tooltip_button_label = 'Help', $position = 'right' ) {

if ( ! is_string( $field_id ) || '' === $field_id ) {

Check failure on line 9029 in src/wp-includes/functions.php

View workflow job for this annotation

GitHub Actions / PHP coding standards / Run coding standards checks

Spaces must be used for mid-line alignment; tabs are not allowed
$error_arg = '$field_id';
} elseif ( ! is_string( $tooltip_text ) || '' === $tooltip_text ) {
$error_arg = '$tooltip_text';
} elseif ( ! is_string( $tooltip_button_label ) ) {
$error_arg = '$tooltip_button_label';
}

if ( isset( $error_arg ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: The invalid argument passed to add_tooltip(). */
__( 'The "%s" argument must be a non-empty string.' ),
$error_arg
),
'6.7.0'
);

return;
}

$valid_positions = array( 'top', 'right', 'bottom', 'left' );

// Validate position input.
if ( ! is_string( $position ) || ! in_array( $position, $valid_positions, true ) ) {

_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: Invalid $position argument passed to add_tooltip(). */
__( 'The passed "%s" argument is invalid. Default "right" position was used instead.' ),
'$position'
),
'6.7.0'
);

$position = 'right';
}

/**
* Enqueues the Styles and Scripts for the Tooltip.
*
* @since 6.7.0
*
*/
wp_enqueue_style( 'wp-tooltip' );
wp_enqueue_script( 'wp-tooltip' );

$icon_url = 'dashicons-editor-help';

/**
* Filters $icon_url before the tooltip is rendered in the HTML.
*
* @since 6.7.0
*
* @param string $icon_url The URL to the icon to be used for this tooltip.
* * Pass a base64-encoded SVG using a data URI, which will be colored to match
* the color scheme. This should begin with 'data:image/svg+xml;base64,'.
* * Pass the name of a Dashicons helper class to use a font icon,
* e.g. 'dashicons-editor-help'.
* * Pass 'none' to leave span.wp-tooltip-button-span empty so an icon can be added via CSS.
* @param string $field_id The unique identifier for the tooltip container.
*/
$icon_url = apply_filters( 'wp_tooltip_icon', $icon_url, $field_id );
$icon_url = set_url_scheme( $icon_url );

if ( str_starts_with( $icon_url, 'dashicons-' ) ) {
$icon = 'class="dashicons ' . sanitize_html_class( $icon_url ) . '"';
$icon_html = '<span ' . $icon . '></span>';
} elseif ( str_starts_with( $icon_url, 'data:image/svg+xml;base64,' ) ) {
$icon = ' style="background-image:url(\'' . esc_attr( $icon_url ) . '\')"';
$icon_html = '<svg height = "20" width = "20"' . $icon . '</svg>';
} elseif ( str_starts_with( $icon_url, 'http' ) ) {
$icon_html = '<img height = "20" width = "20" src="' . esc_url( $icon_url ) . '" alt="" />';
} elseif ( 'none' === $icon_url ) {
$icon_html = '';
} else {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: Invalid $icon_html passed in 'pre_wp_tooltip_rendered' hook. */
__( 'The passed "%1$s" argument in the "%2$s" filter is invalid.' ),
'$icon_html',
'pre_wp_tooltip_rendered'
),
'6.7.0'
);

$icon_html = '<span class="dashicons dashicons-editor-help"></span>';
}

/**
* Fires before the tooltip is rendered.
*
* @since 6.7.0
*
* @param string $field_id The unique identifier for the tooltip container.
* @param string $tooltip_text The text content to be displayed in the tooltip.
* @param string $tooltip_button_label The label for the tooltip button.
* @param string $position The default position of the tooltip.
* @param string $icon_url The URL to the icon to be used for this tooltip.
* Pass a base64-encoded SVG using a data URI, which will be colored to match
* the color scheme. This should begin with 'data:image/svg+xml;base64,'.
* Pass the name of a Dashicons helper class to use a font icon,
* e.g. 'dashicons-editor-help'.
* Pass 'none' to leave span.wp-tooltip-button-span empty so an icon can be added via CSS.
*/
add_action( 'pre_wp_tooltip_rendered', $field_id, $tooltip_text, $tooltip_button_label, $position, $icon_url );

?>
<div class="wp-tooltip-container <?php echo esc_attr( $field_id ); ?> <?php echo esc_attr( 'position-' . $position ); ?>">
<button type="button" class="wp-tooltip-button" aria-describedby="<?php echo esc_attr( $field_id ); ?>-tooltip" aria-label="<?php echo esc_attr( $tooltip_button_label ); ?>">
<span class="wp-tooltip-button-span"><?php echo $icon_html; ?></span>
</button>
<div id="<?php echo esc_attr( $field_id ); ?>-tooltip" class="wp-tooltip-content">
<p><?php echo esc_html( $tooltip_text ); ?></p>
</div>
</div>
<?php
}
Loading
Loading