Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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.
}


/**
* 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