Ticket #26631: 26631.6.diff
File 26631.6.diff, 57.3 KB (added by , 10 years ago) |
---|
-
src/wp-content/themes/twentyfourteen/functions.php
111 111 'max_posts' => 6, 112 112 ) ); 113 113 114 add_post_type_support( 'attachment:audio', 'thumbnail' ); 115 add_post_type_support( 'attachment:video', 'thumbnail' ); 116 add_theme_support( 'post-thumbnails', array( 'post', 'attachment:audio', 'attachment:video' ) ); 117 114 118 // This theme uses its own gallery styles. 115 119 add_filter( 'use_default_gallery_style', '__return_false' ); 116 120 } -
src/wp-includes/css/editor.css
833 833 } 834 834 835 835 #wp_editbtns, 836 #wp_gallerybtns { 836 #wp_gallerybtns, 837 #wp_playlistbtns { 837 838 padding: 2px; 838 839 position: absolute; 839 840 display: none; … … 843 844 #wp_editimgbtn, 844 845 #wp_delimgbtn, 845 846 #wp_editgallery, 846 #wp_delgallery { 847 #wp_delgallery, 848 #wp_editplaylist, 849 #wp_delplaylist { 847 850 border-color: #999; 848 851 background-color: #eee; 849 852 margin: 2px; … … 857 860 #wp_editimgbtn:hover, 858 861 #wp_delimgbtn:hover, 859 862 #wp_editgallery:hover, 860 #wp_delgallery:hover { 863 #wp_delgallery:hover, 864 #wp_editplaylist:hover, 865 #wp_delplaylist:hover { 861 866 border-color: #555; 862 867 background-color: #ccc; 863 868 } -
src/wp-includes/css/media-views.css
592 592 box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 ); 593 593 } 594 594 595 .media-frame .media-toolbar .add-to-gallery { 595 .media-frame .media-toolbar .add-to-gallery, 596 .media-frame .media-toolbar .add-to-playlist { 596 597 display: none; 597 598 } 598 599 … … 1424 1425 margin: 1.4em 0 0.4em; 1425 1426 } 1426 1427 1427 .gallery-settings {1428 .gallery-settings, .playlist-settings { 1428 1429 overflow: hidden; 1429 1430 } 1430 1431 … … 1883 1884 border-top: none; 1884 1885 } 1885 1886 1886 .gallery-settings h3 {1887 .gallery-settings h3, .playlist-settings h3 { 1887 1888 margin-top: 45px; 1888 1889 } 1889 1890 -
src/wp-includes/js/media-editor.js
8 8 * 9 9 * @static 10 10 */ 11 var workflows = {} ;11 var workflows = {}, cache = {}; 12 12 13 13 /** 14 14 * wp.media.string … … 273 273 return html; 274 274 } 275 275 }; 276 277 276 /** 278 * wp.media. gallery277 * wp.media.collection 279 278 * @namespace 280 279 */ 281 wp.media.gallery = (function() { 282 /** 283 * 284 * @static 285 * @type object 286 */ 287 var galleries = {}; 280 wp.media.collection = { 281 attachments : function ( prop, type ) { 282 return function( shortcode ) { 283 var shortcodeString = shortcode.string(), 284 result = cache[ shortcodeString ], 285 attrs, args, query, others; 288 286 289 return { 290 /** 291 * Default gallery properties 292 * 293 * @global wp.media.view.settings 294 * @readonly 295 */ 296 defaults: { 297 order: 'ASC', 298 id: wp.media.view.settings.post.id, 299 itemtag: 'dl', 300 icontag: 'dt', 301 captiontag: 'dd', 302 columns: '3', 303 link: 'post', 304 size: 'thumbnail', 305 orderby: 'menu_order ID' 306 }, 307 /** 308 * Retrieve attachments based on the properties of the passed shortcode 309 * 310 * @global wp.media.query 311 * 312 * @param {wp.shortcode} shortcode An instance of wp.shortcode(). 313 * @returns {wp.media.model.Attachments} A Backbone.Collection containing 314 * the images belonging to a gallery. The 'gallery' prop is a Backbone.Model 315 * containing the 'props' for the gallery. 316 */ 317 attachments: function( shortcode ) { 318 var shortcodeString = shortcode.string(), 319 result = galleries[ shortcodeString ], 320 attrs, args, query, others; 287 delete cache[ shortcodeString ]; 321 288 322 delete galleries[ shortcodeString ]; 323 324 if ( result ) { 325 return result; 289 if ( result ) { 290 return result; 326 291 } 327 292 328 // Fill the default shortcode attributes.329 attrs = _.defaults( shortcode.attrs.named, wp.media.gallery.defaults );330 args = _.pick( attrs, 'orderby', 'order' );293 // Fill the default shortcode attributes. 294 attrs = _.defaults( shortcode.attrs.named, this.defaults ); 295 args = _.pick( attrs, 'orderby', 'order' ); 331 296 332 args.type = 'image';333 args.perPage = -1;297 args.type = type; 298 args.perPage = -1; 334 299 335 // Mark the `orderby` override attribute.336 if( undefined !== attrs.orderby ) {337 attrs._orderByField = attrs.orderby;300 // Mark the `orderby` override attribute. 301 if ( undefined !== attrs.orderby ) { 302 attrs._orderByField = attrs.orderby; 338 303 } 304 339 305 if ( 'rand' === attrs.orderby ) { 340 306 attrs._orderbyRandom = true; 341 307 } … … 365 331 others = _.omit( attrs, 'id', 'ids', 'include', 'exclude', 'orderby', 'order' ); 366 332 367 333 query = wp.media.query( args ); 368 query .gallery= new Backbone.Model( others );334 query[ prop ] = new Backbone.Model( others ); 369 335 return query; 370 }, 371 /** 372 * Triggered when clicking 'Insert Gallery' or 'Update Gallery' 373 * 374 * @global wp.shortcode 375 * @global wp.media.model.Attachments 376 * 377 * @param {wp.media.model.Attachments} attachments A Backbone.Collection containing 378 * the images belonging to a gallery. The 'gallery' prop is a Backbone.Model 379 * containing the 'props' for the gallery. 380 * @returns {wp.shortcode} 381 */ 382 shortcode: function( attachments ) { 383 var props = attachments.props.toJSON(), 384 attrs = _.pick( props, 'orderby', 'order' ), 385 shortcode, clone; 336 }; 337 }, 386 338 387 if ( attachments.gallery) {388 _.extend( attrs, attachments.gallery.toJSON() ); 389 } 339 shortcodeAttrs : function ( prop, attachments ) { 340 var props = attachments.props.toJSON(), 341 attrs = _.pick( props, 'orderby', 'order', 'style' ); 390 342 391 // Convert all gallery shortcodes to use the `ids` property. 392 // Ignore `post__in` and `post__not_in`; the attachments in 393 // the collection will already reflect those properties. 394 attrs.ids = attachments.pluck('id'); 343 if ( attachments[ prop ] ) { 344 _.extend( attrs, attachments[ prop ].toJSON() ); 345 } 395 346 396 // Copy the `uploadedTo` post ID.397 if ( props.uploadedTo ) { 398 attrs.id = props.uploadedTo; 399 } 347 // Convert all collection shortcodes to use the `ids` property. 348 // Ignore `post__in` and `post__not_in`; the attachments in 349 // the collection will already reflect those properties. 350 attrs.ids = attachments.pluck('id'); 400 351 401 // Check if the gallery is randomly ordered. 402 delete attrs.orderby; 352 // Copy the `uploadedTo` post ID. 353 if ( props.uploadedTo ) { 354 attrs.id = props.uploadedTo; 355 } 403 356 404 if ( attrs._orderbyRandom ) { 405 attrs.orderby = 'rand'; 406 } else if ( attrs._orderByField && attrs._orderByField != 'rand' ) { 407 attrs.orderby = attrs._orderByField; 408 } 357 // Check if the collection is randomly ordered. 358 delete attrs.orderby; 409 359 410 delete attrs._orderbyRandom; 411 delete attrs._orderByField; 360 if ( attrs._orderbyRandom ) { 361 attrs.orderby = 'rand'; 362 } else if ( attrs._orderByField && attrs._orderByField != 'rand' ) { 363 attrs.orderby = attrs._orderByField; 364 } 412 365 413 // If the `ids` attribute is set and `orderby` attribute 414 // is the default value, clear it for cleaner output. 415 if ( attrs.ids && 'post__in' === attrs.orderby ) { 416 delete attrs.orderby; 417 } 366 delete attrs._orderbyRandom; 367 delete attrs._orderByField; 418 368 419 // Remove default attributes from the shortcode. 420 _.each( wp.media.gallery.defaults, function( value, key ) { 421 if ( value === attrs[ key ] ) 422 delete attrs[ key ];423 });369 // If the `ids` attribute is set and `orderby` attribute 370 // is the default value, clear it for cleaner output. 371 if ( attrs.ids && 'post__in' === attrs.orderby ) { 372 delete attrs.orderby; 373 } 424 374 425 shortcode = new wp.shortcode({ 426 tag: 'gallery', 427 attrs: attrs, 428 type: 'single' 429 }); 375 // Remove default attributes from the shortcode. 376 _.each( this.defaults, function( value, key ) { 377 if ( value === attrs[ key ] ) { 378 delete attrs[ key ]; 379 } 380 }); 430 381 431 // Use a cloned version of the gallery. 432 clone = new wp.media.model.Attachments( attachments.models, { 433 props: props 434 }); 435 clone.gallery = attachments.gallery; 436 galleries[ shortcode.string() ] = clone; 382 return attrs; 383 }, 437 384 438 return shortcode; 439 }, 440 /** 441 * Triggered when double-clicking a Gallery shortcode placeholder 442 * in the editor 443 * 444 * @global wp.shortcode 445 * @global wp.media.model.Selection 446 * @global wp.media.view.l10n 447 * 448 * @param {string} content Content that is searched for possible 449 * shortcode markup matching the passed tag name, 450 * 451 * @this wp.media.gallery 452 * 453 * @returns {wp.media.view.MediaFrame.Select} A media workflow. 454 */ 455 edit: function( content ) { 456 var shortcode = wp.shortcode.next( 'gallery', content ), 457 defaultPostId = wp.media.gallery.defaults.id, 458 attachments, selection; 385 editSelection : function ( prop, shortcode ) { 386 var defaultPostId = wp.media[ prop ].defaults.id, 387 attachments, selection; 459 388 460 // Bail if we didn't match the shortcode or all of the content. 461 if ( ! shortcode || shortcode.content !== content ) { 462 return; 463 } 389 // Ignore the rest of the match object. 390 shortcode = shortcode.shortcode; 464 391 465 // Ignore the rest of the match object. 466 shortcode = shortcode.shortcode; 392 if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) { 393 shortcode.set( 'id', defaultPostId ); 394 } 467 395 468 if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) { 469 shortcode.set( 'id', defaultPostId ); 470 } 396 attachments = wp.media[ prop ].attachments( shortcode ); 471 397 472 attachments = wp.media.gallery.attachments( shortcode ); 398 selection = new wp.media.model.Selection( attachments.models, { 399 props: attachments.props.toJSON(), 400 multiple: true 401 }); 473 402 474 selection = new wp.media.model.Selection( attachments.models, { 475 props: attachments.props.toJSON(), 476 multiple: true 477 }); 403 selection[ prop ] = attachments[ prop ]; 478 404 479 selection.gallery = attachments.gallery; 405 // Fetch the query's attachments, and then break ties from the 406 // query to allow for sorting. 407 selection.more().done( function() { 408 // Break ties with the query. 409 selection.props.set({ query: false }); 410 selection.unmirror(); 411 selection.props.unset('orderby'); 412 }); 480 413 481 // Fetch the query's attachments, and then break ties from the 482 // query to allow for sorting. 483 selection.more().done( function() { 484 // Break ties with the query. 485 selection.props.set({ query: false }); 486 selection.unmirror(); 487 selection.props.unset('orderby'); 488 }); 414 return selection; 415 }, 489 416 490 // Destroy the previous gallery frame. 491 if ( this.frame ) { 492 this.frame.dispose(); 493 } 417 cacheShortcode : function ( prop, attachments, shortcode ) { 418 // Use a cloned version of the playlist. 419 var clone = new wp.media.model.Attachments( attachments.models, { 420 props: attachments.props.toJSON() 421 }); 422 clone[ prop ] = attachments[ prop ]; 423 cache[ shortcode.string() ] = clone; 494 424 495 // Store the current gallery frame. 496 this.frame = wp.media({ 497 frame: 'post', 498 state: 'gallery-edit', 499 title: wp.media.view.l10n.editGalleryTitle, 500 editing: true, 501 multiple: true, 502 selection: selection 503 }).open(); 425 return shortcode; 426 }, 504 427 505 return this.frame; 428 getEditFrame : function ( args ) { 429 // Destroy the previous gallery frame. 430 if ( this.frame ) { 431 this.frame.dispose(); 506 432 } 507 };508 }());509 433 434 // Store the current gallery frame. 435 this.frame = wp.media( _.extend( { 436 frame: 'post', 437 editing: true, 438 multiple: true, 439 }, args ) ).open(); 440 441 return this.frame; 442 }, 443 444 instance : function ( prop, args ) { 445 return { 446 attachments: this.attachments( prop, args.type ), 447 shortcode: function( attachments ) { 448 var shortcode = new wp.shortcode({ 449 tag: prop, 450 attrs: wp.media.collection.shortcodeAttrs( prop, attachments ), 451 type: 'single' 452 }); 453 454 return wp.media.collection.cacheShortcode( prop, attachments, shortcode ); 455 }, 456 edit: function( content ) { 457 var shortcode = wp.shortcode.next( prop, content ); 458 459 // Bail if we didn't match the shortcode or all of the content. 460 if ( ! shortcode || shortcode.content !== content ) { 461 return; 462 } 463 464 return wp.media.collection.getEditFrame( { 465 title: args.title, 466 state: prop + '-edit', 467 selection: wp.media.collection.editSelection( prop, shortcode ) 468 } ); 469 } 470 }; 471 } 472 }; 473 474 wp.media.gallery = (function() { 475 var gallery = { 476 defaults : { 477 itemtag: 'dl', 478 icontag: 'dt', 479 captiontag: 'dd', 480 columns: '3', 481 link: 'post', 482 size: 'thumbnail', 483 order: 'ASC', 484 id: wp.media.view.settings.post.id, 485 orderby : 'menu_order ID' 486 } 487 }; 488 489 return _.extend(gallery, wp.media.collection.instance( 'gallery', { 490 type : 'image', 491 title : wp.media.view.l10n.editGalleryTitle 492 })); 493 }()); 494 495 wp.media.playlist = (function() { 496 var playlist = { 497 defaults : { 498 id: wp.media.view.settings.post.id, 499 style: 'light', 500 tracklist: true, 501 tracknumbers: true 502 } 503 }; 504 505 return _.extend(playlist, wp.media.collection.instance( 'playlist', { 506 type : 'audio', 507 title : wp.media.view.l10n.editPlaylistTitle 508 })); 509 }()); 510 511 wp.media['video-playlist'] = (function() { 512 var playlist = { 513 defaults : { 514 id: wp.media.view.settings.post.id, 515 style: 'dark', 516 tracklist: false, 517 tracknumbers: false 518 } 519 }; 520 521 return _.extend(playlist, wp.media.collection.instance( 'video-playlist', { 522 type : 'video', 523 title : wp.media.view.l10n.editVideoPlaylistTitle 524 })); 525 }()); 526 510 527 /** 511 528 * wp.media.featuredImage 512 529 * @namespace … … 725 742 this.insert( wp.media.gallery.shortcode( selection ).string() ); 726 743 }, this ); 727 744 745 workflow.state('playlist-edit').on( 'update', function( selection ) { 746 this.insert( wp.media.playlist.shortcode( selection ).string() ); 747 }, this ); 748 749 workflow.state('video-playlist-edit').on( 'update', function( selection ) { 750 this.insert( wp.media['video-playlist'].shortcode( selection ).string() ); 751 }, this ); 752 728 753 workflow.state('embed').on( 'select', function() { 729 754 /** 730 755 * @this wp.media.editor … … 964 989 if ( elem.hasClass( 'gallery' ) ) { 965 990 options.state = 'gallery'; 966 991 options.title = wp.media.view.l10n.createGalleryTitle; 992 } else if ( elem.hasClass( 'playlist' ) ) { 993 options.state = 'playlist'; 994 options.title = wp.media.view.l10n.createPlaylistTitle; 995 } else if ( elem.hasClass( 'video-playlist' ) ) { 996 options.state = 'video-playlist'; 997 options.title = wp.media.view.l10n.createVideoPlaylistTitle; 967 998 } 968 999 969 1000 wp.media.editor.open( editor, options ); -
src/wp-includes/js/media-views.js
760 760 }); 761 761 762 762 /** 763 * wp.media.controller.GalleryEdit764 *765 * @constructor766 * @augments wp.media.controller.Library767 * @augments wp.media.controller.State768 * @augments Backbone.Model769 */770 media.controller.GalleryEdit = media.controller.Library.extend({771 defaults: {772 id: 'gallery-edit',773 multiple: false,774 describe: true,775 edge: 199,776 editing: false,777 sortable: true,778 searchable: false,779 toolbar: 'gallery-edit',780 content: 'browse',781 title: l10n.editGalleryTitle,782 priority: 60,783 dragInfo: true,784 785 // Don't sync the selection, as the Edit Gallery library786 // *is* the selection.787 syncSelection: false788 },789 790 initialize: function() {791 // If we haven't been provided a `library`, create a `Selection`.792 if ( ! this.get('library') ) {793 this.set( 'library', new media.model.Selection() );794 }795 796 // The single `Attachment` view to be used in the `Attachments` view.797 if ( ! this.get('AttachmentView') ) {798 this.set( 'AttachmentView', media.view.Attachment.EditLibrary );799 }800 801 media.controller.Library.prototype.initialize.apply( this, arguments );802 },803 804 activate: function() {805 var library = this.get('library');806 807 // Limit the library to images only.808 library.props.set( 'type', 'image' );809 810 // Watch for uploaded attachments.811 this.get('library').observe( wp.Uploader.queue );812 813 this.frame.on( 'content:render:browse', this.gallerySettings, this );814 815 media.controller.Library.prototype.activate.apply( this, arguments );816 },817 818 deactivate: function() {819 // Stop watching for uploaded attachments.820 this.get('library').unobserve( wp.Uploader.queue );821 822 this.frame.off( 'content:render:browse', this.gallerySettings, this );823 824 media.controller.Library.prototype.deactivate.apply( this, arguments );825 },826 827 /**828 * @param {Object} browser829 */830 gallerySettings: function( browser ) {831 var library = this.get('library');832 833 if ( ! library || ! browser ) {834 return;835 }836 837 library.gallery = library.gallery || new Backbone.Model();838 839 browser.sidebar.set({840 gallery: new media.view.Settings.Gallery({841 controller: this,842 model: library.gallery,843 priority: 40844 })845 });846 847 browser.toolbar.set( 'reverse', {848 text: l10n.reverseOrder,849 priority: 80,850 851 click: function() {852 library.reset( library.toArray().reverse() );853 }854 });855 }856 });857 858 /**859 * wp.media.controller.GalleryAdd860 *861 * @constructor862 * @augments wp.media.controller.Library863 * @augments wp.media.controller.State864 * @augments Backbone.Model865 */866 media.controller.GalleryAdd = media.controller.Library.extend({867 defaults: _.defaults({868 id: 'gallery-library',869 filterable: 'uploaded',870 multiple: 'add',871 menu: 'gallery',872 toolbar: 'gallery-add',873 title: l10n.addToGalleryTitle,874 priority: 100,875 876 // Don't sync the selection, as the Edit Gallery library877 // *is* the selection.878 syncSelection: false879 }, media.controller.Library.prototype.defaults ),880 881 /**882 * If we haven't been provided a `library`, create a `Selection`.883 */884 initialize: function() {885 if ( ! this.get('library') ) {886 this.set( 'library', media.query({ type: 'image' }) );887 }888 media.controller.Library.prototype.initialize.apply( this, arguments );889 },890 891 activate: function() {892 var library = this.get('library'),893 edit = this.frame.state('gallery-edit').get('library');894 895 if ( this.editLibrary && this.editLibrary !== edit ) {896 library.unobserve( this.editLibrary );897 }898 899 // Accepts attachments that exist in the original library and900 // that do not exist in gallery's library.901 library.validator = function( attachment ) {902 return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) &&903 media.model.Selection.prototype.validator.apply( this, arguments );904 };905 906 // Reset the library to ensure that all attachments are re-added907 // to the collection. Do so silently, as calling `observe` will908 // trigger the `reset` event.909 library.reset( library.mirroring.models, { silent: true });910 library.observe( edit );911 this.editLibrary = edit;912 913 media.controller.Library.prototype.activate.apply( this, arguments );914 }915 });916 917 /**918 763 * wp.media.controller.FeaturedImage 919 764 * 920 765 * @constructor … … 993 838 } 994 839 }); 995 840 841 media.controller.CollectionEdit = function ( prop, args ) { 842 return media.controller.Library.extend({ 843 defaults : _.defaults(args.defaults || {}, { 844 id: prop + '-edit', 845 toolbar: prop + '-edit', 846 multiple: false, 847 describe: true, 848 edge: 199, 849 editing: false, 850 sortable: true, 851 searchable: false, 852 content: 'browse', 853 priority: 60, 854 dragInfo: true, 855 856 // Don't sync the selection, as the Edit {Collection} library 857 // *is* the selection. 858 syncSelection: false 859 }), 860 861 initialize: function() { 862 // If we haven't been provided a `library`, create a `Selection`. 863 if ( ! this.get('library') ) { 864 this.set( 'library', new media.model.Selection() ); 865 } 866 // The single `Attachment` view to be used in the `Attachments` view. 867 if ( ! this.get('AttachmentView') ) { 868 this.set( 'AttachmentView', media.view.Attachment.EditLibrary ); 869 } 870 media.controller.Library.prototype.initialize.apply( this, arguments ); 871 }, 872 873 activate: function() { 874 var library = this.get('library'); 875 876 // Limit the library to images only. 877 library.props.set( 'type', args.type ); 878 879 // Watch for uploaded attachments. 880 this.get('library').observe( wp.Uploader.queue ); 881 882 this.frame.on( 'content:render:browse', this.settings, this ); 883 884 media.controller.Library.prototype.activate.apply( this, arguments ); 885 }, 886 887 deactivate: function() { 888 // Stop watching for uploaded attachments. 889 this.get('library').unobserve( wp.Uploader.queue ); 890 891 this.frame.off( 'content:render:browse', this.settings, this ); 892 893 media.controller.Library.prototype.deactivate.apply( this, arguments ); 894 }, 895 896 settings: function( browser ) { 897 var library = this.get('library'), obj = {}; 898 899 if ( ! library || ! browser ) { 900 return; 901 } 902 903 library[ prop ] = library[ prop ] || new Backbone.Model(); 904 905 obj[ prop ] = new media.view.Settings[ args.settings ]({ 906 controller: this, 907 model: library[ prop ], 908 priority: 40 909 }); 910 911 browser.sidebar.set( obj ); 912 913 if ( args.dragInfoText ) { 914 browser.toolbar.set( 'dragInfo', new media.View({ 915 el: $( '<div class="instructions">' + args.dragInfoText + '</div>' )[0], 916 priority: -40 917 }) ); 918 } 919 920 browser.toolbar.set( 'reverse', { 921 text: l10n.reverseOrder, 922 priority: 80, 923 924 click: function() { 925 library.reset( library.toArray().reverse() ); 926 } 927 }); 928 } 929 }); 930 }; 931 932 media.controller.CollectionAdd = function ( prop, args ) { 933 return media.controller.Library.extend({ 934 defaults: _.defaults({ 935 id: prop + '-library', 936 filterable: 'uploaded', 937 multiple: 'add', 938 menu: prop, 939 toolbar: prop + '-add', 940 priority: 100, 941 syncSelection: false 942 }, args.defaults || {}, media.controller.Library.prototype.defaults ), 943 initialize: function() { 944 // If we haven't been provided a `library`, create a `Selection`. 945 if ( ! this.get('library') ) { 946 this.set( 'library', media.query({ type: args.type }) ); 947 } 948 media.controller.Library.prototype.initialize.apply( this, arguments ); 949 }, 950 951 activate: function() { 952 var library = this.get('library'), 953 edit = this.frame.state(prop + '-edit').get('library'); 954 955 if ( this.editLibrary && this.editLibrary !== edit ) { 956 library.unobserve( this.editLibrary ); 957 } 958 959 // Accepts attachments that exist in the original library and 960 // that do not exist in gallery's library. 961 library.validator = function( attachment ) { 962 return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && media.model.Selection.prototype.validator.apply( this, arguments ); 963 }; 964 965 // Reset the library to ensure that all attachments are re-added 966 // to the collection. Do so silently, as calling `observe` will 967 // trigger the `reset` event. 968 library.reset( library.mirroring.models, { silent: true }); 969 library.observe( edit ); 970 this.editLibrary = edit; 971 972 media.controller.Library.prototype.activate.apply( this, arguments ); 973 } 974 }); 975 }; 976 977 // wp.media.controller.GalleryEdit 978 // ------------------------------- 979 media.controller.GalleryEdit = media.controller.CollectionEdit( 'gallery', { 980 type: 'image', 981 settings: 'Gallery', 982 defaults: { 983 title: l10n.editGalleryTitle 984 } 985 }); 986 987 // wp.media.controller.GalleryAdd 988 // --------------------------------- 989 media.controller.GalleryAdd = media.controller.CollectionAdd( 'gallery', { 990 type: 'image', 991 defaults: { 992 title: l10n.addToGalleryTitle 993 } 994 }); 995 996 // wp.media.controller.PlaylistEdit 997 // ------------------------------- 998 media.controller.PlaylistEdit = media.controller.CollectionEdit( 'playlist', { 999 type: 'audio', 1000 settings: 'Playlist', 1001 dragInfoText: l10n.playlistDragInfo, 1002 defaults: { 1003 title: l10n.editPlaylistTitle, 1004 dragInfo : false 1005 } 1006 }); 1007 1008 // wp.media.controller.PlaylistAdd 1009 // --------------------------------- 1010 media.controller.PlaylistAdd = media.controller.CollectionAdd( 'playlist', { 1011 type: 'audio', 1012 defaults: { 1013 title: l10n.addToPlaylistTitle 1014 } 1015 }); 1016 1017 // wp.media.controller.VideoPlaylistEdit 1018 // ------------------------------- 1019 media.controller.VideoPlaylistEdit = media.controller.CollectionEdit( 'video-playlist', { 1020 type: 'video', 1021 settings: 'Playlist', 1022 dragInfoText: l10n.videoPlaylistDragInfo, 1023 defaults: { 1024 title: l10n.editVideoPlaylistTitle, 1025 dragInfo : false 1026 } 1027 }); 1028 1029 // wp.media.controller.VideoPlaylistAdd 1030 // --------------------------------- 1031 media.controller.VideoPlaylistAdd = media.controller.CollectionAdd( 'video-playlist', { 1032 type: 'video', 1033 defaults: { 1034 title: l10n.addToVideoPlaylistTitle 1035 } 1036 }); 1037 996 1038 /** 997 1039 * wp.media.controller.ReplaceImage 998 1040 * … … 1740 1782 menu: 'gallery' 1741 1783 }), 1742 1784 1743 new media.controller.GalleryAdd() 1785 new media.controller.GalleryAdd(), 1786 1787 new media.controller.Library({ 1788 id: 'playlist', 1789 title: l10n.createPlaylistTitle, 1790 priority: 60, 1791 toolbar: 'main-playlist', 1792 filterable: 'uploaded', 1793 multiple: 'add', 1794 editable: false, 1795 1796 library: media.query( _.defaults({ 1797 type: 'audio' 1798 }, options.library ) ) 1799 }), 1800 1801 // Playlist states. 1802 new media.controller.PlaylistEdit({ 1803 library: options.selection, 1804 editing: options.editing, 1805 menu: 'playlist' 1806 }), 1807 1808 new media.controller.PlaylistAdd(), 1809 1810 new media.controller.Library({ 1811 id: 'video-playlist', 1812 title: l10n.createVideoPlaylistTitle, 1813 priority: 60, 1814 toolbar: 'main-video-playlist', 1815 filterable: 'uploaded', 1816 multiple: 'add', 1817 editable: false, 1818 1819 library: media.query( _.defaults({ 1820 type: 'video' 1821 }, options.library ) ) 1822 }), 1823 1824 // Video Playlist states. 1825 new media.controller.VideoPlaylistEdit({ 1826 library: options.selection, 1827 editing: options.editing, 1828 menu: 'video-playlist' 1829 }), 1830 1831 new media.controller.VideoPlaylistAdd() 1744 1832 ]); 1745 1833 1746 1834 … … 1755 1843 */ 1756 1844 media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments ); 1757 1845 this.on( 'menu:create:gallery', this.createMenu, this ); 1846 this.on( 'menu:create:playlist', this.createMenu, this ); 1847 this.on( 'menu:create:video-playlist', this.createMenu, this ); 1758 1848 this.on( 'toolbar:create:main-insert', this.createToolbar, this ); 1759 this.on( 'toolbar:create:main-gallery', this.createToolbar, this ); 1849 this.on( 'toolbar:create:main-gallery', this.createToolbar, this ); 1850 this.on( 'toolbar:create:main-playlist', this.createToolbar, this ); 1851 this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this ); 1760 1852 this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this ); 1761 1853 this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this ); 1762 1854 1763 1855 var handlers = { 1764 1856 menu: { 1765 1857 'default': 'mainMenu', 1766 'gallery': 'galleryMenu' 1858 'gallery': 'galleryMenu', 1859 'playlist': 'playlistMenu', 1860 'video-playlist': 'videoPlaylistMenu' 1767 1861 }, 1768 1862 1769 1863 content: { … … 1775 1869 'main-insert': 'mainInsertToolbar', 1776 1870 'main-gallery': 'mainGalleryToolbar', 1777 1871 'gallery-edit': 'galleryEditToolbar', 1778 'gallery-add': 'galleryAddToolbar' 1872 'gallery-add': 'galleryAddToolbar', 1873 'main-playlist': 'mainPlaylistToolbar', 1874 'playlist-edit': 'playlistEditToolbar', 1875 'playlist-add': 'playlistAddToolbar', 1876 'main-video-playlist': 'mainVideoPlaylistToolbar', 1877 'video-playlist-edit': 'videoPlaylistEditToolbar', 1878 'video-playlist-add': 'videoPlaylistAddToolbar' 1779 1879 } 1780 1880 }; 1781 1881 … … 1825 1925 }); 1826 1926 }, 1827 1927 1928 playlistMenu: function( view ) { 1929 var lastState = this.lastState(), 1930 previous = lastState && lastState.id, 1931 frame = this; 1932 1933 view.set({ 1934 cancel: { 1935 text: l10n.cancelPlaylistTitle, 1936 priority: 20, 1937 click: function() { 1938 if ( previous ) 1939 frame.setState( previous ); 1940 else 1941 frame.close(); 1942 } 1943 }, 1944 separateCancel: new media.View({ 1945 className: 'separator', 1946 priority: 60 1947 }) 1948 }); 1949 }, 1950 1951 videoPlaylistMenu: function( view ) { 1952 var lastState = this.lastState(), 1953 previous = lastState && lastState.id, 1954 frame = this; 1955 1956 view.set({ 1957 cancel: { 1958 text: l10n.cancelVideoPlaylistTitle, 1959 priority: 20, 1960 click: function() { 1961 if ( previous ) 1962 frame.setState( previous ); 1963 else 1964 frame.close(); 1965 } 1966 }, 1967 separateCancel: new media.View({ 1968 className: 'separator', 1969 priority: 80 1970 }) 1971 }); 1972 }, 1973 1828 1974 // Content 1829 1975 embedContent: function() { 1830 1976 var view = new media.view.Embed({ … … 1943 2089 }); 1944 2090 }, 1945 2091 2092 mainPlaylistToolbar: function( view ) { 2093 var controller = this; 2094 2095 this.selectionStatusToolbar( view ); 2096 2097 view.set( 'playlist', { 2098 style: 'primary', 2099 text: l10n.createNewPlaylist, 2100 priority: 100, 2101 requires: { selection: true }, 2102 2103 click: function() { 2104 var selection = controller.state().get('selection'), 2105 edit = controller.state('playlist-edit'), 2106 models = selection.where({ type: 'audio' }); 2107 2108 edit.set( 'library', new media.model.Selection( models, { 2109 props: selection.props.toJSON(), 2110 multiple: true 2111 }) ); 2112 2113 this.controller.setState('playlist-edit'); 2114 } 2115 }); 2116 }, 2117 2118 mainVideoPlaylistToolbar: function( view ) { 2119 var controller = this; 2120 2121 this.selectionStatusToolbar( view ); 2122 2123 view.set( 'video-playlist', { 2124 style: 'primary', 2125 text: l10n.createNewVideoPlaylist, 2126 priority: 100, 2127 requires: { selection: true }, 2128 2129 click: function() { 2130 var selection = controller.state().get('selection'), 2131 edit = controller.state('video-playlist-edit'), 2132 models = selection.where({ type: 'video' }); 2133 2134 edit.set( 'library', new media.model.Selection( models, { 2135 props: selection.props.toJSON(), 2136 multiple: true 2137 }) ); 2138 2139 this.controller.setState('video-playlist-edit'); 2140 } 2141 }); 2142 }, 2143 1946 2144 featuredImageToolbar: function( toolbar ) { 1947 2145 this.createSelectToolbar( toolbar, { 1948 2146 text: l10n.setFeaturedImage, … … 2011 2209 } 2012 2210 } 2013 2211 }) ); 2212 }, 2213 2214 playlistEditToolbar: function() { 2215 var editing = this.state().get('editing'); 2216 this.toolbar.set( new media.view.Toolbar({ 2217 controller: this, 2218 items: { 2219 insert: { 2220 style: 'primary', 2221 text: editing ? l10n.updatePlaylist : l10n.insertPlaylist, 2222 priority: 80, 2223 requires: { library: true }, 2224 2225 /** 2226 * @fires wp.media.controller.State#update 2227 */ 2228 click: function() { 2229 var controller = this.controller, 2230 state = controller.state(); 2231 2232 controller.close(); 2233 state.trigger( 'update', state.get('library') ); 2234 2235 // Restore and reset the default state. 2236 controller.setState( controller.options.state ); 2237 controller.reset(); 2238 } 2239 } 2240 } 2241 }) ); 2242 }, 2243 2244 playlistAddToolbar: function() { 2245 this.toolbar.set( new media.view.Toolbar({ 2246 controller: this, 2247 items: { 2248 insert: { 2249 style: 'primary', 2250 text: l10n.addToPlaylist, 2251 priority: 80, 2252 requires: { selection: true }, 2253 2254 /** 2255 * @fires wp.media.controller.State#reset 2256 */ 2257 click: function() { 2258 var controller = this.controller, 2259 state = controller.state(), 2260 edit = controller.state('playlist-edit'); 2261 2262 edit.get('library').add( state.get('selection').models ); 2263 state.trigger('reset'); 2264 controller.setState('playlist-edit'); 2265 } 2266 } 2267 } 2268 }) ); 2269 }, 2270 2271 videoPlaylistEditToolbar: function() { 2272 var editing = this.state().get('editing'); 2273 this.toolbar.set( new media.view.Toolbar({ 2274 controller: this, 2275 items: { 2276 insert: { 2277 style: 'primary', 2278 text: editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist, 2279 priority: 140, 2280 requires: { library: true }, 2281 2282 click: function() { 2283 var controller = this.controller, 2284 state = controller.state(); 2285 2286 controller.close(); 2287 state.trigger( 'update', state.get('library') ); 2288 2289 // Restore and reset the default state. 2290 controller.setState( controller.options.state ); 2291 controller.reset(); 2292 } 2293 } 2294 } 2295 }) ); 2296 }, 2297 2298 videoPlaylistAddToolbar: function() { 2299 this.toolbar.set( new media.view.Toolbar({ 2300 controller: this, 2301 items: { 2302 insert: { 2303 style: 'primary', 2304 text: l10n.addToVideoPlaylist, 2305 priority: 140, 2306 requires: { selection: true }, 2307 2308 click: function() { 2309 var controller = this.controller, 2310 state = controller.state(), 2311 edit = controller.state('video-playlist-edit'); 2312 2313 edit.get('library').add( state.get('selection').models ); 2314 state.trigger('reset'); 2315 controller.setState('video-playlist-edit'); 2316 } 2317 } 2318 } 2319 }) ); 2014 2320 } 2015 2016 2321 }); 2017 2322 2018 2323 media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({ … … 4842 5147 }); 4843 5148 4844 5149 /** 5150 * wp.media.view.Settings.Gallery 5151 */ 5152 media.view.Settings.Playlist = media.view.Settings.extend({ 5153 className: 'playlist-settings', 5154 template: media.template('playlist-settings') 5155 }); 5156 5157 /** 4845 5158 * wp.media.view.Attachment.Details 4846 5159 * 4847 5160 * @constructor -
src/wp-includes/js/mediaelement/wp-mediaelement.css
13 13 .me-cannotplay { 14 14 width: auto !important; 15 15 } 16 17 .wp-playlist { 18 border: 1px solid #ccc; 19 padding: 10px; 20 margin: 12px 0 18px; 21 font-size: 85%; 22 } 23 24 .wp-playlist .mejs-container { 25 margin: 0; 26 } 27 28 .wp-playlist .mejs-controls .mejs-button button { 29 outline: 0; 30 } 31 32 .wp-playlist-audio { 33 34 } 35 36 .wp-playlist-video { 37 38 } 39 40 .wp-playlist-light { 41 background: #fff; 42 } 43 44 .wp-playlist-dark { 45 color: #fff; 46 background: #000; 47 } 48 49 .wp-playlist-current-item { 50 overflow: hidden; 51 margin-bottom: 10px; 52 } 53 54 .wp-playlist-current-item img { 55 float: left; 56 max-width: 60px; 57 height: auto; 58 margin-right: 10px; 59 } 60 61 .wp-playlist-caption { 62 } 63 64 .wp-caption-meta { 65 display: block; 66 } 67 68 .wp-caption-title { 69 font-size: 100%; 70 } 71 72 .wp-caption-album { 73 font-style: italic; 74 } 75 76 .wp-caption-artist { 77 font-size: 80%; 78 text-transform: uppercase; 79 } 80 81 .wp-caption-by { 82 font-size: 65%; 83 font-weight: bold; 84 } 85 86 .wp-playlist-item-length { 87 position: absolute; 88 right: 0; 89 top: 0; 90 } 91 92 .wp-playlist-tracks { 93 margin-top: 10px; 94 border-top: 1px solid #ccc; 95 } 96 97 .wp-playlist-item { 98 position: relative; 99 cursor: pointer; 100 border-bottom: 1px solid #ccc; 101 } 102 No newline at end of file -
src/wp-includes/js/mediaelement/wp-playlist.js
1 /*globals window, document, $, jQuery */ 2 3 (function ($, _, Backbone) { 4 "use strict"; 5 6 var WPPlaylistView = Backbone.View.extend({ 7 index : 0, 8 9 itemTemplate : wp.template('wp-playlist-item'), 10 11 currentTemplate : wp.template('wp-playlist-current-item'), 12 13 initialize : function () { 14 var settings = {}; 15 16 this.data = $.parseJSON( this.$('script').html() ); 17 this.playerNode = this.$( this.data.type ); 18 19 this.tracks = new Backbone.Collection( this.data.tracks ); 20 this.current = this.tracks.first(); 21 this.currentNode = this.$( '.wp-playlist-current-item' ); 22 this.renderCurrent(); 23 24 if ( this.data.tracklist ) { 25 this.renderTracks(); 26 } 27 28 this.playerNode.attr( 'src', this.current.get('src') ); 29 30 _.bindAll( this, 'bindPlayer', 'ended', 'clickTrack' ); 31 32 if ( typeof _wpmejsSettings !== 'undefined' ) { 33 settings.pluginPath = _wpmejsSettings.pluginPath; 34 } 35 settings.success = this.bindPlayer; 36 37 new MediaElementPlayer( this.playerNode.get(0), settings ); 38 }, 39 40 renderCurrent : function () { 41 this.currentNode.html( this.currentTemplate( this.current.toJSON() ) ); 42 }, 43 44 renderTracks : function () { 45 var that = this, i = 1, tracklist = $( '<div class="wp-playlist-tracks"></div>' ); 46 this.tracks.each(function (model) { 47 model.set( 'index', that.data.tracknums ? i : false ); 48 tracklist.append( that.itemTemplate( model.toJSON() ) ); 49 i += 1; 50 }); 51 this.$el.append( tracklist ); 52 }, 53 54 events : { 55 'click .wp-playlist-item' : 'clickTrack', 56 'click .wp-playlist-next' : 'next', 57 'click .wp-playlist-prev' : 'prev' 58 }, 59 60 bindPlayer : function (mejs) { 61 this.player = mejs; 62 this.player.addEventListener( 'ended', this.ended ); 63 }, 64 65 clickTrack : function (e) { 66 this.index = this.$( '.wp-playlist-item' ).index( e.currentTarget ); 67 this.setCurrent(); 68 }, 69 70 ended : function () { 71 if ( this.index + 1 < this.tracks.length ) { 72 this.next(); 73 } else { 74 this.player.pause(); 75 this.index = 0; 76 this.current = this.tracks.at( this.index ); 77 this.playerNode.attr( 'src', this.current.get( 'src' ) ); 78 this.player.load(); 79 } 80 }, 81 82 next : function () { 83 this.index = this.index + 1 >= this.tracks.length ? 0 : this.index + 1; 84 this.setCurrent(); 85 }, 86 87 prev : function () { 88 this.index = this.index - 1 < 0 ? this.tracks.length - 1 : this.index - 1; 89 this.setCurrent(); 90 }, 91 92 setCurrent : function () { 93 this.current = this.tracks.at( this.index ); 94 this.renderCurrent(); 95 96 this.player.pause(); 97 this.playerNode.attr( 'src', this.current.get( 'src' ) ); 98 this.player.load(); 99 this.player.play(); 100 } 101 }); 102 103 $(document).ready(function () { 104 $('.wp-playlist').each(function () { 105 return new WPPlaylistView({ el: this }); 106 }); 107 }); 108 109 }(jQuery, _, Backbone)); 110 No newline at end of file -
src/wp-includes/js/plupload/handlers.js
22 22 .appendTo( jQuery('#media-items' ) ); 23 23 24 24 // Disable submit 25 jQuery('#insert-gallery ').prop('disabled', true);25 jQuery('#insert-gallery, #insert-playlist').prop('disabled', true); 26 26 } 27 27 28 28 function uploadStart() { … … 47 47 48 48 if ( max > hundredmb && file.size > hundredmb ) { 49 49 setTimeout(function(){ 50 50 51 51 if ( file.status < 3 && file.loaded === 0 ) { // not uploading 52 52 wpFileError(file, pluploadL10n.big_upload_failed.replace('%1$s', '<a class="uploader-html" href="#">').replace('%2$s', '</a>')); 53 53 up.stop(); // stops the whole queue … … 64 64 // Just one file, no need for collapsible part 65 65 if ( items.length == 1 ) { 66 66 items.addClass('open').find('.slidetoggle').show(); 67 jQuery('.insert-gallery ').hide();67 jQuery('.insert-gallery, .insert-playlist').hide(); 68 68 } else if ( items.length > 1 ) { 69 69 items.removeClass('open'); 70 // Only show Gallery buttonwhen there are at least two files.71 jQuery('.insert-gallery ').show();70 // Only show Gallery/Playlist buttons when there are at least two files. 71 jQuery('.insert-gallery, .insert-playlist').show(); 72 72 } 73 73 74 74 // Only show Save buttons when there is at least one file. … … 171 171 success: function( ){ 172 172 var type, 173 173 item = jQuery('#media-item-' + fileObj.id); 174 174 175 175 if ( type = jQuery('#type-of-' + fileObj.id).val() ) 176 176 jQuery('#' + type + '-counter').text(jQuery('#' + type + '-counter').text()-0+1); 177 177 … … 257 257 } 258 258 259 259 function uploadComplete() { 260 jQuery('#insert-gallery ').prop('disabled', false);260 jQuery('#insert-gallery, #insert-playlist').prop('disabled', false); 261 261 } 262 262 263 263 function switchUploader(s) { -
src/wp-includes/js/swfupload/handlers.js
25 25 jQuery('.progress', '#media-item-' + fileObj.id).show(); 26 26 27 27 // Disable submit and enable cancel 28 jQuery('#insert-gallery ').prop('disabled', true);28 jQuery('#insert-gallery, #insert-playlist').prop('disabled', true); 29 29 jQuery('#cancel-upload').prop('disabled', false); 30 30 } 31 31 32 32 function uploadStart(fileObj) { 33 33 try { 34 34 if ( typeof topWin.tb_remove != 'undefined' ) 35 topWin.jQuery('#TB_overlay').unbind('click', topWin.tb_remove); 35 topWin.jQuery('#TB_overlay').unbind('click', topWin.tb_remove); 36 36 } catch(e){} 37 37 38 38 return true; … … 212 212 else 213 213 jQuery('.savebutton').hide(); 214 214 215 // Only show Gallery button when there are at least two files. 216 if ( items.length > 1 ) 217 jQuery('.insert-gallery').show(); 218 else 219 jQuery('.insert-gallery').hide(); 215 // Only show Gallery/Playlist buttons when there are at least two files. 216 if ( items.length > 1 ) { 217 jQuery('.insert-gallery, .insert-playlist').show(); 218 } else { 219 jQuery('.insert-gallery, .insert-playlist').hide(); 220 } 220 221 } 221 222 222 223 function uploadSuccess(fileObj, serverData) { … … 238 239 // If no more uploads queued, enable the submit button 239 240 if ( swfu.getStats().files_queued == 0 ) { 240 241 jQuery('#cancel-upload').prop('disabled', true); 241 jQuery('#insert-gallery ').prop('disabled', false);242 jQuery('#insert-gallery, #insert-playlist').prop('disabled', false); 242 243 } 243 244 } 244 245 -
src/wp-includes/js/tinymce/langs/wp-langs-en.js
478 478 add_audio: "Add Audio", 479 479 editgallery: "Edit Gallery", 480 480 delgallery: "Delete Gallery", 481 editplaylist: "Edit Playlist", 482 delplaylist: "Delete Playlist", 481 483 wp_fullscreen_desc: "Distraction Free Writing mode (Alt + Shift + W)" 482 484 }); 483 485 -
src/wp-includes/js/tinymce/plugins/wpgallery/plugin.js
25 25 } 26 26 27 27 function replaceAVShortcodes( content ) { 28 var testRegex = /\[( audio|video)[^\]]*\]/,29 replaceRegex = /\[( audio|video)[^\]]*\]([\s\S]*?\[\/\1\])?/;28 var testRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]/, 29 replaceRegex = /\[(video-playlist|audio|video|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/; 30 30 31 31 while ( testRegex.test( content ) ) { 32 32 content = content.replace( replaceRegex, replaceCallback ); … … 60 60 } 61 61 62 62 // Check if the `wp.media.gallery` API exists. 63 if ( typeof wp === 'undefined' || ! wp.media || ! wp.media.gallery) {63 if ( typeof wp === 'undefined' || ! wp.media ) { 64 64 return; 65 65 } 66 66 67 67 // Make sure we've selected a gallery node. 68 if ( editor.dom.hasClass( node, 'wp-gallery' ) ) {68 if ( editor.dom.hasClass( node, 'wp-gallery' ) && wp.media.gallery ) { 69 69 gallery = wp.media.gallery; 70 70 data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) ); 71 71 frame = gallery.edit( data ); … … 74 74 var shortcode = gallery.shortcode( selection ).string(); 75 75 editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); 76 76 }); 77 } else if ( editor.dom.hasClass( node, 'wp-playlist' ) && wp.media.playlist ) { 78 data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) ); 79 frame = wp.media.playlist.edit( data ); 80 81 frame.state('playlist-edit').on( 'update', function( selection ) { 82 var shortcode = gallery.shortcode( selection ).string(); 83 editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); 84 }); 85 } else if ( editor.dom.hasClass( node, 'wp-video-playlist' ) && wp.media['video-playlist'] ) { 86 data = window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) ); 87 frame = wp.media['video-playlist'].edit( data ); 88 89 frame.state('video-playlist-edit').on( 'update', function( selection ) { 90 var shortcode = wp.media['video-playlist'].shortcode( selection ).string(); 91 editor.dom.setAttrib( node, 'data-wp-media', window.encodeURIComponent( shortcode ) ); 92 }); 77 93 } else { 78 94 // temp 79 95 window.console && window.console.log( 'Edit AV shortcode ' + window.decodeURIComponent( editor.dom.getAttrib( node, 'data-wp-media' ) ) ); … … 138 154 event.name = 'video'; 139 155 } else if ( dom.hasClass( node, 'wp-audio' ) ) { 140 156 event.name = 'audio'; 157 } else if ( dom.hasClass( node, 'wp-playlist' ) ) { 158 event.name = 'playlist'; 159 } else if ( dom.hasClass( node, 'wp-video-playlist' ) ) { 160 event.name = 'video-playlist'; 141 161 } 142 162 } 143 163 }); -
src/wp-includes/js/tinymce/skins/wordpress/wp-content.css
143 143 background-image: url("images/audio.png"); 144 144 } 145 145 146 .mce-content-body img.wp-media.wp-playlist { 147 background-image: url("images/audio.png"); 148 } 149 150 .mce-content-body img.wp-media.wp-video-playlist { 151 background-image: url("images/video.png"); 152 } 153 146 154 #wp-image-toolbar { 147 155 position: absolute; 148 156 } -
src/wp-includes/media-template.php
411 411 </label> 412 412 </script> 413 413 414 <script type="text/html" id="tmpl-playlist-settings"> 415 <h3><?php _e('Playlist Settings'); ?></h3> 416 417 <label class="setting"> 418 <span><?php _e( 'Random Order' ); ?></span> 419 <input type="checkbox" data-setting="_orderbyRandom" /> 420 </label> 421 422 <label class="setting"> 423 <span><?php _e('Style'); ?></span> 424 <select class="style" data-setting="style"> 425 <option value="light"> 426 <?php esc_attr_e('Light'); ?> 427 </option> 428 <option value="dark"> 429 <?php esc_attr_e('Dark'); ?> 430 </option> 431 </select> 432 </label> 433 434 <label class="setting"> 435 <span><?php _e( 'Show Tracklist' ); ?></span> 436 <input type="checkbox" data-setting="tracklist" /> 437 </label> 438 439 <label class="setting"> 440 <span><?php _e( 'Show Track Numbers' ); ?></span> 441 <input type="checkbox" data-setting="tracknums" /> 442 </label> 443 444 <label class="setting"> 445 <span><?php _e( 'Show Images' ); ?></span> 446 <input type="checkbox" data-setting="images" /> 447 </label> 448 </script> 449 414 450 <script type="text/html" id="tmpl-embed-link-settings"> 415 451 <label class="setting"> 416 452 <span><?php _e('Title'); ?></span> -
src/wp-includes/media.php
934 934 } 935 935 936 936 /** 937 * The Playlist shortcode. 938 * 939 * This implements the functionality of the Playlist Shortcode for displaying 940 * a collection of WordPress audio or video files in a post. 941 * 942 * @since 3.9.0 943 * 944 * @param array $attr Attributes of the shortcode. 945 * @return string $type Type of playlist. Defaults to audio, video is also supported 946 */ 947 function wp_get_playlist( $attr, $type ) { 948 $post = get_post(); 949 950 if ( ! in_array( $type, array( 'audio', 'video' ) ) ) { 951 return ''; 952 } 953 954 static $instance = 0; 955 $instance++; 956 957 if ( ! empty( $attr['ids'] ) ) { 958 // 'ids' is explicitly ordered, unless you specify otherwise. 959 if ( empty( $attr['orderby'] ) ) { 960 $attr['orderby'] = 'post__in'; 961 } 962 $attr['include'] = $attr['ids']; 963 } 964 965 // Allow plugins/themes to override the default gallery template. 966 $output = apply_filters( 'post_playlist', '', $attr, $type ); 967 if ( $output != '' ) { 968 return $output; 969 } 970 971 // We're trusting author input, so let's at least make sure it looks like a valid orderby statement 972 if ( isset( $attr['orderby'] ) ) { 973 $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] ); 974 if ( ! $attr['orderby'] ) 975 unset( $attr['orderby'] ); 976 } 977 978 extract( shortcode_atts( array( 979 'order' => 'ASC', 980 'orderby' => 'menu_order ID', 981 'id' => $post ? $post->ID : 0, 982 'include' => '', 983 'exclude' => '', 984 'style' => 'light', 985 'tracklist' => 'audio' === $type, 986 'tracknums' => 'audio' === $type, 987 'images' => true 988 ), $attr, 'playlist' ) ); 989 990 $id = intval( $id ); 991 if ( 'RAND' == $order ) { 992 $orderby = 'none'; 993 } 994 995 $args = array( 996 'post_status' => 'inherit', 997 'post_type' => 'attachment', 998 'post_mime_type' => $type, 999 'order' => $order, 1000 'orderby' => $orderby 1001 ); 1002 1003 if ( ! empty( $include ) ) { 1004 $args['include'] = $include; 1005 $_attachments = get_posts( $args ); 1006 1007 $attachments = array(); 1008 foreach ( $_attachments as $key => $val ) { 1009 $attachments[$val->ID] = $_attachments[$key]; 1010 } 1011 } elseif ( ! empty( $exclude ) ) { 1012 $args['post_parent'] = $id; 1013 $args['exclude'] = $exclude; 1014 $attachments = get_children( $args ); 1015 } else { 1016 $args['post_parent'] = $id; 1017 $attachments = get_children( $args ); 1018 } 1019 1020 if ( empty( $attachments ) ) { 1021 return ''; 1022 } 1023 1024 if ( is_feed() ) { 1025 $output = "\n"; 1026 foreach ( $attachments as $att_id => $attachment ) { 1027 $output .= wp_get_attachment_link( $att_id, $size, true ) . "\n"; 1028 } 1029 return $output; 1030 } 1031 1032 $supports_thumbs = ( current_theme_supports( 'post-thumbnails', "attachment:$type" ) && post_type_supports( "attachment:$type", 'thumbnail' ) ) 1033 || $images; 1034 1035 $data = compact( 'type', 'style' ); 1036 // don't pass strings to JSON, will be truthy in JS 1037 $data['tracklist'] = filter_var( $tracklist, FILTER_VALIDATE_BOOLEAN ); 1038 $data['tracknums'] = filter_var( $tracknums, FILTER_VALIDATE_BOOLEAN ); 1039 $data['images'] = filter_var( $images, FILTER_VALIDATE_BOOLEAN ); 1040 1041 $tracks = array(); 1042 foreach ( $attachments as $attachment ) { 1043 $url = wp_get_attachment_url( $attachment->ID ); 1044 $ftype = wp_check_filetype( $url, wp_get_mime_types() ); 1045 $track = array( 1046 'type' => $type, 1047 'src' => $url, 1048 'type' => $ftype['ext'], 1049 'title' => get_the_title( $attachment->ID ), 1050 'caption' => wptexturize( $attachment->post_excerpt ), 1051 'description' => wptexturize( $attachment->post_content ) 1052 ); 1053 1054 $meta = wp_get_attachment_metadata( $attachment->ID ); 1055 if ( ! empty( $meta ) ) { 1056 $track['meta'] = array(); 1057 1058 $keys = array( 'title', 'artist', 'band', 'album', 'genre', 'year', 'length', 'length_formatted' ); 1059 foreach ( $keys as $key ) { 1060 if ( ! empty( $meta[ $key ] ) ) { 1061 $track['meta'][ $key ] = $meta[ $key ]; 1062 } 1063 } 1064 } 1065 1066 if ( $supports_thumbs ) { 1067 $id = get_post_thumbnail_id( $attachment->ID ); 1068 if ( ! empty( $id ) ) { 1069 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' ); 1070 $track['image'] = compact( 'src', 'width', 'height' ); 1071 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumb' ); 1072 $track['thumb'] = compact( 'src', 'width', 'height' ); 1073 } 1074 } 1075 1076 $tracks[] = $track; 1077 } 1078 $data['tracks'] = $tracks; 1079 1080 ob_start(); 1081 1082 if ( 1 === $instance ): 1083 wp_enqueue_style( 'wp-mediaelement' ); 1084 wp_enqueue_script( 'wp-playlist' ); 1085 ?> 1086 <script type="text/html" id="tmpl-wp-playlist-current-item"> 1087 <# if ( data.image ) { #> 1088 <img src="{{{ data.image.src }}}"/> 1089 <# } #> 1090 <# if ( data.meta.title ) { #> 1091 <div class="wp-playlist-caption"> 1092 <span class="wp-caption-meta wp-caption-title">“{{{ data.meta.title }}}”</span> 1093 <span class="wp-caption-meta wp-caption-album">{{{ data.meta.album }}}</span> 1094 <span class="wp-caption-meta wp-caption-artist">{{{ data.meta.artist }}}</span> 1095 </div> 1096 <# } else { #> 1097 <div class="wp-playlist-caption">{{{ data.caption }}}</div> 1098 <# } #> 1099 </script> 1100 <script type="text/html" id="tmpl-wp-playlist-item"> 1101 <div class="wp-playlist-item"> 1102 <# if ( ( data.title || data.meta.title ) && data.meta.artist ) { #> 1103 <div class="wp-playlist-caption"> 1104 {{{ data.index ? ( data.index + '. ' ) : '' }}} 1105 <span class="wp-caption-title">“{{{ data.title ? data.title : data.meta.title }}}”</span> 1106 <span class="wp-caption-by"><?php _e( 'by' ) ?></span> 1107 <span class="wp-caption-artist">{{{ data.meta.artist }}}</span> 1108 </div> 1109 <# } else { #> 1110 <div class="wp-playlist-caption">{{{ data.index ? ( data.index + '.' ) : '' }}} {{{ data.caption ? data.caption : data.title }}}</div> 1111 <# } #> 1112 <# if ( data.meta.length_formatted ) { #> 1113 <div class="wp-playlist-item-length">{{{ data.meta.length_formatted }}}</div> 1114 <# } #> 1115 </div> 1116 </script> 1117 <?php endif ?> 1118 <div class="wp-playlist wp-<?php echo $type ?>-playlist wp-playlist-<?php echo $style ?>"> 1119 <div class="wp-playlist-current-item"></div> 1120 <<?php echo $type ?> controls="controls" preload="metadata"></<?php echo $type ?>> 1121 <div class="wp-playlist-next"></div> 1122 <div class="wp-playlist-prev"></div> 1123 <noscript> 1124 <?php 1125 $output = "\n"; 1126 foreach ( $attachments as $att_id => $attachment ) { 1127 $output .= wp_get_attachment_link( $att_id, $size, true ) . "\n"; 1128 } 1129 1130 echo $output; 1131 ?> 1132 </noscript> 1133 <script type="application/json"><?php echo json_encode( $data ) ?></script> 1134 </div> 1135 <?php 1136 return ob_get_clean(); 1137 } 1138 1139 function wp_playlist_shortcode( $attr ) { 1140 return wp_get_playlist( $attr, 'audio' ); 1141 } 1142 add_shortcode( 'playlist', 'wp_playlist_shortcode' ); 1143 1144 function wp_video_playlist_shortcode( $attr ) { 1145 return wp_get_playlist( $attr, 'video' ); 1146 } 1147 add_shortcode( 'video-playlist', 'wp_video_playlist_shortcode' ); 1148 1149 /** 937 1150 * Provide a No-JS Flash fallback as a last resort for audio / video 938 1151 * 939 1152 * @since 3.6.0 … … 2044 2257 'mediaLibraryTitle' => __( 'Media Library' ), 2045 2258 'insertMediaTitle' => __( 'Insert Media' ), 2046 2259 'createNewGallery' => __( 'Create a new gallery' ), 2260 'createNewPlaylist' => __( 'Create a new playlist' ), 2261 'createNewVideoPlaylist' => __( 'Create a new video playlist' ), 2047 2262 'returnToLibrary' => __( '← Return to library' ), 2048 2263 'allMediaItems' => __( 'All media items' ), 2049 2264 'noItemsFound' => __( 'No items found.' ), … … 2071 2286 // Edit Image 2072 2287 'imageDetailsTitle' => __( 'Image Details' ), 2073 2288 'imageReplaceTitle' => __( 'Replace Image' ), 2074 'imageDetailsCancel' => __( 'Cancel Edit' ) 2289 'imageDetailsCancel' => __( 'Cancel Edit' ), 2290 2291 // Playlist 2292 'playlistDragInfo' => __( 'Drag and drop to reorder tracks.' ), 2293 'createPlaylistTitle' => __( 'Create Playlist' ), 2294 'editPlaylistTitle' => __( 'Edit Playlist' ), 2295 'cancelPlaylistTitle' => __( '← Cancel Playlist' ), 2296 'insertPlaylist' => __( 'Insert playlist' ), 2297 'updatePlaylist' => __( 'Update playlist' ), 2298 'addToPlaylist' => __( 'Add to playlist' ), 2299 'addToPlaylistTitle' => __( 'Add to Playlist' ), 2300 2301 // Video Playlist 2302 'videoPlaylistDragInfo' => __( 'Drag and drop to reorder videos.' ), 2303 'createVideoPlaylistTitle' => __( 'Create Video Playlist' ), 2304 'editVideoPlaylistTitle' => __( 'Edit Video Playlist' ), 2305 'cancelVideoPlaylistTitle' => __( '← Cancel Video Playlist' ), 2306 'insertVideoPlaylist' => __( 'Insert Video playlist' ), 2307 'updateVideoPlaylist' => __( 'Update Video playlist' ), 2308 'addToVideoPlaylist' => __( 'Add to Video playlist' ), 2309 'addToVideoPlaylistTitle' => __( 'Add to Video Playlist' ), 2075 2310 ); 2076 2311 2077 2312 $settings = apply_filters( 'media_view_settings', $settings, $post ); -
src/wp-includes/script-loader.php
315 315 'pluginPath' => includes_url( 'js/mediaelement/', 'relative' ), 316 316 ) ); 317 317 318 $scripts->add( 'wp-playlist', "/wp-includes/js/mediaelement/wp-playlist.js", array( 'wp-util', 'backbone', 'mediaelement' ), false, 1 ); 319 318 320 $scripts->add( 'zxcvbn-async', "/wp-includes/js/zxcvbn-async$suffix.js", array(), '1.0' ); 319 321 did_action( 'init' ) && $scripts->localize( 'zxcvbn-async', '_zxcvbnSettings', array( 320 322 'src' => empty( $guessed_url ) ? includes_url( '/js/zxcvbn.min.js' ) : $scripts->base_url . '/wp-includes/js/zxcvbn.min.js',