Ticket #26631: 26631.8.diff
File 26631.8.diff, 62.6 KB (added by , 10 years ago) |
---|
-
src/wp-admin/edit-form-advanced.php
24 24 $user_ID = isset($user_ID) ? (int) $user_ID : 0; 25 25 $action = isset($action) ? $action : ''; 26 26 27 if ( post_type_supports($post_type, 'editor') || post_type_supports($post_type, 'thumbnail') ) { 27 $media_type = false; 28 if ( 'attachment' && $post_ID ) { 29 $post = get_post( $post_ID ); 30 $media_type = post_supports_thumbnails( $post ); 31 } 32 33 if ( post_type_supports( $post_type, 'editor' ) || post_type_supports( $post_type, 'thumbnail' ) || $media_type ) { 28 34 add_thickbox(); 29 35 wp_enqueue_media( array( 'post' => $post_ID ) ); 30 36 } -
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/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 {596 display: none;597 }598 599 595 .media-frame-title h1 { 600 596 padding: 0 16px; 601 597 font-size: 22px; … … 1424 1420 margin: 1.4em 0 0.4em; 1425 1421 } 1426 1422 1427 . gallery-settings {1423 .collection-settings { 1428 1424 overflow: hidden; 1429 1425 } 1430 1426 … … 1883 1879 border-top: none; 1884 1880 } 1885 1881 1886 . gallery-settings h3 {1882 .collection-settings h3 { 1887 1883 margin-top: 45px; 1888 1884 } 1889 1885 -
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 = {}; 288 289 return { 280 wp.media.collection = { 281 attachments : function ( prop, type ) { 290 282 /** 291 * Default gallery properties292 *293 * @global wp.media.view.settings294 * @readonly295 */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 283 * Retrieve attachments based on the properties of the passed shortcode 309 284 * 310 285 * @global wp.media.query 311 286 * 312 287 * @param {wp.shortcode} shortcode An instance of wp.shortcode(). 313 288 * @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. 289 * the media items belonging to a collection. 290 * The 'prop' specified by the passed prop is a Backbone.Model 291 * containing the 'props' for the gallery. 316 292 */ 317 attachments:function( shortcode ) {318 var shortcodeString = shortcode.string(),319 result = galleries[ shortcodeString ],320 attrs, args, query, others;293 return function( shortcode ) { 294 var shortcodeString = shortcode.string(), 295 result = cache[ shortcodeString ], 296 attrs, args, query, others; 321 297 322 delete galleries[ shortcodeString ];298 delete cache[ shortcodeString ]; 323 299 324 if ( result ) {325 return result;300 if ( result ) { 301 return result; 326 302 } 327 303 328 // Fill the default shortcode attributes.329 attrs = _.defaults( shortcode.attrs.named, wp.media.gallery.defaults );330 args = _.pick( attrs, 'orderby', 'order' );304 // Fill the default shortcode attributes. 305 attrs = _.defaults( shortcode.attrs.named, this.defaults ); 306 args = _.pick( attrs, 'orderby', 'order' ); 331 307 332 args.type = 'image';333 args.perPage = -1;308 args.type = type; 309 args.perPage = -1; 334 310 335 // Mark the `orderby` override attribute.336 if( undefined !== attrs.orderby ) {337 attrs._orderByField = attrs.orderby;311 // Mark the `orderby` override attribute. 312 if ( undefined !== attrs.orderby ) { 313 attrs._orderByField = attrs.orderby; 338 314 } 315 339 316 if ( 'rand' === attrs.orderby ) { 340 317 attrs._orderbyRandom = true; 341 318 } 342 319 320 if ( -1 !== jQuery.inArray( prop, ['playlist', 'video-playlist'] ) ) { 321 _.each(['tracknumbers', 'tracklist', 'images'], function (setting) { 322 if ( 'undefined' === typeof attrs[setting] ) { 323 attrs['_' + setting] = wp.media[ prop ].defaults[ setting ]; 324 } else if ( 'true' === attrs[setting] || true === attrs[setting] ) { 325 attrs['_' + setting] = true; 326 } 327 }); 328 } 329 343 330 // Map the `orderby` attribute to the corresponding model property. 344 331 if ( ! attrs.orderby || /^menu_order(?: ID)?$/i.test( attrs.orderby ) ) { 345 332 args.orderby = 'menuOrder'; … … 365 352 others = _.omit( attrs, 'id', 'ids', 'include', 'exclude', 'orderby', 'order' ); 366 353 367 354 query = wp.media.query( args ); 368 query .gallery= new Backbone.Model( others );355 query[ prop ] = new Backbone.Model( others ); 369 356 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; 357 }; 358 }, 386 359 387 if ( attachments.gallery) {388 _.extend( attrs, attachments.gallery.toJSON() ); 389 } 360 shortcodeAttrs : function ( prop, attachments ) { 361 var props = attachments.props.toJSON(), 362 attrs = _.pick( props, 'orderby', 'order', 'style' ); 390 363 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'); 364 if ( attachments[ prop ] ) { 365 _.extend( attrs, attachments[ prop ].toJSON() ); 366 } 395 367 396 // Copy the `uploadedTo` post ID.397 if ( props.uploadedTo ) { 398 attrs.id = props.uploadedTo; 399 } 368 // Convert all collection shortcodes to use the `ids` property. 369 // Ignore `post__in` and `post__not_in`; the attachments in 370 // the collection will already reflect those properties. 371 attrs.ids = attachments.pluck('id'); 400 372 401 // Check if the gallery is randomly ordered. 402 delete attrs.orderby; 373 // Copy the `uploadedTo` post ID. 374 if ( props.uploadedTo ) { 375 attrs.id = props.uploadedTo; 376 } 403 377 404 if ( attrs._orderbyRandom ) { 405 attrs.orderby = 'rand'; 406 } else if ( attrs._orderByField && attrs._orderByField != 'rand' ) { 407 attrs.orderby = attrs._orderByField; 408 } 378 // Check if the collection is randomly ordered. 379 delete attrs.orderby; 409 380 410 delete attrs._orderbyRandom; 411 delete attrs._orderByField; 381 if ( attrs._orderbyRandom ) { 382 attrs.orderby = 'rand'; 383 } else if ( attrs._orderByField && attrs._orderByField != 'rand' ) { 384 attrs.orderby = attrs._orderByField; 385 } 412 386 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 } 387 delete attrs._orderbyRandom; 388 delete attrs._orderByField; 418 389 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 });390 // If the `ids` attribute is set and `orderby` attribute 391 // is the default value, clear it for cleaner output. 392 if ( attrs.ids && 'post__in' === attrs.orderby ) { 393 delete attrs.orderby; 394 } 424 395 425 shortcode = new wp.shortcode({ 426 tag: 'gallery', 427 attrs: attrs, 428 type: 'single' 396 if ( -1 !== jQuery.inArray( prop, ['playlist', 'video-playlist'] ) ) { 397 _.each(['tracknumbers', 'tracklist', 'images'], function (setting) { 398 if ( attrs['_' + setting] ) { 399 attrs[setting] = true; 400 } else { 401 attrs[setting] = false; 402 } 403 delete attrs['_' + setting]; 429 404 }); 405 } 430 406 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; 407 // Remove default attributes from the shortcode. 408 _.each( this.defaults, function( value, key ) { 409 if ( value === attrs[ key ] ) { 410 delete attrs[ key ]; 411 } 412 }); 413 return attrs; 414 }, 437 415 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; 416 editSelection : function ( prop, shortcode ) { 417 var defaultPostId = wp.media[ prop ].defaults.id, 418 attachments, selection; 459 419 460 // Bail if we didn't match the shortcode or all of the content. 461 if ( ! shortcode || shortcode.content !== content ) { 462 return; 463 } 420 // Ignore the rest of the match object. 421 shortcode = shortcode.shortcode; 464 422 465 // Ignore the rest of the match object. 466 shortcode = shortcode.shortcode; 423 if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) { 424 shortcode.set( 'id', defaultPostId ); 425 } 467 426 468 if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) { 469 shortcode.set( 'id', defaultPostId ); 470 } 427 attachments = wp.media[ prop ].attachments( shortcode ); 471 428 472 attachments = wp.media.gallery.attachments( shortcode ); 429 selection = new wp.media.model.Selection( attachments.models, { 430 props: attachments.props.toJSON(), 431 multiple: true 432 }); 473 433 474 selection = new wp.media.model.Selection( attachments.models, { 475 props: attachments.props.toJSON(), 476 multiple: true 477 }); 434 selection[ prop ] = attachments[ prop ]; 478 435 479 selection.gallery = attachments.gallery; 436 // Fetch the query's attachments, and then break ties from the 437 // query to allow for sorting. 438 selection.more().done( function() { 439 // Break ties with the query. 440 selection.props.set({ query: false }); 441 selection.unmirror(); 442 selection.props.unset('orderby'); 443 }); 480 444 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 }); 445 return selection; 446 }, 489 447 490 // Destroy the previous gallery frame. 491 if ( this.frame ) { 492 this.frame.dispose(); 493 } 448 /** 449 * 450 * @param {string} prop The shortcode slug 451 * @param {type} attachments 452 * @param {wp.media.shortcode} shortcode 453 * @returns {wp.media.shortcode} 454 */ 455 cacheShortcode : function ( prop, attachments, shortcode ) { 456 // Use a cloned version of the playlist. 457 var clone = new wp.media.model.Attachments( attachments.models, { 458 props: attachments.props.toJSON() 459 }); 460 clone[ prop ] = attachments[ prop ]; 461 cache[ shortcode.string() ] = clone; 494 462 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(); 463 return shortcode; 464 }, 504 465 505 return this.frame; 466 getEditFrame : function ( args ) { 467 // Destroy the previous gallery frame. 468 if ( this.frame ) { 469 this.frame.dispose(); 506 470 } 507 };508 }());509 471 472 // Store the current gallery frame. 473 this.frame = wp.media( _.extend( { 474 frame: 'post', 475 editing: true, 476 multiple: true, 477 }, args ) ).open(); 478 479 return this.frame; 480 }, 481 482 instance : function ( prop, args ) { 483 return { 484 attachments: this.attachments( prop, args.type ), 485 /** 486 * Triggered when clicking 'Insert {label}' or 'Update {label}' 487 * 488 * @global wp.shortcode 489 * @global wp.media.model.Attachments 490 * 491 * @param {wp.media.model.Attachments} attachments A Backbone.Collection containing 492 * the media items belonging to a collection. 493 * The 'prop' specified by the passed prop is a Backbone.Model 494 * containing the 'props' for the gallery. 495 * @returns {wp.shortcode} 496 */ 497 shortcode: function( attachments ) { 498 var shortcode = new wp.shortcode({ 499 tag: prop, 500 attrs: wp.media.collection.shortcodeAttrs( prop, attachments ), 501 type: 'single' 502 }); 503 504 return wp.media.collection.cacheShortcode( prop, attachments, shortcode ); 505 }, 506 /** 507 * Triggered when double-clicking a collection shortcode placeholder 508 * in the editor 509 * 510 * @global wp.shortcode 511 * @global wp.media.model.Selection 512 * @global wp.media.view.l10n 513 * 514 * @param {string} content Content that is searched for possible 515 * shortcode markup matching the passed tag name, 516 * 517 * @this wp.media.{prop} 518 * 519 * @returns {wp.media.view.MediaFrame.Select} A media workflow. 520 */ 521 edit: function( content ) { 522 var shortcode = wp.shortcode.next( prop, content ); 523 524 // Bail if we didn't match the shortcode or all of the content. 525 if ( ! shortcode || shortcode.content !== content ) { 526 return; 527 } 528 529 return wp.media.collection.getEditFrame( { 530 title: args.title, 531 state: prop + '-edit', 532 selection: wp.media.collection.editSelection( prop, shortcode ) 533 } ); 534 } 535 }; 536 } 537 }; 538 539 wp.media.gallery = (function() { 540 var gallery = { 541 defaults : { 542 itemtag: 'dl', 543 icontag: 'dt', 544 captiontag: 'dd', 545 columns: '3', 546 link: 'post', 547 size: 'thumbnail', 548 order: 'ASC', 549 id: wp.media.view.settings.post.id, 550 orderby : 'menu_order ID' 551 } 552 }; 553 554 return _.extend(gallery, wp.media.collection.instance( 'gallery', { 555 type : 'image', 556 title : wp.media.view.l10n.editGalleryTitle 557 })); 558 }()); 559 560 wp.media.playlist = (function() { 561 var playlist = { 562 defaults : { 563 id: wp.media.view.settings.post.id, 564 style: 'light', 565 tracklist: true, 566 tracknumbers: true, 567 images: true 568 } 569 }; 570 571 return _.extend(playlist, wp.media.collection.instance( 'playlist', { 572 type : 'audio', 573 title : wp.media.view.l10n.editPlaylistTitle 574 })); 575 }()); 576 577 wp.media['video-playlist'] = (function() { 578 var playlist = { 579 defaults : { 580 id: wp.media.view.settings.post.id, 581 style: 'light', 582 tracklist: false, 583 tracknumbers: false, 584 images: false 585 } 586 }; 587 588 return _.extend(playlist, wp.media.collection.instance( 'video-playlist', { 589 type : 'video', 590 title : wp.media.view.l10n.editVideoPlaylistTitle 591 })); 592 }()); 593 510 594 /** 511 595 * wp.media.featuredImage 512 596 * @namespace … … 725 809 this.insert( wp.media.gallery.shortcode( selection ).string() ); 726 810 }, this ); 727 811 812 workflow.state('playlist-edit').on( 'update', function( selection ) { 813 this.insert( wp.media.playlist.shortcode( selection ).string() ); 814 }, this ); 815 816 workflow.state('video-playlist-edit').on( 'update', function( selection ) { 817 this.insert( wp.media['video-playlist'].shortcode( selection ).string() ); 818 }, this ); 819 728 820 workflow.state('embed').on( 'select', function() { 729 821 /** 730 822 * @this wp.media.editor … … 964 1056 if ( elem.hasClass( 'gallery' ) ) { 965 1057 options.state = 'gallery'; 966 1058 options.title = wp.media.view.l10n.createGalleryTitle; 1059 } else if ( elem.hasClass( 'playlist' ) ) { 1060 options.state = 'playlist'; 1061 options.title = wp.media.view.l10n.createPlaylistTitle; 1062 } else if ( elem.hasClass( 'video-playlist' ) ) { 1063 options.state = 'video-playlist'; 1064 options.title = wp.media.view.l10n.createVideoPlaylistTitle; 967 1065 } 968 1066 969 1067 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({ … … 4837 5142 * @augments Backbone.View 4838 5143 */ 4839 5144 media.view.Settings.Gallery = media.view.Settings.extend({ 4840 className: ' gallery-settings',5145 className: 'collection-settings gallery-settings', 4841 5146 template: media.template('gallery-settings') 4842 5147 }); 4843 5148 4844 5149 /** 5150 * wp.media.view.Settings.Gallery 5151 */ 5152 media.view.Settings.Playlist = media.view.Settings.extend({ 5153 className: 'collection-settings 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 width: 100%; 27 } 28 29 .wp-playlist .mejs-controls .mejs-button button { 30 outline: 0; 31 } 32 33 .wp-playlist-light { 34 background: #fff; 35 } 36 37 .wp-playlist-dark { 38 color: #fff; 39 background: #000; 40 } 41 42 .wp-playlist-current-item { 43 overflow: hidden; 44 margin-bottom: 10px; 45 } 46 47 .wp-playlist-current-item img { 48 float: left; 49 max-width: 60px; 50 height: auto; 51 margin-right: 10px; 52 } 53 54 .wp-playlist-caption { 55 } 56 57 .wp-caption-meta { 58 display: block; 59 } 60 61 .wp-caption-title { 62 font-size: 100%; 63 } 64 65 .wp-caption-album { 66 font-style: italic; 67 } 68 69 .wp-caption-artist { 70 font-size: 80%; 71 text-transform: uppercase; 72 } 73 74 .wp-caption-by { 75 font-size: 65%; 76 font-weight: bold; 77 } 78 79 .wp-playlist-item-length { 80 position: absolute; 81 right: 0; 82 top: 0; 83 } 84 85 .wp-playlist-tracks { 86 margin-top: 10px; 87 border-top: 1px solid #ccc; 88 } 89 90 .wp-playlist-item { 91 position: relative; 92 cursor: pointer; 93 border-bottom: 1px solid #ccc; 94 } 95 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 initialize : function () { 12 var settings = {}; 13 14 this.data = $.parseJSON( this.$('script').html() ); 15 this.playerNode = this.$( this.data.type ); 16 17 this.tracks = new Backbone.Collection( this.data.tracks ); 18 this.current = this.tracks.first(); 19 20 if ( 'audio' === this.data.type ) { 21 this.currentTemplate = wp.template('wp-playlist-current-item'); 22 this.currentNode = this.$( '.wp-playlist-current-item' ); 23 } 24 25 this.renderCurrent(); 26 27 if ( this.data.tracklist ) { 28 this.renderTracks(); 29 } 30 31 this.playerNode.attr( 'src', this.current.get('src') ); 32 33 _.bindAll( this, 'bindPlayer', 'ended', 'clickTrack' ); 34 35 if ( typeof _wpmejsSettings !== 'undefined' ) { 36 settings.pluginPath = _wpmejsSettings.pluginPath; 37 } 38 settings.defaultAudioWidth = '100%'; 39 settings.success = this.bindPlayer; 40 41 new MediaElementPlayer( this.playerNode.get(0), settings ); 42 }, 43 44 renderCurrent : function () { 45 if ( 'video' === this.data.type ) { 46 if ( this.data.images && this.current.get( 'image' ) ) { 47 this.playerNode.attr( 'poster', this.current.get( 'image' ).src ); 48 } 49 this.playerNode.attr( 'width', this.current.get( 'width' ) ); 50 this.playerNode.attr( 'height', this.current.get( 'height' ) ); 51 } else { 52 if ( ! this.data.images ) { 53 this.current.set( 'image', false ); 54 } 55 this.currentNode.html( this.currentTemplate( this.current.toJSON() ) ); 56 } 57 }, 58 59 renderTracks : function () { 60 var that = this, i = 1, tracklist = $( '<div class="wp-playlist-tracks"></div>' ); 61 this.tracks.each(function (model) { 62 if ( ! that.data.images ) { 63 model.set( 'image', false ); 64 } 65 model.set( 'index', that.data.tracknumbers ? i : false ); 66 tracklist.append( that.itemTemplate( model.toJSON() ) ); 67 i += 1; 68 }); 69 this.$el.append( tracklist ); 70 }, 71 72 events : { 73 'click .wp-playlist-item' : 'clickTrack', 74 'click .wp-playlist-next' : 'next', 75 'click .wp-playlist-prev' : 'prev' 76 }, 77 78 bindPlayer : function (mejs) { 79 this.player = mejs; 80 this.player.addEventListener( 'ended', this.ended ); 81 }, 82 83 clickTrack : function (e) { 84 this.index = this.$( '.wp-playlist-item' ).index( e.currentTarget ); 85 this.setCurrent(); 86 }, 87 88 ended : function () { 89 if ( this.index + 1 < this.tracks.length ) { 90 this.next(); 91 } else { 92 this.index = 0; 93 this.current = this.tracks.at( this.index ); 94 this.loadCurrent(); 95 } 96 }, 97 98 next : function () { 99 this.index = this.index + 1 >= this.tracks.length ? 0 : this.index + 1; 100 this.setCurrent(); 101 }, 102 103 prev : function () { 104 this.index = this.index - 1 < 0 ? this.tracks.length - 1 : this.index - 1; 105 this.setCurrent(); 106 }, 107 108 loadCurrent : function () { 109 this.player.pause(); 110 this.playerNode.attr( 'src', this.current.get( 'src' ) ); 111 this.renderCurrent(); 112 this.player.load(); 113 }, 114 115 setCurrent : function () { 116 this.current = this.tracks.at( this.index ); 117 this.loadCurrent(); 118 this.player.play(); 119 } 120 }); 121 122 $(document).ready(function () { 123 $('.wp-playlist').each(function () { 124 return new WPPlaylistView({ el: this }); 125 }); 126 }); 127 128 }(jQuery, _, Backbone)); 129 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 = wp.media.playlist.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="_tracknumbers" /> 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 global $content_width; 949 $post = get_post(); 950 951 if ( ! in_array( $type, array( 'audio', 'video' ) ) ) { 952 return ''; 953 } 954 955 static $instance = 0; 956 $instance++; 957 958 if ( ! empty( $attr['ids'] ) ) { 959 // 'ids' is explicitly ordered, unless you specify otherwise. 960 if ( empty( $attr['orderby'] ) ) { 961 $attr['orderby'] = 'post__in'; 962 } 963 $attr['include'] = $attr['ids']; 964 } 965 966 // Allow plugins/themes to override the default gallery template. 967 $output = apply_filters( 'post_playlist', '', $attr, $type ); 968 if ( $output != '' ) { 969 return $output; 970 } 971 972 // We're trusting author input, so let's at least make sure it looks like a valid orderby statement 973 if ( isset( $attr['orderby'] ) ) { 974 $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] ); 975 if ( ! $attr['orderby'] ) 976 unset( $attr['orderby'] ); 977 } 978 979 extract( shortcode_atts( array( 980 'order' => 'ASC', 981 'orderby' => 'menu_order ID', 982 'id' => $post ? $post->ID : 0, 983 'include' => '', 984 'exclude' => '', 985 'style' => 'light', 986 'tracklist' => 'audio' === $type, 987 'tracknumbers' => 'audio' === $type, 988 'images' => true 989 ), $attr, 'playlist' ) ); 990 991 // don't pass strings to JSON, will be truthy in JS 992 $tracklist = filter_var( $tracklist, FILTER_VALIDATE_BOOLEAN ); 993 $tracknumbers = filter_var( $tracknumbers, FILTER_VALIDATE_BOOLEAN ); 994 $images = filter_var( $images, FILTER_VALIDATE_BOOLEAN ); 995 996 $id = intval( $id ); 997 if ( 'RAND' == $order ) { 998 $orderby = 'none'; 999 } 1000 1001 $args = array( 1002 'post_status' => 'inherit', 1003 'post_type' => 'attachment', 1004 'post_mime_type' => $type, 1005 'order' => $order, 1006 'orderby' => $orderby 1007 ); 1008 1009 if ( ! empty( $include ) ) { 1010 $args['include'] = $include; 1011 $_attachments = get_posts( $args ); 1012 1013 $attachments = array(); 1014 foreach ( $_attachments as $key => $val ) { 1015 $attachments[$val->ID] = $_attachments[$key]; 1016 } 1017 } elseif ( ! empty( $exclude ) ) { 1018 $args['post_parent'] = $id; 1019 $args['exclude'] = $exclude; 1020 $attachments = get_children( $args ); 1021 } else { 1022 $args['post_parent'] = $id; 1023 $attachments = get_children( $args ); 1024 } 1025 1026 if ( empty( $attachments ) ) { 1027 return ''; 1028 } 1029 1030 if ( is_feed() ) { 1031 $output = "\n"; 1032 foreach ( $attachments as $att_id => $attachment ) { 1033 $output .= wp_get_attachment_link( $att_id ) . "\n"; 1034 } 1035 return $output; 1036 } 1037 1038 $supports_thumbs = ( current_theme_supports( 'post-thumbnails', "attachment:$type" ) && post_type_supports( "attachment:$type", 'thumbnail' ) ) 1039 || $images; 1040 1041 $outer = 22; // default padding and border of wrapper 1042 $data = compact( 'type', 'style', 'tracklist', 'tracknumbers', 'images' ); 1043 $tracks = array(); 1044 foreach ( $attachments as $attachment ) { 1045 $url = wp_get_attachment_url( $attachment->ID ); 1046 $ftype = wp_check_filetype( $url, wp_get_mime_types() ); 1047 $track = array( 1048 'type' => $type, 1049 'src' => $url, 1050 'type' => $ftype['ext'], 1051 'title' => get_the_title( $attachment->ID ), 1052 'caption' => wptexturize( $attachment->post_excerpt ), 1053 'description' => wptexturize( $attachment->post_content ) 1054 ); 1055 1056 $meta = wp_get_attachment_metadata( $attachment->ID ); 1057 if ( ! empty( $meta ) ) { 1058 $track['meta'] = array(); 1059 1060 $keys = array( 'title', 'artist', 'band', 'album', 'genre', 'year', 'length', 'length_formatted' ); 1061 foreach ( $keys as $key ) { 1062 if ( ! empty( $meta[ $key ] ) ) { 1063 $track['meta'][ $key ] = $meta[ $key ]; 1064 } 1065 } 1066 1067 if ( 'video' === $type ) { 1068 $width = empty( $meta['width'] ) ? 640 : $meta['width']; 1069 $height = empty( $meta['height'] ) ? 360 : $meta['height']; 1070 $track['width'] = $content_width - $outer; 1071 $track['height'] = round( ( $height * $track['width'] ) / $width ); 1072 } 1073 } 1074 1075 if ( $supports_thumbs ) { 1076 $id = get_post_thumbnail_id( $attachment->ID ); 1077 if ( ! empty( $id ) ) { 1078 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' ); 1079 $track['image'] = compact( 'src', 'width', 'height' ); 1080 list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumb' ); 1081 $track['thumb'] = compact( 'src', 'width', 'height' ); 1082 } 1083 } 1084 1085 $tracks[] = $track; 1086 } 1087 $data['tracks'] = $tracks; 1088 1089 ob_start(); 1090 1091 if ( 1 === $instance ): 1092 wp_enqueue_style( 'wp-mediaelement' ); 1093 wp_enqueue_script( 'wp-playlist' ); 1094 ?> 1095 <!--[if lt IE 9]><script>document.createElement('<?php echo $type ?>');</script><![endif]--> 1096 <script type="text/html" id="tmpl-wp-playlist-current-item"> 1097 <# if ( data.image ) { #> 1098 <img src="{{{ data.image.src }}}"/> 1099 <# } #> 1100 <# if ( data.meta.title ) { #> 1101 <div class="wp-playlist-caption"> 1102 <span class="wp-caption-meta wp-caption-title">“{{{ data.meta.title }}}”</span> 1103 <span class="wp-caption-meta wp-caption-album">{{{ data.meta.album }}}</span> 1104 <span class="wp-caption-meta wp-caption-artist">{{{ data.meta.artist }}}</span> 1105 </div> 1106 <# } else { #> 1107 <div class="wp-playlist-caption">{{{ data.caption }}}</div> 1108 <# } #> 1109 </script> 1110 <script type="text/html" id="tmpl-wp-playlist-item"> 1111 <div class="wp-playlist-item"> 1112 <# if ( ( data.title || data.meta.title ) && data.meta.artist ) { #> 1113 <div class="wp-playlist-caption"> 1114 {{{ data.index ? ( data.index + '. ' ) : '' }}} 1115 <span class="wp-caption-title">“{{{ data.title ? data.title : data.meta.title }}}”</span> 1116 <span class="wp-caption-by"><?php _e( 'by' ) ?></span> 1117 <span class="wp-caption-artist">{{{ data.meta.artist }}}</span> 1118 </div> 1119 <# } else { #> 1120 <div class="wp-playlist-caption">{{{ data.index ? ( data.index + '.' ) : '' }}} {{{ data.caption ? data.caption : data.title }}}</div> 1121 <# } #> 1122 <# if ( data.meta.length_formatted ) { #> 1123 <div class="wp-playlist-item-length">{{{ data.meta.length_formatted }}}</div> 1124 <# } #> 1125 </div> 1126 </script> 1127 <?php endif ?> 1128 <div class="wp-playlist wp-<?php echo $type ?>-playlist wp-playlist-<?php echo $style ?>"> 1129 <?php if ( 'audio' === $type ): ?> 1130 <div class="wp-playlist-current-item"></div> 1131 <?php endif ?> 1132 <<?php echo $type ?> controls="controls" preload="metadata" width="<?php echo $content_width - $outer ?>"></<?php echo $type ?>> 1133 <div class="wp-playlist-next"></div> 1134 <div class="wp-playlist-prev"></div> 1135 <noscript> 1136 <?php 1137 $output = "\n"; 1138 foreach ( $attachments as $att_id => $attachment ) { 1139 $output .= wp_get_attachment_link( $att_id ) . "\n"; 1140 } 1141 1142 echo $output; 1143 ?> 1144 </noscript> 1145 <script type="application/json"><?php echo json_encode( $data ) ?></script> 1146 </div> 1147 <?php 1148 return ob_get_clean(); 1149 } 1150 1151 function wp_playlist_shortcode( $attr ) { 1152 return wp_get_playlist( $attr, 'audio' ); 1153 } 1154 add_shortcode( 'playlist', 'wp_playlist_shortcode' ); 1155 1156 function wp_video_playlist_shortcode( $attr ) { 1157 return wp_get_playlist( $attr, 'video' ); 1158 } 1159 add_shortcode( 'video-playlist', 'wp_video_playlist_shortcode' ); 1160 1161 /** 937 1162 * Provide a No-JS Flash fallback as a last resort for audio / video 938 1163 * 939 1164 * @since 3.6.0 … … 2012 2237 'nonce' => wp_create_nonce( 'update-post_' . $post->ID ), 2013 2238 ); 2014 2239 2015 if ( current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail') ) {2240 if ( theme_supports_thumbnails( $post ) && post_supports_thumbnails( $post ) ) { 2016 2241 $featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true ); 2017 2242 $settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1; 2018 2243 } … … 2044 2269 'mediaLibraryTitle' => __( 'Media Library' ), 2045 2270 'insertMediaTitle' => __( 'Insert Media' ), 2046 2271 'createNewGallery' => __( 'Create a new gallery' ), 2272 'createNewPlaylist' => __( 'Create a new playlist' ), 2273 'createNewVideoPlaylist' => __( 'Create a new video playlist' ), 2047 2274 'returnToLibrary' => __( '← Return to library' ), 2048 2275 'allMediaItems' => __( 'All media items' ), 2049 2276 'noItemsFound' => __( 'No items found.' ), … … 2071 2298 // Edit Image 2072 2299 'imageDetailsTitle' => __( 'Image Details' ), 2073 2300 'imageReplaceTitle' => __( 'Replace Image' ), 2074 'imageDetailsCancel' => __( 'Cancel Edit' ) 2301 'imageDetailsCancel' => __( 'Cancel Edit' ), 2302 2303 // Playlist 2304 'playlistDragInfo' => __( 'Drag and drop to reorder tracks.' ), 2305 'createPlaylistTitle' => __( 'Create Playlist' ), 2306 'editPlaylistTitle' => __( 'Edit Playlist' ), 2307 'cancelPlaylistTitle' => __( '← Cancel Playlist' ), 2308 'insertPlaylist' => __( 'Insert playlist' ), 2309 'updatePlaylist' => __( 'Update playlist' ), 2310 'addToPlaylist' => __( 'Add to playlist' ), 2311 'addToPlaylistTitle' => __( 'Add to Playlist' ), 2312 2313 // Video Playlist 2314 'videoPlaylistDragInfo' => __( 'Drag and drop to reorder videos.' ), 2315 'createVideoPlaylistTitle' => __( 'Create Video Playlist' ), 2316 'editVideoPlaylistTitle' => __( 'Edit Video Playlist' ), 2317 'cancelVideoPlaylistTitle' => __( '← Cancel Video Playlist' ), 2318 'insertVideoPlaylist' => __( 'Insert Video playlist' ), 2319 'updateVideoPlaylist' => __( 'Update Video playlist' ), 2320 'addToVideoPlaylist' => __( 'Add to Video playlist' ), 2321 'addToVideoPlaylistTitle' => __( 'Add to Video Playlist' ), 2075 2322 ); 2076 2323 2077 2324 $settings = apply_filters( 'media_view_settings', $settings, $post ); … … 2240 2487 /** 2241 2488 * If an attachment is missing its metadata, try to regenerate it 2242 2489 * 2490 * @since 3.9.0 2491 * 2243 2492 * @param post $attachment Post object. 2244 2493 */ 2245 2494 function maybe_regenerate_attachment_metadata( $attachment ) { … … 2258 2507 delete_transient( $regeneration_lock ); 2259 2508 } 2260 2509 } 2510 } 2511 2512 /** 2513 * Whether a post supports thumbnails 2514 * 2515 * @since 3.9.0 2516 * 2517 * @param WP_Post $post 2518 * 2519 * @return boolean 2520 */ 2521 function post_supports_thumbnails( $post ) { 2522 if ( 'attachment' === $post->post_type ) { 2523 if ( 0 === strpos( $post->post_mime_type, 'audio' ) ) { 2524 return post_type_supports( 'attachment:audio', 'thumbnail' ); 2525 } elseif ( 0 === strpos( $post->post_mime_type, 'video' ) ) { 2526 return post_type_supports( 'attachment:video', 'thumbnail' ); 2527 } 2528 } 2529 2530 return post_type_supports( $post->post_type, 'thumbnail' ); 2531 } 2532 2533 /** 2534 * Whether a theme supports thumbnails 2535 * 2536 * @since 3.9.0 2537 * 2538 * @param WP_Post $post 2539 * 2540 * @return boolean 2541 */ 2542 function theme_supports_thumbnails( $post ) { 2543 if ( 'attachment' === $post->post_type ) { 2544 if ( 0 === strpos( $post->post_mime_type, 'audio' ) ) { 2545 return current_theme_supports( 'post-thumbnails', 'attachment:audio' ); 2546 } elseif ( 0 === strpos( $post->post_mime_type, 'video' ) ) { 2547 return current_theme_supports( 'post-thumbnails', 'attachment:video' ); 2548 } 2549 } 2550 2551 return current_theme_supports( 'post-thumbnails', $post->post_type ); 2261 2552 } 2553 No newline at end of file -
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',