diff options
author | Scott Taylor <wonderboymusic@git.wordpress.org> | 2014-03-20 13:33:00 +0000 |
---|---|---|
committer | Scott Taylor <wonderboymusic@git.wordpress.org> | 2014-03-20 13:33:00 +0000 |
commit | 5c0f7ae4fbcf6517ba586ddfa2c2d16f5db5f6ad (patch) | |
tree | 3d68b3b10ad91f902b75bd7a9662e048de650c30 /src | |
parent | 5bbb2d3951880b77659ab89595c3c0ca7d909815 (diff) | |
download | wordpress-5c0f7ae4fbcf6517ba586ddfa2c2d16f5db5f6ad.tar.gz wordpress-5c0f7ae4fbcf6517ba586ddfa2c2d16f5db5f6ad.zip |
Unifying media controls and supporting playlists in the editor:
* Support a `caption` attribute for audio and video shortcodes
* In `wp.media.audio|video`, rename `update` to `shortcode` to allow these models to share the same mixins as `wp.media.collection` subclasses
* When sending an audio or video shortcode to the editor, create a default caption if the user hasn't entered one. This currently only displays in the editor, not on the front end. Captions aren't tied to a specific attachment here because external sources are supported.
* In the `wp.mce.media` mixin, in the `edit` method, read `attr` instead of `data` when attempting to parse the encoded shortcode. `data` does not automatically update when the attribute changes. This was a blessing to debug.
* Add `wp.mce.media.PlaylistView` to support playlist views in TinyMCE
* Expose `WPPlaylistView` to global scope and suppress auto-parsing of playlist nodes when in the admin. Allow `WPPlaylistView` to be passed `metadata` on creation instead of requiring a JSON blob to be parsed.
* Remove all of the playlist logic from the `wpgallery` TinyMCE plugin.
* In `wp_prepare_attachment_for_js()` return more data for audio/video so that playlists can have parity in the admin/front end.
See #27320.
git-svn-id: https://develop.svn.wordpress.org/trunk@27640 602fd350-edb4-49c9-b593-d223f7449a82
Diffstat (limited to 'src')
-rw-r--r-- | src/wp-includes/js/media-audiovideo.js | 154 | ||||
-rw-r--r-- | src/wp-includes/js/media-editor.js | 18 | ||||
-rw-r--r-- | src/wp-includes/js/mediaelement/wp-playlist.js | 16 | ||||
-rw-r--r-- | src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js | 47 | ||||
-rw-r--r-- | src/wp-includes/js/tinymce/skins/wordpress/wp-content.css | 18 | ||||
-rw-r--r-- | src/wp-includes/media-template.php | 40 | ||||
-rw-r--r-- | src/wp-includes/media.php | 43 | ||||
-rw-r--r-- | src/wp-includes/script-loader.php | 2 |
8 files changed, 258 insertions, 80 deletions
diff --git a/src/wp-includes/js/media-audiovideo.js b/src/wp-includes/js/media-audiovideo.js index 182cc158da..261be871bc 100644 --- a/src/wp-includes/js/media-audiovideo.js +++ b/src/wp-includes/js/media-audiovideo.js @@ -207,10 +207,11 @@ defaults : { id : wp.media.view.settings.post.id, - src : '', - loop : false, + src : '', + loop : false, autoplay : false, - preload : 'none' + preload : 'none', + caption : '' }, edit : function (data) { @@ -227,7 +228,7 @@ return frame; }, - update : function (model) { + shortcode : function (model) { var self = this, content; _.each( this.defaults, function( value, key ) { @@ -266,7 +267,8 @@ loop : false, autoplay : false, preload : 'metadata', - content : '' + content : '', + caption : '' }, edit : function (data) { @@ -287,7 +289,7 @@ return frame; }, - update : function (model) { + shortcode : function (model) { var self = this, content; _.each( this.defaults, function( value, key ) { @@ -1129,13 +1131,13 @@ wp.media.mixin.pauseAllPlayers(); - data = window.decodeURIComponent( $( node ).data('wpview-text') ); + data = window.decodeURIComponent( $( node ).attr('data-wpview-text') ); frame = media.edit( data ); frame.on( 'close', function () { frame.detach(); } ); - frame.state( self.shortcode + '-details' ).on( 'update', function( selection ) { - var shortcode = wp.media[ self.shortcode ].update( selection ).string(); + frame.state( self.state ).on( 'update', function( selection ) { + var shortcode = wp.media[ self.shortcode ].shortcode( selection ).string(); $( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) ); wp.mce.views.refreshView( self, shortcode ); frame.detach(); @@ -1205,6 +1207,7 @@ wp.mce.video = _.extend( {}, wp.mce.media, { shortcode: 'video', + state: 'video-details', View: wp.mce.media.View.extend({ className: 'editor-video', template: media.template('editor-video') @@ -1215,6 +1218,7 @@ wp.mce.audio = _.extend( {}, wp.mce.media, { shortcode: 'audio', + state: 'audio-details', View: wp.mce.media.View.extend({ className: 'editor-audio', template: media.template('editor-audio') @@ -1223,6 +1227,138 @@ wp.mce.views.register( 'audio', wp.mce.audio ); + wp.mce.media.PlaylistView = wp.mce.View.extend({ + className: 'editor-playlist', + template: media.template('editor-playlist'), + + initialize: function( options ) { + this.data = {}; + this.attachments = []; + this.shortcode = options.shortcode; + _.bindAll( this, 'setPlayer' ); + $(this).on('ready', this.setNode); + }, + + setNode: function (e, node) { + this.node = node; + this.fetch(); + }, + + fetch: function() { + this.attachments = wp.media[ this.shortcode.tag ].attachments( this.shortcode ); + this.attachments.more().done( this.setPlayer ); + }, + + setPlayer: function () { + var p, + html = this.getHtml(), + t = this.encodedText, + self = this; + + this.unsetPlayer(); + + _.each( tinymce.editors, function( editor ) { + var doc; + if ( editor.plugins.wpview ) { + doc = editor.getDoc(); + $( doc ).find( '[data-wpview-text="' + t + '"]' ).each(function (i, elem) { + var node = $( elem ); + node.html( html ); + self.node = elem; + }); + } + }, this ); + + p = new WPPlaylistView({ + el: $( self.node ).find( '.wp-playlist' ).get(0), + metadata: this.data + }); + + this.player = p._player; + }, + + getHtml: function() { + var data = this.shortcode.attrs.named, + model = wp.media[ this.shortcode.tag ], + type = 'playlist' === this.shortcode.tag ? 'audio' : 'video', + options, + attachments, + tracks = []; + + if ( ! this.attachments.length ) { + return; + } + + _.each( model.defaults, function( value, key ) { + data[ key ] = model.coerce( data, key ); + }); + + attachments = this.attachments.toJSON(); + + options = { + type: type, + style: data.style, + tracklist: data.tracklist, + tracknumbers: data.tracknumbers, + images: data.images, + artists: data.artists + }; + + _.each( attachments, function (attachment) { + var size = {}, track = { + src : attachment.url, + type : attachment.mime, + title : attachment.title, + caption : attachment.caption, + description : attachment.description, + meta : attachment.meta + }; + + if ( 'video' === type ) { + if ( ! options.width ) { + options.width = attachment.width; + options.height = attachment.height; + } + size.width = attachment.width; + size.height = attachment.height; + track.dimensions = { + original : size, + resized : size + }; + } else { + options.width = 400; + } + + track.image = attachment.image; + track.thumb = attachment.thumb; + + tracks.push( track ); + } ); + + options.tracks = tracks; + this.data = options; + + return this.template( options ); + } + }); + _.extend( wp.mce.media.PlaylistView.prototype, wp.media.mixin ); + + wp.mce.playlist = _.extend( {}, wp.mce.media, { + shortcode: 'playlist', + state: 'playlist-edit', + View: wp.mce.media.PlaylistView + } ); + + wp.mce.views.register( 'playlist', wp.mce.playlist ); + + wp.mce['video-playlist'] = _.extend( {}, wp.mce.media, { + shortcode: 'video-playlist', + state: 'video-playlist-edit', + View: wp.mce.media.PlaylistView + } ); + + wp.mce.views.register( 'video-playlist', wp.mce['video-playlist'] ); + function init() { $(document.body) .on( 'click', '.wp-switch-editor', wp.media.mixin.pauseAllPlayers ) diff --git a/src/wp-includes/js/media-editor.js b/src/wp-includes/js/media-editor.js index d0b4308810..f7253b7969 100644 --- a/src/wp-includes/js/media-editor.js +++ b/src/wp-includes/js/media-editor.js @@ -198,6 +198,23 @@ } } + if ( ! _.isEmpty( attachment.caption ) ) { + shortcode.caption = attachment.caption; + } else if ( attachment.meta && attachment.meta.title ) { + shortcode.caption = '“' + attachment.meta.title + '”'; + if ( attachment.meta.album ) { + shortcode.caption += ' from ' + attachment.meta.album; + } + + if ( attachment.meta.artist ) { + shortcode.caption += ' by ' + attachment.meta.artist; + } + } else if ( ! _.isEmpty( attachment.description ) ) { + shortcode.caption = attachment.description; + } else { + shortcode.caption = attachment.title; + } + extension = attachment.filename.split('.').pop(); if ( _.contains( wp.media.view.settings.embedExts, extension ) ) { @@ -387,6 +404,7 @@ if ( attachments[this.tag] ) { _.extend( attrs, attachments[this.tag].toJSON() ); } + // Convert all gallery shortcodes to use the `ids` property. // Ignore `post__in` and `post__not_in`; the attachments in // the collection will already reflect those properties. diff --git a/src/wp-includes/js/mediaelement/wp-playlist.js b/src/wp-includes/js/mediaelement/wp-playlist.js index 6c19e1da5f..bfe75c2bb0 100644 --- a/src/wp-includes/js/mediaelement/wp-playlist.js +++ b/src/wp-includes/js/mediaelement/wp-playlist.js @@ -8,10 +8,10 @@ itemTemplate : wp.template('wp-playlist-item'), - initialize : function () { + initialize : function (options) { var settings = {}; - this.data = $.parseJSON( this.$('script').html() ); + this.data = options.metadata || $.parseJSON( this.$('script').html() ); this.playerNode = this.$( this.data.type ); this.tracks = new Backbone.Collection( this.data.tracks ); @@ -38,7 +38,7 @@ } settings.success = this.bindPlayer; - new MediaElementPlayer( this.playerNode.get(0), settings ); + this._player = new MediaElementPlayer( this.playerNode.get(0), settings ); }, renderCurrent : function () { @@ -132,9 +132,13 @@ }); $(document).ready(function () { - $('.wp-playlist').each(function () { - return new WPPlaylistView({ el: this }); - }); + if ( ! $( 'body' ).hasClass('wp-admin') ) { + $('.wp-playlist').each(function () { + return new WPPlaylistView({ el: this }); + }); + } }); + window.WPPlaylistView = WPPlaylistView; + }(jQuery, _, Backbone));
\ No newline at end of file diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js b/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js index 2f0912873b..7f82e3575f 100644 --- a/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js +++ b/src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js @@ -13,28 +13,6 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { 'data-wp-media="' + data + '" data-mce-resize="false" data-mce-placeholder="1" />'; } - function replaceCallback( match, type, close ) { - var index; - - if ( close && close.indexOf( '[' + type ) > -1 ) { - index = match.length - close.length; - return html( 'wp-' + type, match.substring( 0, index ) ) + match.substring( index ); - } - - return html( 'wp-' + type, match ); - } - - function replaceAVShortcodes( content ) { - var testRegex = /\[(video-playlist|playlist)[^\]]*\]/, - replaceRegex = /\[(video-playlist|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/; - - while ( testRegex.test( content ) ) { - content = content.replace( replaceRegex, replaceCallback ); - } - - return content; - } - function restoreMediaShortcodes( content ) { function getAttr( str, name ) { name = new RegExp( name + '=\"([^\"]+)\"' ).exec( str ); @@ -76,25 +54,6 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); frame.detach(); }); - } else if ( editor.dom.hasClass( node, 'wp-playlist' ) && wp.media.playlist ) { - frame = wp.media.playlist.edit( data ); - - frame.state('playlist-edit').on( 'update', function( selection ) { - var shortcode = wp.media.playlist.shortcode( selection ).string(); - editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); - frame.detach(); - }); - } else if ( editor.dom.hasClass( node, 'wp-video-playlist' ) && wp.media['video-playlist'] ) { - frame = wp.media['video-playlist'].edit( data ); - - frame.state('video-playlist-edit').on( 'update', function( selection ) { - var shortcode = wp.media['video-playlist'].shortcode( selection ).string(); - editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); - frame.detach(); - }); - } else { - // temp - window.console && window.console.log( 'Edit AV shortcode ' + data ); } } @@ -152,10 +111,6 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { if ( node.nodeName === 'IMG' && dom.getAttrib( node, 'data-wp-media' ) ) { if ( dom.hasClass( node, 'wp-gallery' ) ) { event.name = 'gallery'; - } else if ( dom.hasClass( node, 'wp-playlist' ) ) { - event.name = 'playlist'; - } else if ( dom.hasClass( node, 'wp-video-playlist' ) ) { - event.name = 'video-playlist'; } } }); @@ -165,8 +120,6 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { if ( ! editor.plugins.wpview ) { event.content = replaceGalleryShortcodes( event.content ); } - - event.content = replaceAVShortcodes( event.content ); }); editor.on( 'PostProcess', function( event ) { diff --git a/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css b/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css index 6ee1e2f931..f758542193 100644 --- a/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css +++ b/src/wp-includes/js/tinymce/skins/wordpress/wp-content.css @@ -141,14 +141,6 @@ img::selection { background-image: url(images/gallery.png); } -.mce-content-body img.wp-media.wp-playlist { - background-image: url("images/playlist-audio.png"); -} - -.mce-content-body img.wp-media.wp-video-playlist { - background-image: url("images/playlist-video.png"); -} - /* Image resize handles */ .mce-content-body div.mce-resizehandle { border-color: #777; @@ -299,6 +291,16 @@ embed { border-color: rgba(0,0,0,0.3); } +.wpview-type-audio .track-details { + position: absolute; + top: 0; + left: 5px; + width: 85%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + .gallery img[data-mce-selected]:focus { outline: none; } diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php index 9f72f176f6..add9940006 100644 --- a/src/wp-includes/media-template.php +++ b/src/wp-includes/media-template.php @@ -814,7 +814,7 @@ function wp_print_media_templates() { <div class="setting preload"> <span><?php _e( 'Preload' ); ?></span> <div class="button-group button-large" data-setting="preload"> - <button class="button" value="auto"><?php _ex( 'Auto', 'auto preload video' ); ?></button> + <button class="button" value="auto"><?php _ex( 'Auto', 'auto preload audio' ); ?></button> <button class="button" value="metadata"><?php _e( 'Metadata' ); ?></button> <button class="button active" value="none"><?php _e( 'None' ); ?></button> </div> @@ -829,6 +829,12 @@ function wp_print_media_templates() { <span><?php _e( 'Loop' ); ?></span> <input type="checkbox" data-setting="loop" /> </label> + + <label class="setting"> + <span><?php _e( 'Caption' ); ?></span> + <input type="text" data-setting="caption" value="{{ data.model.caption }}" /> + </label> + <div class="clear"></div> </div> </div> @@ -901,7 +907,7 @@ function wp_print_media_templates() { <div class="setting preload"> <span><?php _e( 'Preload' ); ?></span> <div class="button-group button-large" data-setting="preload"> - <button class="button" value="auto"><?php _e( 'Auto' ); ?></button> + <button class="button" value="auto"><?php _ex( 'Auto', 'auto preload video' ); ?></button> <button class="button" value="metadata"><?php _e( 'Metadata' ); ?></button> <button class="button active" value="none"><?php _e( 'None' ); ?></button> </div> @@ -936,6 +942,11 @@ function wp_print_media_templates() { <# } #> <textarea class="hidden content-setting">{{ content }}</textarea> </label> + + <label class="setting"> + <span><?php _e( 'Caption' ); ?></span> + <input type="text" data-setting="caption" value="{{ data.model.caption }}" /> + </label> </div> </div> </script> @@ -966,6 +977,9 @@ function wp_print_media_templates() { <div class="dashicons dashicons-edit edit"></div> <div class="dashicons dashicons-no-alt remove"></div> </div> + <# if ( ! _.isEmpty( data.model.caption ) ) { #> + <div class="track-details">{{{ data.model.caption }}}</div> + <# } #> <?php wp_underscore_audio_template() ?> </script> @@ -974,9 +988,31 @@ function wp_print_media_templates() { <div class="dashicons dashicons-edit edit"></div> <div class="dashicons dashicons-no-alt remove"></div> </div> + <# if ( ! _.isEmpty( data.model.caption ) ) { #> + <div class="track-details">{{{ data.model.caption }}}</div> + <# } #> <?php wp_underscore_video_template() ?> </script> + <?php wp_underscore_playlist_templates() ?> + + <script type="text/html" id="tmpl-editor-playlist"> + <div class="toolbar"> + <div class="dashicons dashicons-edit edit"></div> + <div class="dashicons dashicons-no-alt remove"></div> + </div> + <div class="wp-playlist wp-{{ data.type }}-playlist wp-playlist-{{ data.style }}"> + <# if ( 'audio' === data.type ){ #> + <div class="wp-playlist-current-item"></div> + <# } #> + <{{ data.type }} controls="controls" preload="none" <# + if ( data.width ) { #> width="{{ data.width }}"<# } + #><# if ( data.height ) { #> height="{{ data.height }}"<# } #>></{{ data.type }}> + <div class="wp-playlist-next"></div> + <div class="wp-playlist-prev"></div> + </div> + </script> + <?php /** diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index a1afae1698..a7eea4e996 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -999,17 +999,12 @@ function gallery_shortcode( $attr ) { } /** - * Output and enqueue default scripts and styles for playlists. + * Output the templates used by playlists * * @since 3.9.0 - * - * @param string $type Type of playlist: "audio" or "video." */ -function wp_playlist_scripts( $type ) { - wp_enqueue_style( 'wp-mediaelement' ); - wp_enqueue_script( 'wp-playlist' ); +function wp_underscore_playlist_templates() { ?> -<!--[if lt IE 9]><script>document.createElement('<?php echo esc_js( $type ) ?>');</script><![endif]--> <script type="text/html" id="tmpl-wp-playlist-current-item"> <# if ( data.image ) { #> <img src="{{{ data.thumb.src }}}"/> @@ -1045,6 +1040,22 @@ function wp_playlist_scripts( $type ) { </script> <?php } + +/** + * Output and enqueue default scripts and styles for playlists. + * + * @since 3.9.0 + * + * @param string $type Type of playlist: "audio" or "video." + */ +function wp_playlist_scripts( $type ) { + wp_enqueue_style( 'wp-mediaelement' ); + wp_enqueue_script( 'wp-playlist' ); +?> +<!--[if lt IE 9]><script>document.createElement('<?php echo esc_js( $type ) ?>');</script><![endif]--> +<?php + wp_underscore_playlist_templates(); +} add_action( 'wp_playlist_scripts', 'wp_playlist_scripts' ); /** @@ -1390,6 +1401,7 @@ function wp_audio_shortcode( $attr, $content = '' ) { $default_types = wp_get_audio_extensions(); $defaults_atts = array( + 'caption' => '', 'src' => '', 'loop' => '', 'autoplay' => '', @@ -1549,6 +1561,7 @@ function wp_video_shortcode( $attr, $content = '' ) { $default_types = wp_get_video_extensions(); $defaults_atts = array( + 'caption' => '', 'src' => '', 'poster' => '', 'loop' => '', @@ -2332,6 +2345,22 @@ function wp_prepare_attachment_for_js( $attachment ) { if ( $meta && ( 'audio' === $type || 'video' === $type ) ) { if ( isset( $meta['length_formatted'] ) ) $response['fileLength'] = $meta['length_formatted']; + + $response['meta'] = array(); + $keys = array( 'title', 'artist', 'band', 'album', 'genre', 'year', 'length', 'length_formatted' ); + foreach ( $keys as $key ) { + if ( ! empty( $meta[ $key ] ) ) { + $response['meta'][ $key ] = $meta[ $key ]; + } + } + + $id = get_post_thumbnail_id( $attachment->ID ); + if ( ! empty( $id ) ) { + list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' ); + $response['image'] = compact( 'src', 'width', 'height' ); + list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumbnail' ); + $response['thumb'] = compact( 'src', 'width', 'height' ); + } } if ( function_exists('get_compat_media_markup') ) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index ff2544ab59..77121f4f87 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -396,7 +396,7 @@ function wp_default_scripts( &$scripts ) { // Both rely on numerous settings, styles, and templates to operate correctly. $scripts->add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement' ), false, 1 ); $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 ); - $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor', 'mce-view' ), false, 1 ); + $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor', 'mce-view', 'wp-playlist' ), false, 1 ); $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 ); if ( is_admin() ) { |