Skip to content

Commit

Permalink
T352298: Add custom tooltip (#111)
Browse files Browse the repository at this point in the history
* Add initial tooltip.js

* Initial computeTooltipPosition

* Use Popover component

* Naming update

* Address warnings

* Move useEffect logic to a method for consistency

* Use property to store tooltip count

* Remove className

* Add guard to prevent displaying tooltip if toolbar is closed

* Address php linter

* Proprogate property

* Color popover arrow and add offset

* Rewrite endpoints set up as a function for consistency

* Address linter

* Increment property via window object

* Use camelCasing and improve readability

* Concentrate all tooltip logic inside CustomTooltip for better code hygene

* Disable selector-class-pattern globally

* Track whether the tooltip has been displayed for the full 5 secs

* Address linter

* Clear timeouts if user clicks on W before the tooltip diplays

* Address linter

* Add comments for php properties
  • Loading branch information
medied authored Apr 29, 2024
1 parent 99fe0da commit 6d49a85
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"XMLHttpRequest": true
},
"rules": {
"click-events-have-key-events": "off"
"click-events-have-key-events": "off",
"no-shadow": "off"
}
}
5 changes: 5 additions & 0 deletions .stylelintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"selector-class-pattern": null
}
}
11 changes: 9 additions & 2 deletions src/link/edit.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from '@wordpress/element';
import { useEffect, useState, useRef } from '@wordpress/element';
import { BlockControls } from '@wordpress/block-editor';
import { ToolbarGroup, ToolbarButton } from '@wordpress/components';
import {
Expand All @@ -10,6 +10,7 @@ import {
import { __ } from '@wordpress/i18n';
import { InlineEditUI } from './inline';
import { PreviewEditUI } from './preview';
import { CustomTooltip } from './tooltip';

const formatType = 'wikipediapreview/link';
const formatTitle = __( 'Wikipedia Preview', 'wikipedia-preview' );
Expand Down Expand Up @@ -46,6 +47,7 @@ const Edit = ( {
const startViewingPreview = () => setViewingPreview( true );
const stopViewingPreview = () => setViewingPreview( false );
const [ lastValue, setLastValue ] = useState( null );
const toolbarButtonRef = useRef();

const formatButtonClick = () => {
if ( isActive ) {
Expand Down Expand Up @@ -199,12 +201,17 @@ const Edit = ( {
<ToolbarGroup>
<ToolbarButton
icon={ generateWikipediaLogo( isActive ? 'white' : 'black' ) }
title={ formatTitle }
title={ __( 'Add Wikipedia Preview', 'wikipedia-preview' ) }
isActive={ isActive }
onClick={ formatButtonClick }
ref={ toolbarButtonRef }
/>
</ToolbarGroup>
</BlockControls>
<CustomTooltip
anchorRef={ toolbarButtonRef }
addingPreview={ addingPreview }
/>
{ addingPreview && (
<InlineEditUI
contentRef={ contentRef }
Expand Down
29 changes: 27 additions & 2 deletions src/link/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,35 @@ body {
}
}

.wikipediapreview-edit-tooltip-popover {

&-content {
width: 190px;
height: 40px;
background: #36c;
color: #fff;
display: flex;
justify-content: center;
}

&-text {
align-self: center;
}

.components-popover__arrow {

&::before {
background-color: unset;
}
}

.components-popover__triangle-bg {
fill: #36c;
}
}

.wikipediapreview-edit-preview-popover {

/* stylelint-disable-next-line selector-class-pattern */
.components-popover__content {
background: unset;
border: unset;
Expand Down Expand Up @@ -392,7 +418,6 @@ body {
&.is-expanded {
background-color: rgba(0, 0, 0, 0.7);

/* stylelint-disable-next-line selector-class-pattern */
.components-popover__header {
visibility: hidden;
}
Expand Down
95 changes: 95 additions & 0 deletions src/link/tooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* global wikipediapreviewCustomTooltip */
import { __ } from '@wordpress/i18n';
import { Popover } from '@wordpress/components';
import { useEffect, useState } from '@wordpress/element';

export const CustomTooltip = ( {
anchorRef,
addingPreview,
} ) => {
const [ displayTooltip, setDisplayTooltip ] = useState( false );
const [ timeoutIds, setTimeoutIds ] = useState( [] );
const tooltipDisplayedFullDuration = useState( parseInt( wikipediapreviewCustomTooltip.tooltipDuration ) )[ 0 ];
const tooltipDisplayedCount = useState( parseInt( wikipediapreviewCustomTooltip.tooltipCount ) )[ 0 ];
const tooltipDisplayedLimit = 2;

const updateStoredProperty = ( prop ) => {
fetch( `/wp-json/wikipediapreview/v1/${ prop }/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
} );
};

const finishDisplayingTooltip = () => {
setDisplayTooltip( false );
wikipediapreviewCustomTooltip.tooltipDuration = 1;
updateStoredProperty( 'duration' );
};

const clearTimeouts = () => {
timeoutIds.forEach( ( id ) => {
clearTimeout( id );
} );
};

const waitOneSecThenDisplayTooltip = () => {
const oneSecId = setTimeout( () => {
if ( anchorRef.current ) {
setDisplayTooltip( true );
updateStoredProperty( 'count' );
// Increment global tooltip count directly as well
// to ensure count is up to date in between page reloads
wikipediapreviewCustomTooltip.tooltipCount = tooltipDisplayedCount + 1;
waitFiveSecsThenHideTooltip();
}
}, 1000 );
setTimeoutIds( ( timeoutIds ) => [ ...timeoutIds, oneSecId ] );
};

const waitFiveSecsThenHideTooltip = () => {
const fiveSecId = setTimeout( () => {
finishDisplayingTooltip();
}, 5000 );
setTimeoutIds( ( timeoutIds ) => [ ...timeoutIds, fiveSecId ] );
};

useEffect( () => {
if ( tooltipDisplayedCount < tooltipDisplayedLimit && tooltipDisplayedFullDuration < 1 ) {
waitOneSecThenDisplayTooltip();
}
}, [] );

Check warning on line 62 in src/link/tooltip.js

View workflow job for this annotation

GitHub Actions / build

React Hook useEffect has missing dependencies: 'tooltipDisplayedCount', 'tooltipDisplayedFullDuration', and 'waitOneSecThenDisplayTooltip'. Either include them or remove the dependency array

useEffect( () => {
// Clear all timeouts when unmounting
return () => {
clearTimeouts();
};
}, [ timeoutIds ] );

Check warning on line 69 in src/link/tooltip.js

View workflow job for this annotation

GitHub Actions / build

React Hook useEffect has a missing dependency: 'clearTimeouts'. Either include it or remove the dependency array

useEffect( () => {
if ( addingPreview ) {
clearTimeouts();
finishDisplayingTooltip();
}
}, [ addingPreview ] );

Check warning on line 76 in src/link/tooltip.js

View workflow job for this annotation

GitHub Actions / build

React Hook useEffect has missing dependencies: 'clearTimeouts' and 'finishDisplayingTooltip'. Either include them or remove the dependency array

return (
<div>
{ displayTooltip && (
<Popover
anchor={ anchorRef.current }
placement={ 'top' }
noArrow={ false }
offset={ 10 }
className="wikipediapreview-edit-tooltip-popover"
>
<div className="wikipediapreview-edit-tooltip-popover-content">
<p className="wikipediapreview-edit-tooltip-popover-text">{ __( 'Add Wikipedia Preview' ) }</p>
</div>
</Popover>
) }
</div>
);
};
100 changes: 100 additions & 0 deletions tooltip.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

/*
* The number of times the tooltip has been displayed, whether in full duration or not.
* This count can be incremented until we hit a limit (set on the client side).
*/
DEFINE( 'WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_COUNT', 'wikipediapreview_tooltip_count' );

/*
* Whether or not the tooltip has been displayed in full duration at least once,
* this acts as a boolean that's either 0 or 1. When set to 1, we infer the
* Wikipedia Preview plugin has been 'discovered' and hence we do not display it again
*/
DEFINE( 'WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_DURATION', 'wikipediapreview_tooltip_duration' );

function wikipediapreview_get_tooltip_count() {
return get_option(
WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_COUNT,
0
);
}

function wikipediapreview_increment_tooltip_count() {
$count = wikipediapreview_get_tooltip_count();
update_option(
WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_COUNT,
$count + 1
);
}

function wikipediapreview_update_tooltip_duration() {
update_option(
WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_DURATION,
1
);
}

// For debugging purposes
function wikipediapreview_reset_tooltip_properties() {
update_option(
WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_COUNT,
0
);
update_option(
WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_DURATION,
0
);
}


function wikipediapreview_set_rest_endpoint() {
register_rest_route(
'wikipediapreview/v1',
'/count/',
array(
'methods' => 'POST',
'callback' => 'wikipediapreview_increment_tooltip_count',
)
);
register_rest_route(
'wikipediapreview/v1',
'/duration/',
array(
'methods' => 'POST',
'callback' => 'wikipediapreview_update_tooltip_duration',
)
);
register_rest_route(
'wikipediapreview/v1',
'/reset/',
array(
'methods' => 'POST',
'callback' => 'wikipediapreview_reset_tooltip_properties',
)
);
}

function wikipediapreview_tooltip_enqueue_script() {
$src_link_dir = plugin_dir_url( __FILE__ ) . 'src/link';
$no_dependencies = array();
$in_footer = true;

wp_enqueue_script(
'wikipedia-preview-tooltip',
$src_link_dir . 'tooltip.js',
$no_dependencies,
WIKIPEDIA_PREVIEW_PLUGIN_VERSION,
$in_footer
);

$options = array(
'tooltipCount' => wikipediapreview_get_tooltip_count(),
'tooltipDuration' => get_option( WIKIPEDIA_PREVIEW_TOOLTIP_DISPLAYED_DURATION, 0 ),
);

wp_localize_script( 'wikipedia-preview-tooltip', 'wikipediapreviewCustomTooltip', $options );
}

add_action( 'enqueue_block_editor_assets', 'wikipediapreview_tooltip_enqueue_script' );
add_action( 'rest_api_init', 'wikipediapreview_set_rest_endpoint' );
1 change: 1 addition & 0 deletions wikipediapreview.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,6 @@ function add_meta_links( $links_array, $plugin_file_name, $plugin_data, $status
add_action( 'init', 'myguten_set_script_translations' );
add_action( 'init', 'register_detectlinks_postmeta' );

require __DIR__ . '/tooltip.php';
require __DIR__ . '/banner.php';
require __DIR__ . '/intro.php';

0 comments on commit 6d49a85

Please sign in to comment.