Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions plugins/view-transitions/includes/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ function plvt_print_view_transitions_admin_style(): void {
if ( ! isset( $options['enable_admin_transitions'] ) || true !== $options['enable_admin_transitions'] ) {
return;
}

$duration_seconds = absint( $options['default_transition_animation_duration'] ) / 1000;
?>
<style>
@view-transition { navigation: auto; }
::view-transition-group(*) { animation-duration: <?php echo (int) $duration_seconds ; ?>s; }
#adminmenu > .menu-top { view-transition-name: attr(id type(<custom-ident>), none); }
</style>
<?php
Expand Down
100 changes: 94 additions & 6 deletions plugins/view-transitions/includes/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

/**
* Minimum allowed transition animation duration in milliseconds.
*
* @since n.e.x.t
* @var int
*/
const PLVT_MIN_ANIMATION_DURATION = 100;

/**
* Maximum allowed transition animation duration in milliseconds.
*
* @since n.e.x.t
* @var int
*/
const PLVT_MAX_ANIMATION_DURATION = 5000;
// @codeCoverageIgnoreEnd

/**
Expand Down Expand Up @@ -135,9 +152,11 @@ function plvt_sanitize_setting( $input ): array {
$value['default_transition_animation'] = $input['default_transition_animation'];
}

// Handle default_transition_animation_duration separately.
// Handle default_transition_animation_duration with min/max bounds.
if ( isset( $input['default_transition_animation_duration'] ) ) {
$value['default_transition_animation_duration'] = absint( $input['default_transition_animation_duration'] );
$duration = absint( $input['default_transition_animation_duration'] );
// Clamp between min and max for sensible values.
$value['default_transition_animation_duration'] = max( PLVT_MIN_ANIMATION_DURATION, min( PLVT_MAX_ANIMATION_DURATION, $duration ) );
}

$selector_options = array(
Expand Down Expand Up @@ -193,6 +212,12 @@ function plvt_register_setting(): void {
'type' => 'string',
'enum' => array_keys( plvt_get_view_transition_animation_labels() ),
),
'default_transition_animation_duration' => array(
'description' => __( 'Duration of the view transition animation in milliseconds.', 'view-transitions' ),
'type' => 'integer',
'minimum' => PLVT_MIN_ANIMATION_DURATION,
'maximum' => PLVT_MAX_ANIMATION_DURATION,
),
),
'additionalProperties' => false,
),
Expand Down Expand Up @@ -325,9 +350,14 @@ static function (): void {
'description' => __( 'Choose the animation that is used for the default view transition type.', 'view-transitions' ),
),
'default_transition_animation_duration' => array(
'section' => 'plvt_view_transitions',
'title' => __( 'Transition Animation Duration', 'view-transitions' ),
'description' => __( 'Control the duration of the view transition. Enter the value in milliseconds (e.g., 500, 1000, 2000).', 'view-transitions' ),
'section' => 'plvt_view_transitions',
'title' => __( 'Transition Animation Duration', 'view-transitions' ),
'description' => __( 'Control the duration of the view transition. Enter the value in milliseconds (e.g., 500, 1000, 2000).', 'view-transitions' ),
'min' => PLVT_MIN_ANIMATION_DURATION,
'max' => PLVT_MAX_ANIMATION_DURATION,
'step' => 50,
'unit' => 'ms',
'show_seconds' => true,
),
'header_selector' => array(
'section' => 'plvt_view_transitions',
Expand Down Expand Up @@ -473,10 +503,68 @@ function plvt_render_settings_field( array $args ): void {
<?php echo esc_html( $args['description'] ); ?>
</label>
<?php
} elseif ( 'number' === $type ) {
?>
<input
type="number"
id="<?php echo esc_attr( $args['label_for'] ); ?>"
name="<?php echo esc_attr( "plvt_view_transitions[{$args['field']}]" ); ?>"
value="<?php echo esc_attr( (string) $value ); ?>"
class="small-text"
<?php
if ( isset( $args['min'] ) ) {
?>
min="<?php echo esc_attr( (string) $args['min'] ); ?>"
<?php
}
if ( isset( $args['max'] ) ) {
?>
max="<?php echo esc_attr( (string) $args['max'] ); ?>"
<?php
}
if ( isset( $args['step'] ) ) {
?>
step="<?php echo esc_attr( (string) $args['step'] ); ?>"
<?php
}
if ( '' !== $args['description'] ) {
?>
aria-describedby="<?php echo esc_attr( $args['label_for'] . '-description' ); ?>"
<?php
}
?>
>
<?php
if ( isset( $args['unit'] ) && '' !== $args['unit'] ) {
?>
<span class="description">
<?php
if ( isset( $args['show_seconds'] ) && true === $args['show_seconds'] ) {
$seconds = (int) $value / 1000;
$field_id = esc_attr( $args['label_for'] );
printf(
/* translators: 1: unit, 2: duration in seconds wrapped in a span for dynamic update */
esc_html__( '%1$s (%2$s)', 'view-transitions' ),
esc_html( $args['unit'] ),
'<span id="' . esc_attr( $args['label_for'] ) . '-seconds">' . esc_html( (string) $seconds ) . 's</span>'
);
wp_print_inline_script_tag(
sprintf(
'document.getElementById( %s ).addEventListener( "input", function( e ) { document.getElementById( %s ).textContent = ( parseInt( e.target.value, 10 ) / 1000 ) + "s"; } );',
wp_json_encode( $field_id ),
wp_json_encode( $field_id . '-seconds' )
)
);
} else {
echo esc_html( $args['unit'] );
}
?>
</span>
<?php
}
} else {
?>
<input
<?php echo ( 'number' === $type ) ? 'type="number"' : ''; ?>
id="<?php echo esc_attr( $args['label_for'] ); ?>"
name="<?php echo esc_attr( "plvt_view_transitions[{$args['field']}]" ); ?>"
value="<?php echo esc_attr( (string) $value ); ?>"
Expand Down
60 changes: 60 additions & 0 deletions plugins/view-transitions/tests/test-admin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php
/**
* Tests for the View Transitions plugin includes/admin.php file.
*
* @package view-transitions
* @group view-transitions
*/

class Test_ViewTransitions_Admin extends WP_UnitTestCase {

/**
* @covers ::plvt_print_view_transitions_admin_style
*/
public function test_plvt_print_view_transitions_admin_style_disabled(): void {
update_option( 'plvt_view_transitions', array( 'enable_admin_transitions' => false ) );

ob_start();
plvt_print_view_transitions_admin_style();
$output = ob_get_clean();

$this->assertEmpty( $output );
}

/**
* @covers ::plvt_print_view_transitions_admin_style
*/
public function test_plvt_print_view_transitions_admin_style_enabled(): void {
update_option(
'plvt_view_transitions',
array(
'enable_admin_transitions' => true,
'default_transition_animation_duration' => 500,
)
);

ob_start();
plvt_print_view_transitions_admin_style();
$output = ob_get_clean();

$this->assertStringContainsString( '@view-transition { navigation: auto; }', $output );
$this->assertStringContainsString( 'animation-duration: 0.5s', $output );
}

/**
* @covers ::plvt_print_view_transitions_admin_style
*/
public function test_plvt_print_view_transitions_admin_style_uses_default_duration(): void {
update_option(
'plvt_view_transitions',
array( 'enable_admin_transitions' => true )
);

ob_start();
plvt_print_view_transitions_admin_style();
$output = ob_get_clean();

// Default duration is 400ms = 0.4s.
$this->assertStringContainsString( 'animation-duration: 0.4s', $output );
}
}
89 changes: 89 additions & 0 deletions plugins/view-transitions/tests/test-settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php
/**
* Tests for the View Transitions plugin includes/settings.php file.
*
* @package view-transitions
* @group view-transitions
*/

class Test_ViewTransitions_Settings extends WP_UnitTestCase {

/**
* @covers ::plvt_sanitize_setting
*/
public function test_plvt_sanitize_setting_returns_defaults_for_invalid_input(): void {
$this->assertSame( plvt_get_setting_default(), plvt_sanitize_setting( null ) );
$this->assertSame( plvt_get_setting_default(), plvt_sanitize_setting( 'string' ) );
$this->assertSame( plvt_get_setting_default(), plvt_sanitize_setting( 123 ) );
}

/**
* @covers ::plvt_sanitize_setting
*/
public function test_plvt_sanitize_setting_clamps_duration_minimum(): void {
$input = array( 'default_transition_animation_duration' => 50 );
$result = plvt_sanitize_setting( $input );
$this->assertSame( PLVT_MIN_ANIMATION_DURATION, $result['default_transition_animation_duration'] );
}

/**
* @covers ::plvt_sanitize_setting
*/
public function test_plvt_sanitize_setting_clamps_duration_maximum(): void {
$input = array( 'default_transition_animation_duration' => 10000 );
$result = plvt_sanitize_setting( $input );
$this->assertSame( PLVT_MAX_ANIMATION_DURATION, $result['default_transition_animation_duration'] );
}

/**
* @covers ::plvt_sanitize_setting
*/
public function test_plvt_sanitize_setting_accepts_valid_duration(): void {
$input = array( 'default_transition_animation_duration' => 500 );
$result = plvt_sanitize_setting( $input );
$this->assertSame( 500, $result['default_transition_animation_duration'] );
}

/**
* @covers ::plvt_sanitize_setting
*/
public function test_plvt_sanitize_setting_handles_negative_duration(): void {
$input = array( 'default_transition_animation_duration' => -500 );
$result = plvt_sanitize_setting( $input );
// absint converts negative to positive, then clamps.
$this->assertSame( 500, $result['default_transition_animation_duration'] );
}

/**
* @covers ::plvt_sanitize_setting
*/
public function test_plvt_sanitize_setting_handles_string_duration(): void {
$input = array( 'default_transition_animation_duration' => '750' );
$result = plvt_sanitize_setting( $input );
$this->assertSame( 750, $result['default_transition_animation_duration'] );
}

/**
* @covers ::plvt_get_setting_default
*/
public function test_plvt_get_setting_default_has_valid_duration(): void {
$defaults = plvt_get_setting_default();
$this->assertArrayHasKey( 'default_transition_animation_duration', $defaults );
$this->assertIsInt( $defaults['default_transition_animation_duration'] );
$this->assertGreaterThanOrEqual( PLVT_MIN_ANIMATION_DURATION, $defaults['default_transition_animation_duration'] );
$this->assertLessThanOrEqual( PLVT_MAX_ANIMATION_DURATION, $defaults['default_transition_animation_duration'] );
}

/**
* @covers ::plvt_sanitize_setting
*/
public function test_plvt_sanitize_setting_validates_animation_type(): void {
$input = array( 'default_transition_animation' => 'invalid-animation' );
$result = plvt_sanitize_setting( $input );
$this->assertSame( 'fade', $result['default_transition_animation'] );

$input = array( 'default_transition_animation' => 'slide-from-right' );
$result = plvt_sanitize_setting( $input );
$this->assertSame( 'slide-from-right', $result['default_transition_animation'] );
}
}
32 changes: 32 additions & 0 deletions plugins/view-transitions/tests/test-theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,36 @@ public function test_plvt_load_view_transitions(): void {
$this->assertTrue( wp_style_is( 'plvt-view-transitions', 'registered' ) );
$this->assertTrue( wp_style_is( 'plvt-view-transitions', 'enqueued' ) );
}

/**
* @covers ::plvt_inject_animation_duration
*/
public function test_plvt_inject_animation_duration_with_existing_css(): void {
$css = '::view-transition-old(*) { animation-name: test; }';
$result = plvt_inject_animation_duration( $css, 500 );

$this->assertStringContainsString( '--plvt-view-transition-animation-duration: 0.5s', $result );
$this->assertStringContainsString( $css, $result );
}

/**
* @covers ::plvt_inject_animation_duration
*/
public function test_plvt_inject_animation_duration_with_empty_css(): void {
$result = plvt_inject_animation_duration( '', 400 );

$this->assertStringContainsString( 'animation-duration: 0.4s', $result );
$this->assertStringNotContainsString( '--plvt-view-transition-animation-duration', $result );
}

/**
* @covers ::plvt_inject_animation_duration
*/
public function test_plvt_inject_animation_duration_converts_milliseconds_to_seconds(): void {
$result = plvt_inject_animation_duration( '', 1000 );
$this->assertStringContainsString( '1s', $result );

$result = plvt_inject_animation_duration( '', 250 );
$this->assertStringContainsString( '0.25s', $result );
}
}
Loading