From 07e4b7565ef0450218ec52a7c7d8d8043923e1db Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 29 Jan 2018 23:55:44 +0000 Subject: [PATCH] Customize: Ensure media playlists get initialized after selective refresh; expose new `wp.playlist.initialize()` API. In particular allows audio and video playlists to be added to the Text widget and previewed. Props bpayton, westonruter. See #40854. Fixes #42495. git-svn-id: https://develop.svn.wordpress.org/trunk@42613 602fd350-edb4-49c9-b593-d223f7449a82 --- .../js/customize-selective-refresh.js | 4 ++ .../js/mediaelement/wp-playlist.js | 32 +++++++++-- .../widgets/class-wp-widget-text.php | 20 +++++++ tests/phpunit/tests/widgets/text-widget.php | 54 +++++++++++++++++++ 4 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/js/customize-selective-refresh.js b/src/wp-includes/js/customize-selective-refresh.js index b1169eb277..a3d71f76d1 100644 --- a/src/wp-includes/js/customize-selective-refresh.js +++ b/src/wp-includes/js/customize-selective-refresh.js @@ -488,6 +488,10 @@ wp.customize.selectiveRefresh = ( function( $, api ) { wp.mediaelement.initialize(); } + if ( wp.playlist ) { + wp.playlist.initialize(); + } + /** * Announce when a partial's placement has been rendered so that dynamic elements can be re-built. */ diff --git a/src/wp-includes/js/mediaelement/wp-playlist.js b/src/wp-includes/js/mediaelement/wp-playlist.js index 19cab125ba..81c7da6c42 100644 --- a/src/wp-includes/js/mediaelement/wp-playlist.js +++ b/src/wp-includes/js/mediaelement/wp-playlist.js @@ -3,6 +3,9 @@ (function ($, _, Backbone) { 'use strict'; + /** @namespace wp */ + window.wp = window.wp || {}; + var WPPlaylistView = Backbone.View.extend(/** @lends WPPlaylistView.prototype */{ /** * @constructs @@ -168,11 +171,32 @@ } }); - $(document).ready(function () { - $('.wp-playlist').each( function() { - return new WPPlaylistView({ el: this }); + /** + * Initialize media playlists in the document. + * + * Only initializes new playlists not previously-initialized. + * + * @since 4.9.3 + * @returns {void} + */ + function initialize() { + $( '.wp-playlist:not(:has(.mejs-container))' ).each( function() { + new WPPlaylistView( { el: this } ); } ); - }); + } + + /** + * Expose the API publicly on window.wp.playlist. + * + * @namespace wp.playlist + * @since 4.9.3 + * @type {object} + */ + window.wp.playlist = { + initialize: initialize + }; + + $( document ).ready( initialize ); window.WPPlaylistView = WPPlaylistView; diff --git a/src/wp-includes/widgets/class-wp-widget-text.php b/src/wp-includes/widgets/class-wp-widget-text.php index 5d73eb4ce0..21feb3f20a 100644 --- a/src/wp-includes/widgets/class-wp-widget-text.php +++ b/src/wp-includes/widgets/class-wp-widget-text.php @@ -57,6 +57,10 @@ class WP_Widget_Text extends WP_Widget { wp_add_inline_script( 'text-widgets', sprintf( 'wp.textWidgets.idBases.push( %s );', wp_json_encode( $this->id_base ) ) ); + if ( $this->is_preview() ) { + add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_preview_scripts' ) ); + } + // Note that the widgets component in the customizer will also do the 'admin_print_scripts-widgets.php' action in WP_Customize_Widgets::print_scripts(). add_action( 'admin_print_scripts-widgets.php', array( $this, 'enqueue_admin_scripts' ) ); @@ -393,6 +397,22 @@ class WP_Widget_Text extends WP_Widget { return $instance; } + /** + * Enqueue preview scripts. + * + * These scripts normally are enqueued just-in-time when a playlist shortcode is used. + * However, in the customizer, a playlist shortcode may be used in a text widget and + * dynamically added via selective refresh, so it is important to unconditionally enqueue them. + * + * @since 4.9.3 + */ + public function enqueue_preview_scripts() { + require_once dirname( dirname( __FILE__ ) ) . '/media.php'; + + wp_playlist_scripts( 'audio' ); + wp_playlist_scripts( 'video' ); + } + /** * Loads the required scripts and styles for the widget control. * diff --git a/tests/phpunit/tests/widgets/text-widget.php b/tests/phpunit/tests/widgets/text-widget.php index 490875416b..c50cf31e68 100644 --- a/tests/phpunit/tests/widgets/text-widget.php +++ b/tests/phpunit/tests/widgets/text-widget.php @@ -66,6 +66,60 @@ class Test_WP_Widget_Text extends WP_UnitTestCase { $this->assertEquals( 10, has_action( 'admin_print_scripts-widgets.php', array( $widget, 'enqueue_admin_scripts' ) ) ); $this->assertEquals( 10, has_action( 'admin_footer-widgets.php', array( 'WP_Widget_Text', 'render_control_template_scripts' ) ) ); $this->assertContains( 'wp.textWidgets.idBases.push( "text" );', wp_scripts()->registered['text-widgets']->extra['after'] ); + $this->assertFalse( has_action( 'wp_enqueue_scripts', array( $widget, 'enqueue_preview_scripts' ) ) ); + } + + /** + * Test register in customize preview. + * + * @global WP_Customize_Manager $wp_customize + * @covers WP_Widget_Text::__construct() + * @covers WP_Widget_Text::_register() + */ + function test__register_in_customize_preview() { + global $wp_customize; + wp_set_current_user( + $this->factory()->user->create( + array( + 'role' => 'administrator', + ) + ) + ); + require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; + $wp_customize = new WP_Customize_Manager( + array( + 'changeset_uuid' => wp_generate_uuid4(), + ) + ); + $wp_customize->start_previewing_theme(); + + $widget = new WP_Widget_Text(); + $widget->_register(); + $this->assertEquals( 10, has_action( 'wp_enqueue_scripts', array( $widget, 'enqueue_preview_scripts' ) ) ); + } + + /** + * Test enqueue_preview_scripts method. + * + * @global WP_Scripts $wp_scripts + * @global WP_Styles $wp_styles + * @covers WP_Widget_Text::enqueue_preview_scripts + */ + function test_enqueue_preview_scripts() { + global $wp_scripts, $wp_styles; + $wp_scripts = null; + $wp_styles = null; + $widget = new WP_Widget_Text(); + + $this->assertFalse( wp_style_is( 'wp-mediaelement' ) ); + $this->assertFalse( wp_script_is( 'wp-playlist' ) ); + + ob_start(); + $widget->enqueue_preview_scripts(); + ob_end_clean(); + + $this->assertTrue( wp_style_is( 'wp-mediaelement' ) ); + $this->assertTrue( wp_script_is( 'wp-playlist' ) ); } /**