WordPress.org

Make WordPress Core

Ticket #24716: 24716.15.diff

File 24716.15.diff, 43.8 KB (added by wonderboymusic, 3 years ago)
  • src/wp-admin/upload.php

     
    2222 
    2323if ( 'grid' === $mode ) { 
    2424        wp_enqueue_media(); 
     25        wp_enqueue_script( 'media-grid' ); 
    2526        wp_enqueue_script( 'media' ); 
    2627        require_once( ABSPATH . 'wp-admin/admin-header.php' ); 
    27         ?><div class="view-switch media-grid-view-switch"> 
    28                 <a href="<?php echo esc_url( add_query_arg( 'mode', 'list', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-list"> 
    29                         <img id="view-switch-list" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="List View" alt="List View"/> 
    30                 </a> 
    31                 <a href="<?php echo esc_url( add_query_arg( 'mode', 'grid', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-grid current"> 
    32                         <img id="view-switch-excerpt" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="Grid View" alt="Grid View"/> 
    33                 </a> 
    34         </div><?php 
    3528        include( ABSPATH . 'wp-admin/admin-footer.php' ); 
    3629        exit; 
    3730} 
  • src/wp-includes/css/media-views.css

     
    750750        max-height: 100%; 
    751751} 
    752752 
     753.attachment-preview.type-audio .thumbnail, 
     754.attachment-preview.type-video .thumbnail { 
     755        z-index: 1; 
     756        margin: 5%; 
     757        max-width: 90%; 
     758        max-height: 90%; 
     759} 
     760 
     761.media-frame-content .attachment-preview.type-audio .icon, 
     762.media-frame-content .attachment-preview.type-video .icon { 
     763        z-index: 2; 
     764        background: #f1f1f1; 
     765        position: relative; 
     766        padding: 0; 
     767        top: 15%; 
     768        left: auto; 
     769        right: auto; 
     770} 
     771 
     772.attachment-preview.type-audio .filename, 
     773.attachment-preview.type-video .filename { 
     774        z-index: 3; 
     775} 
     776 
    753777.attachment-preview .thumbnail:after { 
    754778        content: ''; 
    755779        display: block; 
     
    909933        border-radius: 0; 
    910934} 
    911935 
     936.attachment .data-fields { 
     937        margin: 5px 0 0; 
     938} 
     939 
     940.attachment .data-field { 
     941        white-space: nowrap; 
     942        text-overflow: ellipsis; 
     943        overflow: hidden; 
     944        display: block; 
     945        line-height: 19px; 
     946        height: 19px; 
     947        text-align: left; 
     948        width: 90%; 
     949        margin: 0 5%; 
     950} 
     951 
    912952/** 
    913953 * Attachments Browser 
    914954 */ 
     
    924964        height: 50px; 
    925965} 
    926966 
     967.attachments-browser.hide-sidebar .media-toolbar { 
     968        right: 0; 
     969} 
     970 
    927971.attachments-browser .media-toolbar-primary > .media-button, 
    928972.attachments-browser .media-toolbar-primary > .media-button-group, 
    929973.attachments-browser .media-toolbar-secondary > .media-button, 
     
    942986        outline: none; 
    943987} 
    944988 
     989.inline-toolbar { 
     990        position: absolute; 
     991        top: 0; 
     992        left: 0; 
     993        display: none; 
     994        z-index: 100; 
     995} 
     996 
     997.inline-toolbar .remove { 
     998        display: none; 
     999} 
     1000 
     1001.active-video .inline-toolbar .remove { 
     1002        display: inline-block; 
     1003} 
     1004 
     1005.attachment:hover .inline-toolbar { 
     1006        display: block; 
     1007} 
     1008 
     1009.inline-toolbar div, 
     1010.inline-toolbar .inline-media-control { 
     1011        display: inline-block; 
     1012        margin-top: 4px; 
     1013        margin-left: 4px; 
     1014        padding: 2px; 
     1015        width: 20px; 
     1016        height: 20px; 
     1017        box-shadow: 0 1px 3px rgba(0,0,0,0.5); 
     1018        background-color: #000; 
     1019        background-color: rgba(0,0,0,0.9); 
     1020        cursor: pointer; 
     1021        color: white; 
     1022        font-size: 20px; 
     1023} 
     1024 
     1025.ie8 .inline-toolbar div, 
     1026.ie7 .inline-toolbar div { 
     1027        display: inline; 
     1028        padding: 0; 
     1029} 
     1030 
     1031.inline-media-control span { 
     1032        display: block; 
     1033        width: 16px; 
     1034        height: 16px; 
     1035        margin: 2px; 
     1036        background: url(/wp-includes/js/mediaelement/controls.png) 0 0 no-repeat; 
     1037} 
     1038 
     1039.inline-media-control.active span { 
     1040        margin: 2px; 
     1041        background-position: 0 -16px; 
     1042} 
     1043 
     1044.inline-media-control.paused span { 
     1045        margin: 2px; 
     1046        background-position: 0 0; 
     1047} 
     1048 
     1049audio#inline-media-node { 
     1050        display: none; 
     1051} 
     1052 
     1053video#inline-media-node { 
     1054        position: relative; 
     1055        z-index: 5; 
     1056        top: 0; 
     1057        left: 0; 
     1058} 
     1059 
     1060.inline-video-wrap { 
     1061        width: 100%; 
     1062        height: auto; 
     1063        position: absolute; 
     1064        z-index: 5; 
     1065        background: #000; 
     1066        padding: 10px 0 5px; 
     1067        top: 0; 
     1068        left: 0; 
     1069} 
     1070 
     1071.attachments-browser.hide-sidebar .attachments { 
     1072        right: 0; 
     1073} 
     1074 
    9451075.attachments-browser .instructions { 
    9461076        display: inline-block; 
    9471077        margin-top: 16px; 
     
    23882518        line-height: 29px; 
    23892519} 
    23902520 
    2391 .media-grid-view-switch { 
    2392         position: fixed; 
    2393         right: 10px; 
    2394         top: 44px; 
    2395         z-index: 300; 
     2521.media-grid-view .view-switch { 
     2522        display: inline-block; 
     2523        float: none; 
     2524        margin-top: 13px; 
     2525        vertical-align: middle; 
    23962526} 
    23972527 
    23982528/** 
     
    24272557        display: none; 
    24282558} 
    24292559 
     2560/** 
     2561 * Copied styles from the Add theme toolbar. 
     2562 * 
     2563 * This should be OOCSS'd so both use a shared selector. 
     2564 */ 
     2565.media-grid-view .media-toolbar { 
     2566        background: #fff; 
     2567        -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1); 
     2568        box-shadow: 0 1px 1px 0 rgba(0,0,0,.1); 
     2569        -webkit-box-sizing: border-box; 
     2570        -moz-box-sizing: border-box; 
     2571        box-sizing: border-box; 
     2572        color: #555; 
     2573        display: inline-block; 
     2574        font-size: 13px; 
     2575        padding: 0 20px; 
     2576        position: relative; 
     2577        width: 100%; 
     2578} 
     2579 
     2580/** 
     2581 * The left and right buttons are copied from the expanded theme details modal. 
     2582 * 
     2583 * This should be OOCSS'd so both use a shared selector. 
     2584 */ 
     2585.edit-attachment-frame .edit-media-header .left, 
     2586.edit-attachment-frame .edit-media-header .right { 
     2587        cursor: pointer; 
     2588        color: #777; 
     2589        background-color: transparent; 
     2590        height: 48px; 
     2591        width: 54px; 
     2592        float: left; 
     2593        text-align: center; 
     2594        border: 0; 
     2595        border-right: 1px solid #ddd; 
     2596} 
     2597 
     2598.edit-attachment-frame .edit-media-header .right:before, 
     2599.edit-attachment-frame .edit-media-header .left:before { 
     2600        font: normal 20px/50px 'dashicons' !important; 
     2601        display: inline; 
     2602        font-weight: 300; 
     2603} 
     2604 
     2605 
     2606.edit-attachment-frame .edit-media-header .left:before { 
     2607        content: '\f340'; 
     2608} 
     2609 
     2610.edit-attachment-frame .edit-media-header .right:before { 
     2611        content: '\f344'; 
     2612} 
     2613 
     2614.edit-attachment-frame .edit-media-header .left.disabled, 
     2615.edit-attachment-frame .edit-media-header .right.disabled, 
     2616.edit-attachment-frame .edit-media-header .left.disabled:hover, 
     2617.edit-attachment-frame .edit-media-header .right.disabled:hover { 
     2618        color: #ccc; 
     2619        background: inherit; 
     2620        cursor: inherit; 
     2621} 
     2622 
     2623.edit-attachment-frame .edit-media-header .close:hover, 
     2624.edit-attachment-frame .edit-media-header .right:hover, 
     2625.edit-attachment-frame .edit-media-header .left:hover, 
     2626.edit-attachment-frame .edit-media-header .close:focus, 
     2627.edit-attachment-frame .edit-media-header .right:focus, 
     2628.edit-attachment-frame .edit-media-header .left:focus { 
     2629        background: #0074a2; 
     2630        color: #fff; 
     2631} 
     2632 
     2633.edit-attachment-frame .media-frame-content, 
     2634.edit-attachment-frame .media-frame-router { 
     2635        left: 0; 
     2636} 
     2637 
     2638/* Hiding this for the moment instead of removing it from the template. */ 
     2639.edit-attachment-frame h3 { 
     2640        display: none; 
     2641} 
     2642 
     2643.edit-attachment-frame .attachment-details { 
     2644        position: absolute; 
     2645        overflow: auto; 
     2646        top: 0; 
     2647        bottom: 0; 
     2648        right: 0; 
     2649        left: 0; 
     2650} 
     2651 
     2652.edit-attachment-frame .attachment-info { 
     2653        border-bottom: 0; 
     2654        border-right: 1px solid #ddd; 
     2655        bottom: 0; 
     2656        position: absolute; 
     2657        top: 0; 
     2658        left: 0; 
     2659        margin-bottom: 0; 
     2660        padding: 2% 4%; 
     2661        right: 50%; 
     2662} 
     2663 
     2664.edit-attachment-frame .attachment-info .thumbnail { 
     2665        max-width: none; 
     2666        max-height: none; 
     2667} 
     2668 
     2669.edit-attachment-frame .attachment-info .thumbnail-image img { 
     2670        margin: 0; 
     2671} 
     2672 
     2673.edit-attachment-frame .attachment-info .thumbnail-image:after { 
     2674        -webkit-box-shadow: none; 
     2675                box-shadow: none; 
     2676} 
     2677 
     2678.edit-attachment-frame .attachment-info .thumbnail img { 
     2679        max-width: none; 
     2680        max-height: 50%; 
     2681} 
     2682 
     2683.edit-attachment-frame .attachment-info .details { 
     2684        float: none; 
     2685} 
     2686 
     2687.edit-attachment-frame .attachment-fields { 
     2688        bottom: 0; 
     2689        padding: 2% 4%; 
     2690        position: absolute; 
     2691        top: 0; 
     2692        left: 50%; 
     2693        right: 0; 
     2694} 
     2695 
     2696.edit-attachment-frame .attachment-fields .setting { 
     2697        display: block; 
     2698        float: left; 
     2699        width: 100%; 
     2700        margin: 1px 0; 
     2701} 
     2702 
     2703.edit-attachment-frame .attachment-fields .setting label { 
     2704        display: block; 
     2705} 
     2706 
     2707.edit-attachment-frame .attachment-fields .setting .link-to-custom { 
     2708        margin: 3px 0; 
     2709} 
     2710 
     2711.edit-attachment-frame .attachment-fields .setting .name { 
     2712        min-width: 30%; 
     2713        margin-right: 4%; 
     2714        font-size: 12px; 
     2715        text-align: right; 
     2716} 
     2717 
     2718.edit-attachment-frame .attachment-fields .setting select { 
     2719        max-width: 65%; 
     2720} 
     2721 
     2722.edit-attachment-frame .attachment-fields .setting input[type="checkbox"], 
     2723.edit-attachment-frame .attachment-fields .field input[type="checkbox"] { 
     2724        width: 16px; 
     2725        float: none; 
     2726        margin: 8px 3px 0; 
     2727        padding: 0; 
     2728} 
     2729 
     2730.edit-attachment-frame .attachment-fields .setting span { 
     2731        float: left; 
     2732        min-height: 22px; 
     2733        padding-top: 8px; 
     2734        line-height: 16px; 
     2735        font-weight: normal; 
     2736        color: #666; 
     2737} 
     2738 
     2739.edit-attachment-frame .attachment-fields .setting input[type="text"], 
     2740.edit-attachment-frame .attachment-fields .setting input[type="password"], 
     2741.edit-attachment-frame .attachment-fields .setting input[type="number"], 
     2742.edit-attachment-frame .attachment-fields .setting input[type="search"], 
     2743.edit-attachment-frame .attachment-fields .setting input[type="email"], 
     2744.edit-attachment-frame .attachment-fields .setting input[type="url"], 
     2745.edit-attachment-frame .attachment-fields .setting textarea, 
     2746.edit-attachment-frame .attachment-fields .setting .value { 
     2747        margin: 1px; 
     2748        width: 65%; 
     2749        float: right; 
     2750        padding: 6px 8px; 
     2751        -webkit-box-sizing: border-box; 
     2752        -moz-box-sizing: border-box; 
     2753        box-sizing: border-box; 
     2754} 
     2755 
     2756.edit-attachment-frame .attachment-fields .setting textarea { 
     2757        height: 62px; 
     2758        resize: vertical; 
     2759} 
     2760 
     2761.edit-attachment-frame .attachment-fields select { 
     2762        margin-top: 3px; 
     2763} 
     2764 
     2765.media-grid-view.hide-router .media-frame-title { 
     2766        box-shadow: none; 
     2767} 
     2768 
    24302769.media-grid-view .media-frame-content { 
     2770        background-color: transparent; 
    24312771        bottom: 40px; 
    24322772} 
    24332773@media screen and (max-width: 782px) { 
  • src/wp-includes/js/media-audiovideo.js

     
    915915                } 
    916916        }); 
    917917 
     918        media.InlineMedia = Backbone.View.extend( _.extend( {}, media.mixin, { 
     919                initialize: function() { 
     920                        _.bindAll( this, 'setMedia', 'unsetMedia', 'pauseMedia', 'mediaSuccess' ); 
     921 
     922                        this.settings = baseSettings; 
     923                        this.settings.success = this.mediaSuccess; 
     924                        this.isPaused = false; 
     925                }, 
     926 
     927                players : [], 
     928 
     929                mediaSuccess: function( mediaElement ) { 
     930                        var $el = this.currentEl; 
     931 
     932                        this.mejs = mediaElement; 
     933                        this.mejs.load(); 
     934                        this.mejs.play(); 
     935                        this.mejs.addEventListener( 'ended', function() { 
     936                                $el.removeClass( 'active paused' ); 
     937                        } ); 
     938                }, 
     939 
     940                appendNode: function( $el ) { 
     941                        var url = $el.attr( 'href' ), 
     942                                type = $el.data( 'type' ), 
     943                                attrs, 
     944                                wrapClass, 
     945                                $node; 
     946 
     947                        wrapClass = 'inline-media-wrap inline-' + type + '-wrap'; 
     948                        $node = $( '<div class="' + wrapClass + '"></div>' ); 
     949 
     950                        attrs = { 
     951                                id: 'inline-media-node', 
     952                                preload: 'none', 
     953                                src: url, 
     954                                height: 'auto', 
     955                                width: '100%' 
     956                        }; 
     957 
     958                        $node.append( $( '<' + type + ' />' ).attr( attrs ) ); 
     959 
     960                        if ( 'audio' === type ) { 
     961                                $( 'body' ).append( $node.hide() ); 
     962                        } else { 
     963                                $el.parents( '.attachment' ).prepend( $node ).addClass( 'active-video' ); 
     964                        } 
     965                }, 
     966 
     967                playMedia: function( $el ) { 
     968                        var self = this; 
     969                        this.currentEl = $el; 
     970                        this.appendNode( $el ); 
     971                        this.isPaused = false; 
     972 
     973                        _.delay( function () { 
     974                                var player = new MediaElement( $( '#inline-media-node' ).get(0), self.settings ); 
     975                                self.players.push( player ); 
     976                        }, 50 ); 
     977                }, 
     978 
     979                pauseMedia: function(docEvent, e) { 
     980                        if ( this.isPaused ) { 
     981                                this.mejs.play(); 
     982                                this.isPaused = false; 
     983                        } else { 
     984                                this.mejs.pause(); 
     985                                this.isPaused = true; 
     986                        } 
     987 
     988                        $( e.currentTarget )[ ( this.isPaused ? 'add' : 'remove' ) + 'Class' ]( 'paused' ); 
     989                }, 
     990 
     991                setMedia: function(docEvent, e) { 
     992                        var $el = $( e.currentTarget ); 
     993                        this.unsetMedia(); 
     994 
     995                        $el.addClass( 'active' ); 
     996 
     997                        this.playMedia( $el ); 
     998                }, 
     999 
     1000                unsetMedia: function() { 
     1001                        var wraps = $( '.inline-media-wrap' ); 
     1002 
     1003                        $( '.inline-media-control' ).removeClass( 'active paused' ); 
     1004                        this.isPaused = false; 
     1005                        this.unsetPlayers(); 
     1006 
     1007                        wraps.parents( '.attachment' ).removeClass( 'active-video' ); 
     1008                        wraps.remove(); 
     1009                } 
     1010        } ) ); 
     1011 
    9181012        /** 
    9191013         * Event binding 
    9201014         */ 
    9211015        function init() { 
     1016                var inlineMedia = new media.InlineMedia(), currentInline; 
     1017 
    9221018                $(document.body) 
    9231019                        .on( 'click', '.add-media-source', function( e ) { 
    9241020                                media.frame.lastMime = $( e.currentTarget ).data( 'mime' ); 
    9251021                                media.frame.setState( 'add-' + media.frame.defaults.id + '-source' ); 
     1022                        } ) 
     1023                        .on( 'click', '.inline-media-control', function( e ) { 
     1024                                var $el = $( e.currentTarget ); 
     1025                                e.preventDefault(); 
     1026                                e.stopPropagation(); 
     1027 
     1028                                $el.parents( '.attachment' ).blur(); 
     1029 
     1030                                if ( $el.hasClass( 'active' ) ) { 
     1031                                        if ( currentInline && currentInline !== e.currentTarget ) { 
     1032                                                $( document ).trigger( 'inline:media:off', [ e ] ); 
     1033                                        } else { 
     1034                                                $( document ).trigger( 'inline:media:pause', [ e ] ); 
     1035                                        } 
     1036                                } else { 
     1037                                        $( document ).trigger( 'inline:media:on', [ e ] ); 
     1038                                } 
     1039                                currentInline = e.currentTarget; 
     1040                        } ) 
     1041                        .on( 'click', '.active-video .remove', function(e) { 
     1042                                $( e.currentTarget ).parents( '.attachment' ).blur(); 
     1043                                inlineMedia.unsetMedia(); 
    9261044                        } ); 
     1045 
     1046                $( document ) 
     1047                        .on( 'inline:media:on', inlineMedia.setMedia ) 
     1048                        .on( 'inline:media:pause', inlineMedia.pauseMedia ) 
     1049                        .on( 'inline:media:off', inlineMedia.unsetMedia ); 
    9271050        } 
    9281051 
    9291052        $( init ); 
  • src/wp-includes/js/media-grid.js

     
     1(function($, _, Backbone, wp) { 
     2        var media = wp.media, l10n; 
     3 
     4        // Link any localized strings. 
     5        if ( media.view.l10n ) { 
     6                l10n = media.view.l10n; 
     7        } else { 
     8                l10n = media.view.l10n = typeof _wpMediaViewsL10n === 'undefined' ? {} : _wpMediaViewsL10n; 
     9                delete l10n.settings; 
     10        } 
     11 
     12        /** 
     13         * A more abstracted state, because media.controller.State expects 
     14         * specific regions (menu, title, etc.) to exist on the frame, which do not 
     15         * exist in media.view.Frame.EditAttachment. 
     16         */ 
     17        media.controller._State = Backbone.Model.extend({ 
     18                constructor: function() { 
     19                        this.on( 'activate', this._preActivate, this ); 
     20                        this.on( 'activate', this.activate, this ); 
     21                        this.on( 'activate', this._postActivate, this ); 
     22                        this.on( 'deactivate', this._deactivate, this ); 
     23                        this.on( 'deactivate', this.deactivate, this ); 
     24                        this.on( 'reset', this.reset, this ); 
     25                        this.on( 'ready', this.ready, this ); 
     26                        /** 
     27                         * Call parent constructor with passed arguments 
     28                         */ 
     29                        Backbone.Model.apply( this, arguments ); 
     30                }, 
     31 
     32                /** 
     33                 * @abstract 
     34                 */ 
     35                ready: function() {}, 
     36                /** 
     37                 * @abstract 
     38                 */ 
     39                activate: function() {}, 
     40                /** 
     41                 * @abstract 
     42                 */ 
     43                deactivate: function() {}, 
     44                /** 
     45                 * @abstract 
     46                 */ 
     47                reset: function() {}, 
     48                /** 
     49                 * @access private 
     50                 */ 
     51                _preActivate: function() { 
     52                        this.active = true; 
     53                }, 
     54                /** 
     55                 * @access private 
     56                 */ 
     57                _postActivate: function() {}, 
     58                /** 
     59                 * @access private 
     60                 */ 
     61                _deactivate: function() { 
     62                        this.active = false; 
     63                } 
     64        }); 
     65 
     66        /** 
     67         * A state for editing (cropping, etc.) an image. 
     68         * 
     69         * @constructor 
     70         * @augments wp.media.controller.State 
     71         * @augments Backbone.Model 
     72         */ 
     73        media.controller.EditImageNoFrame = media.controller._State.extend({ 
     74                defaults: { 
     75                        id:      'edit-attachment', 
     76                        title:   l10n.editImage, 
     77                        // Region mode defaults. 
     78                        menu:    false, 
     79                        router:  'edit-metadata', 
     80                        content: 'edit-metadata', 
     81                        toolbar: 'toolbar', 
     82 
     83                        url:     '' 
     84                }, 
     85 
     86                initialize: function() { 
     87                        media.controller._State.prototype.initialize.apply( this, arguments ); 
     88                }, 
     89 
     90                activate: function() { 
     91                        this.listenTo( this.frame, 'toolbar:render:edit-image', this.toolbar ); 
     92                }, 
     93 
     94                _postActivate: function() { 
     95                        this._content(); 
     96                        this._router(); 
     97                }, 
     98 
     99                deactivate: function() { 
     100                        this.stopListening( this.frame ); 
     101                }, 
     102 
     103                toolbar: function() { 
     104                        var frame = this.frame, 
     105                                lastState = frame.lastState(), 
     106                                previous = lastState && lastState.id; 
     107 
     108                        frame.toolbar.set( new media.view.Toolbar({ 
     109                                controller: frame, 
     110                                items: { 
     111                                        back: { 
     112                                                style: 'primary', 
     113                                                text:     l10n.back, 
     114                                                priority: 20, 
     115                                                click:    function() { 
     116                                                        if ( previous ) { 
     117                                                                frame.setState( previous ); 
     118                                                        } else { 
     119                                                                frame.close(); 
     120                                                        } 
     121                                                } 
     122                                        } 
     123                                } 
     124                        }) ); 
     125                }, 
     126 
     127                /** 
     128                 * @access private 
     129                 */ 
     130                _router: function() { 
     131                        var router = this.frame.router, 
     132                                mode = this.get('router'), 
     133                                view; 
     134 
     135                        this.frame.$el.toggleClass( 'hide-router', ! mode ); 
     136                        if ( ! mode ) { 
     137                                return; 
     138                        } 
     139 
     140                        this.frame.router.render( mode ); 
     141 
     142                        view = router.get(); 
     143                        if ( view && view.select ) { 
     144                                view.select( this.frame.content.mode() ); 
     145                        } 
     146                }, 
     147 
     148                _content: function() { 
     149                        var mode = this.get( 'content' ); 
     150                        if ( mode ) { 
     151                                this.frame[ 'content' ].render( mode ); 
     152                        } 
     153                } 
     154        }); 
     155 
     156        /** 
     157         * wp.media.view.MediaFrame.Manage 
     158         * 
     159         * A generic management frame workflow. 
     160         * 
     161         * Used in the media grid view. 
     162         * 
     163         * @constructor 
     164         * @augments wp.media.view.MediaFrame 
     165         * @augments wp.media.view.Frame 
     166         * @augments wp.media.View 
     167         * @augments wp.Backbone.View 
     168         * @augments Backbone.View 
     169         * @mixes wp.media.controller.StateMachine 
     170         */ 
     171        media.view.MediaFrame.Manage = media.view.MediaFrame.extend({ 
     172                /** 
     173                 * @global wp.Uploader 
     174                 */ 
     175                initialize: function() { 
     176                        _.defaults( this.options, { 
     177                                title:     l10n.mediaLibraryTitle, 
     178                                modal:     false, 
     179                                selection: [], 
     180                                library:   {}, 
     181                                multiple:  false, 
     182                                state:     'library', 
     183                                uploader:  true, 
     184                                mode:      [ 'grid', 'edit' ] 
     185                        }); 
     186 
     187                        // Ensure core and media grid view UI is enabled. 
     188                        this.$el.addClass('wp-core-ui media-grid-view'); 
     189 
     190                        // Force the uploader off if the upload limit has been exceeded or 
     191                        // if the browser isn't supported. 
     192                        if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) { 
     193                                this.options.uploader = false; 
     194                        } 
     195 
     196                        // Initialize a window-wide uploader. 
     197                        if ( this.options.uploader ) { 
     198                                this.uploader = new media.view.UploaderWindow({ 
     199                                        controller: this, 
     200                                        uploader: { 
     201                                                dropzone:  $('body'), 
     202                                                container: $('body') 
     203                                        } 
     204                                }).render(); 
     205                                this.uploader.ready(); 
     206                                $('body').append( this.uploader.el ); 
     207 
     208                                this.options.uploader = false; 
     209                        } 
     210 
     211                        /** 
     212                         * call 'initialize' directly on the parent class 
     213                         */ 
     214                        media.view.MediaFrame.prototype.initialize.apply( this, arguments ); 
     215 
     216                        // Since we're not using the default modal built into 
     217                        // a media frame, append our $element to the supplied container. 
     218                        this.$el.appendTo( this.options.container ); 
     219 
     220                        this.createSelection(); 
     221                        this.createStates(); 
     222                        this.bindHandlers(); 
     223                        this.render(); 
     224                }, 
     225 
     226                createSelection: function() { 
     227                        var selection = this.options.selection; 
     228 
     229                        if ( ! (selection instanceof media.model.Selection) ) { 
     230                                this.options.selection = new media.model.Selection( selection, { 
     231                                        multiple: this.options.multiple 
     232                                }); 
     233                        } 
     234 
     235                        this._selection = { 
     236                                attachments: new media.model.Attachments(), 
     237                                difference: [] 
     238                        }; 
     239                }, 
     240 
     241                createStates: function() { 
     242                        var options = this.options; 
     243 
     244                        if ( this.options.states ) { 
     245                                return; 
     246                        } 
     247 
     248                        // Add the default states. 
     249                        this.states.add([ 
     250                                new media.controller.Library({ 
     251                                        library:    media.query( options.library ), 
     252                                        multiple:   options.multiple, 
     253                                        title:      options.title, 
     254                                        priority:   20, 
     255                                        toolbar:    false, 
     256                                        router:     false, 
     257                                        content:    'browse', 
     258                                        filterable: 'mime-types' 
     259                                }) 
     260                        ]); 
     261                }, 
     262 
     263                bindHandlers: function() { 
     264                        this.on( 'content:create:browse', this.browseContent, this ); 
     265                        this.on( 'content:render:edit-image', this.editImageContent, this ); 
     266 
     267                        // Handle a frame-level event for editing an attachment. 
     268                        this.on( 'edit:attachment', this.editAttachment, this ); 
     269                        this.on( 'edit:attachment:next', this.editNextAttachment, this ); 
     270                        this.on( 'edit:attachment:previous', this.editPreviousAttachment, this ); 
     271                }, 
     272 
     273                editPreviousAttachment: function( currentModel ) { 
     274                        var library = this.state().get('library'), 
     275                            currentModelIndex = library.indexOf( currentModel ); 
     276                        this.trigger( 'edit:attachment', library.at( currentModelIndex - 1 ) ); 
     277                }, 
     278 
     279                editNextAttachment: function( currentModel ) { 
     280                        var library = this.state().get('library'), 
     281                            currentModelIndex = library.indexOf( currentModel ); 
     282                        this.trigger( 'edit:attachment', library.at( currentModelIndex + 1 ) ); 
     283                }, 
     284 
     285                /** 
     286                 * Open the Edit Attachment modal. 
     287                 */ 
     288                editAttachment: function( model ) { 
     289                        var library = this.state().get('library'), hasPrevious, hasNext; 
     290                        if ( library.indexOf( model ) > 0 ) { 
     291                                hasPrevious = true; 
     292                        } 
     293                        else { 
     294                                hasPrevious = false; 
     295                        } 
     296                        if ( library.indexOf( model ) < library.length - 1 ) { 
     297                                hasNext = true; 
     298                        } 
     299                        else { 
     300                                hasNext = false; 
     301                        } 
     302 
     303                        new media.view.Frame.EditAttachment({ 
     304                                hasPrevious:    hasPrevious, 
     305                                hasNext:        hasNext, 
     306                                model:          model, 
     307                                gridController: this 
     308                        }); 
     309                }, 
     310 
     311                /** 
     312                 * Content 
     313                 * 
     314                 * @param {Object} content 
     315                 * @this wp.media.controller.Region 
     316                 */ 
     317                browseContent: function( content ) { 
     318                        var state = this.state(); 
     319 
     320                        // Browse our library of attachments. 
     321                        content.view = new media.view.AttachmentsBrowser({ 
     322                                controller: this, 
     323                                collection: state.get('library'), 
     324                                selection:  state.get('selection'), 
     325                                model:      state, 
     326                                sortable:   state.get('sortable'), 
     327                                search:     state.get('searchable'), 
     328                                filters:    state.get('filterable'), 
     329                                display:    state.get('displaySettings'), 
     330                                dragInfo:   state.get('dragInfo'), 
     331                                bulkEdit:   true, 
     332                                sidebar:    false, 
     333 
     334                                suggestedWidth:  state.get('suggestedWidth'), 
     335                                suggestedHeight: state.get('suggestedHeight'), 
     336 
     337                                AttachmentView: state.get('AttachmentView') 
     338                        }); 
     339                }, 
     340 
     341                editImageContent: function() { 
     342                        var image = this.state().get('image'), 
     343                                view = new media.view.EditImage( { model: image, controller: this } ).render(); 
     344 
     345                        this.content.set( view ); 
     346 
     347                        // after creating the wrapper view, load the actual editor via an ajax call 
     348                        view.loadEditor(); 
     349 
     350                } 
     351        }); 
     352 
     353        media.view.Attachment.Details.TwoColumn = media.view.Attachment.Details.extend({ 
     354                template: wp.template( 'attachment-details-two-column' ), 
     355 
     356                initialize: function() { 
     357                        this.$el.attr('aria-label', this.model.attributes.title).attr('aria-checked', false); 
     358                        this.model.on( 'change:sizes change:uploading', this.render, this ); 
     359                        this.model.on( 'change:title', this._syncTitle, this ); 
     360                        this.model.on( 'change:caption', this._syncCaption, this ); 
     361                        this.model.on( 'change:percent', this.progress, this ); 
     362 
     363                        // Update the selection. 
     364                        this.model.on( 'add', this.select, this ); 
     365                        this.model.on( 'remove', this.deselect, this ); 
     366                } 
     367        }); 
     368 
     369        /** 
     370         * A frame for editing the details of a specific media item. 
     371         * 
     372         * Opens in a modal by default. 
     373         * 
     374         * Requires an attachment model to be passed in the options hash under `model`. 
     375         */ 
     376        media.view.Frame.EditAttachment = media.view.Frame.extend({ 
     377 
     378                className: 'edit-attachment-frame', 
     379                template: media.template( 'edit-attachment-frame' ), 
     380                regions:   [ 'router', 'content' ], 
     381 
     382                events: { 
     383                        'click':                    'collapse', 
     384                        'click .delete-media-item': 'deleteMediaItem', 
     385                        'click .left':              'previousMediaItem', 
     386                        'click .right':             'nextMediaItem' 
     387                }, 
     388 
     389                initialize: function( options ) { 
     390                        var self = this; 
     391                        media.view.Frame.prototype.initialize.apply( this, arguments ); 
     392 
     393                        _.defaults( this.options, { 
     394                                modal: true, 
     395                                state: 'edit-attachment' 
     396                        }); 
     397 
     398                        this.createStates(); 
     399 
     400                        this.on( 'content:render:edit-metadata', this.editMetadataContent, this ); 
     401                        this.on( 'content:render:edit-image', this.editImageContentUgh, this ); 
     402 
     403                        // Only need a tab to Edit Image for images. 
     404                        if ( this.model.get( 'type' ) === 'image' ) { 
     405                                this.on( 'router:create', this.createRouter, this ); 
     406                                this.on( 'router:render', this.browseRouter, this ); 
     407                        } 
     408 
     409                        // Initialize modal container view. 
     410                        if ( this.options.modal ) { 
     411                                this.modal = new media.view.Modal({ 
     412                                        controller: this, 
     413                                        title:      this.options.title 
     414                                }); 
     415 
     416                                // Completely destroy the modal DOM element when closing it. 
     417                                this.modal.close = function() { 
     418                                        self.modal.remove(); 
     419                                }; 
     420 
     421                                this.modal.content( this ); 
     422                                this.modal.open(); 
     423                        } 
     424                }, 
     425 
     426                /** 
     427                 * Add the default states to the frame. 
     428                 */ 
     429                createStates: function() { 
     430                        this.states.add([ 
     431                                new media.controller.EditImageNoFrame( { model: this.model } ) 
     432                        ]); 
     433                }, 
     434 
     435                /** 
     436                 * @returns {wp.media.view.MediaFrame} Returns itself to allow chaining 
     437                 */ 
     438                render: function() { 
     439                        // Activate the default state if no active state exists. 
     440                        if ( ! this.state() && this.options.state ) { 
     441                                this.setState( this.options.state ); 
     442                        } 
     443                        /** 
     444                         * call 'render' directly on the parent class 
     445                         */ 
     446                        return media.view.Frame.prototype.render.apply( this, arguments ); 
     447                }, 
     448 
     449                /** 
     450                 * Content region rendering callback for the `edit-metadata` mode. 
     451                 */ 
     452                editMetadataContent: function() { 
     453                        var view = new media.view.Attachment.Details.TwoColumn({ 
     454                                controller: this, 
     455                                model:      this.model 
     456                        }); 
     457                        this.content.set( view ); 
     458                }, 
     459 
     460                /** 
     461                 * For some reason the view doesn't exist in the DOM yet, don't have the 
     462                 * patience to track this down right now. 
     463                 */ 
     464                editImageContentUgh: function() { 
     465                        _.defer( _.bind( this.editImageContent, this ) ); 
     466                }, 
     467 
     468                /** 
     469                 * Render the EditImage view into the frame's content region. 
     470                 */ 
     471                editImageContent: function() { 
     472                        var view = new media.view.EditImage( { model: this.model, controller: this } ).render(); 
     473 
     474                        this.content.set( view ); 
     475 
     476                        // after creating the wrapper view, load the actual editor via an ajax call 
     477                        view.loadEditor(); 
     478                }, 
     479 
     480                /** 
     481                 * Create the router view. 
     482                 * 
     483                 * @param {Object} router 
     484                 * @this wp.media.controller.Region 
     485                 */ 
     486                createRouter: function( router ) { 
     487                        router.view = new media.view.Router({ 
     488                                controller: this 
     489                        }); 
     490                }, 
     491 
     492                /** 
     493                 * Router rendering callback. 
     494                 * 
     495                 * @param  media.view.Router view Instantiated in this.createRouter() 
     496                 */ 
     497                browseRouter: function( view ) { 
     498                        view.set({ 
     499                                'edit-metadata': { 
     500                                        text:     'Edit Metadata', 
     501                                        priority: 20 
     502                                }, 
     503                                'edit-image': { 
     504                                        text:     'Edit Image', 
     505                                        priority: 40 
     506                                } 
     507                        }); 
     508                }, 
     509 
     510                /** 
     511                 * Click handler to switch to the previous media item. 
     512                 */ 
     513                previousMediaItem: function() { 
     514                        if ( ! this.options.hasPrevious ) 
     515                                return; 
     516                        this.modal.close(); 
     517                        this.options.gridController.trigger( 'edit:attachment:previous', this.model ); 
     518                }, 
     519 
     520                /** 
     521                 * Click handler to switch to the next media item. 
     522                 */ 
     523                nextMediaItem: function() { 
     524                        if ( ! this.options.hasNext ) 
     525                                return; 
     526                        this.modal.close(); 
     527                        this.options.gridController.trigger( 'edit:attachment:next', this.model ); 
     528                } 
     529 
     530        }); 
     531 
     532}(jQuery, _, Backbone, wp)); 
     533 No newline at end of file 
  • src/wp-includes/js/media-views.js

     
    17581758                        _.defaults( this.options, { 
    17591759                                title:    '', 
    17601760                                modal:    true, 
    1761                                 uploader: true 
     1761                                uploader: true, 
     1762                                mode:     ['select'] 
    17621763                        }); 
    17631764 
    17641765                        // Ensure core UI is enabled. 
     
    19551956        }); 
    19561957 
    19571958        /** 
    1958          * wp.media.view.MediaFrame.Manage 
    1959          * 
    1960          * A generic management frame workflow. 
    1961          * 
    1962          * Used in the media grid view. 
    1963          * 
    1964          * @constructor 
    1965          * @augments wp.media.view.MediaFrame 
    1966          * @augments wp.media.view.Frame 
    1967          * @augments wp.media.View 
    1968          * @augments wp.Backbone.View 
    1969          * @augments Backbone.View 
    1970          * @mixes wp.media.controller.StateMachine 
    1971          */ 
    1972         media.view.MediaFrame.Manage = media.view.MediaFrame.extend({ 
    1973                 /** 
    1974                  * @global wp.Uploader 
    1975                  */ 
    1976                 initialize: function() { 
    1977                         _.defaults( this.options, { 
    1978                                 title:     l10n.mediaLibraryTitle, 
    1979                                 modal:     false, 
    1980                                 selection: [], 
    1981                                 library:   {}, 
    1982                                 multiple:  false, 
    1983                                 state:     'library', 
    1984                                 uploader:  true 
    1985                         }); 
    1986  
    1987                         // Ensure core and media grid view UI is enabled. 
    1988                         this.$el.addClass('wp-core-ui media-grid-view'); 
    1989  
    1990                         // Force the uploader off if the upload limit has been exceeded or 
    1991                         // if the browser isn't supported. 
    1992                         if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) { 
    1993                                 this.options.uploader = false; 
    1994                         } 
    1995  
    1996                         // Initialize a window-wide uploader. 
    1997                         if ( this.options.uploader ) { 
    1998                                 this.uploader = new media.view.UploaderWindow({ 
    1999                                         controller: this, 
    2000                                         uploader: { 
    2001                                                 dropzone:  $('body'), 
    2002                                                 container: $('body') 
    2003                                         } 
    2004                                 }).render(); 
    2005                                 this.uploader.ready(); 
    2006                                 $('body').append( this.uploader.el ); 
    2007  
    2008                                 this.options.uploader = false; 
    2009                         } 
    2010  
    2011                         /** 
    2012                          * call 'initialize' directly on the parent class 
    2013                          */ 
    2014                         media.view.MediaFrame.prototype.initialize.apply( this, arguments ); 
    2015  
    2016                         // Since we're not using the default modal built into 
    2017                         // a media frame, append our $element to the supplied container. 
    2018                         this.$el.appendTo( this.options.container ); 
    2019  
    2020                         this.createSelection(); 
    2021                         this.createStates(); 
    2022                         this.bindHandlers(); 
    2023                         this.render(); 
    2024                 }, 
    2025  
    2026                 createSelection: function() { 
    2027                         var selection = this.options.selection; 
    2028  
    2029                         if ( ! (selection instanceof media.model.Selection) ) { 
    2030                                 this.options.selection = new media.model.Selection( selection, { 
    2031                                         multiple: this.options.multiple 
    2032                                 }); 
    2033                         } 
    2034  
    2035                         this._selection = { 
    2036                                 attachments: new media.model.Attachments(), 
    2037                                 difference: [] 
    2038                         }; 
    2039                 }, 
    2040  
    2041                 createStates: function() { 
    2042                         var options = this.options; 
    2043  
    2044                         if ( this.options.states ) { 
    2045                                 return; 
    2046                         } 
    2047  
    2048                         // Add the default states. 
    2049                         this.states.add([ 
    2050                                 new media.controller.Library({ 
    2051                                         library:    media.query( options.library ), 
    2052                                         multiple:   options.multiple, 
    2053                                         title:      options.title, 
    2054                                         priority:   20, 
    2055                                         toolbar:    false, 
    2056                                         router:     false, 
    2057                                         content:    'browse', 
    2058                                         filterable: 'mime-types' 
    2059                                 }), 
    2060  
    2061                                 new media.controller.EditImage( { model: options.editImage } ) 
    2062                         ]); 
    2063                 }, 
    2064  
    2065                 bindHandlers: function() { 
    2066                         this.on( 'content:create:browse', this.browseContent, this ); 
    2067                         this.on( 'content:render:edit-image', this.editImageContent, this ); 
    2068                 }, 
    2069  
    2070                 /** 
    2071                  * Content 
    2072                  * 
    2073                  * @param {Object} content 
    2074                  * @this wp.media.controller.Region 
    2075                  */ 
    2076                 browseContent: function( content ) { 
    2077                         var state = this.state(); 
    2078  
    2079                         // Browse our library of attachments. 
    2080                         content.view = new media.view.AttachmentsBrowser({ 
    2081                                 controller: this, 
    2082                                 collection: state.get('library'), 
    2083                                 selection:  state.get('selection'), 
    2084                                 model:      state, 
    2085                                 sortable:   state.get('sortable'), 
    2086                                 search:     state.get('searchable'), 
    2087                                 filters:    state.get('filterable'), 
    2088                                 display:    state.get('displaySettings'), 
    2089                                 dragInfo:   state.get('dragInfo'), 
    2090                                 bulkEdit:   true, 
    2091  
    2092                                 suggestedWidth:  state.get('suggestedWidth'), 
    2093                                 suggestedHeight: state.get('suggestedHeight'), 
    2094  
    2095                                 AttachmentView: state.get('AttachmentView') 
    2096                         }); 
    2097                 }, 
    2098  
    2099                 editImageContent: function() { 
    2100                         var image = this.state().get('image'), 
    2101                                 view = new media.view.EditImage( { model: image, controller: this } ).render(); 
    2102  
    2103                         this.content.set( view ); 
    2104  
    2105                         // after creating the wrapper view, load the actual editor via an ajax call 
    2106                         view.loadEditor(); 
    2107  
    2108                 } 
    2109         }); 
    2110  
    2111         /** 
    21121959         * wp.media.view.MediaFrame.Select 
    21131960         * 
    21141961         * Type of media frame that is used to select an item or items from the media library 
     
    46654512                        var selection = this.options.selection; 
    46664513 
    46674514                        this.$el.attr('aria-label', this.model.attributes.title).attr('aria-checked', false); 
    4668                         this.model.on( 'change:sizes change:uploading', this.render, this ); 
     4515                        this.model.on( 'change', this.render, this ); 
    46694516                        this.model.on( 'change:title', this._syncTitle, this ); 
    46704517                        this.model.on( 'change:caption', this._syncCaption, this ); 
    46714518                        this.model.on( 'change:percent', this.progress, this ); 
     
    47184565                                        compat:        false, 
    47194566                                        alt:           '', 
    47204567                                        description:   '' 
    4721                                 }); 
     4568                                }, this.options ); 
    47224569 
    47234570                        options.buttons  = this.buttons; 
    47244571                        options.describe = this.controller.state().get('describe'); 
     
    47684615                 */ 
    47694616                toggleSelectionHandler: function( event ) { 
    47704617                        var method; 
    4771  
    47724618                        // Catch enter and space events 
    47734619                        if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) { 
    47744620                                return; 
    47754621                        } 
     4622 
     4623                        // In the grid view, bubble up an edit:attachment event to the controller. 
     4624                        if ( _.contains( this.controller.options.mode, 'grid' ) ) { 
     4625                                this.controller.trigger( 'edit:attachment', this.model ); 
     4626                                return; 
     4627                        } 
     4628 
    47764629                        if ( event.shiftKey ) { 
    47774630                                method = 'between'; 
    47784631                        } else if ( event.ctrlKey || event.metaKey ) { 
     
    53035156                 */ 
    53045157                createAttachmentView: function( attachment ) { 
    53055158                        var view = new this.options.AttachmentView({ 
    5306                                 controller: this.controller, 
    5307                                 model:      attachment, 
    5308                                 collection: this.collection, 
    5309                                 selection:  this.options.selection 
     5159                                controller:           this.controller, 
     5160                                model:                attachment, 
     5161                                collection:           this.collection, 
     5162                                selection:            this.options.selection, 
     5163                                showAttachmentFields: this.options.showAttachmentFields 
    53105164                        }); 
    53115165 
    53125166                        return this._viewsByCid[ attachment.cid ] = view; 
     
    56035457                } 
    56045458        }); 
    56055459 
    5606  
    56075460        /** 
    56085461         * wp.media.view.AttachmentsBrowser 
    56095462         * 
     
    56215474                                filters: false, 
    56225475                                search:  true, 
    56235476                                display: false, 
    5624  
     5477                                sidebar: true, 
     5478                                showAttachmentFields: getUserSetting( 'showAttachmentFields', [ 'title', 'uploadedTo', 'dateFormatted', 'mime' ] ), 
    56255479                                AttachmentView: media.view.Attachment.Library 
    56265480                        }); 
    56275481 
    56285482                        this.createToolbar(); 
    56295483                        this.updateContent(); 
    5630                         this.createSidebar(); 
     5484                        if ( this.options.sidebar ) { 
     5485                                this.createSidebar(); 
     5486                        } else { 
     5487                                this.$el.addClass( 'hide-sidebar' ); 
     5488                        } 
    56315489 
    56325490                        this.collection.on( 'add remove reset', this.updateContent, this ); 
    56335491                }, 
     
    56525510 
    56535511                        this.views.add( this.toolbar ); 
    56545512 
     5513                        // Feels odd to bring the global media library switcher into the Attachment 
     5514                        // browser view. Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar ); 
     5515                        // which the controller can tap into and add this view? 
     5516                        if ( _.contains( this.controller.options.mode, 'grid' ) ) { 
     5517                                var libraryViewSwitcherConstructor = media.View.extend({ 
     5518                                        className: 'view-switch media-grid-view-switch', 
     5519                                        template: media.template( 'media-library-view-switcher') 
     5520                                }); 
     5521                                this.toolbar.set( 'libraryViewSwitcher', new libraryViewSwitcherConstructor({ 
     5522                                        controller: this.controller, 
     5523                                        priority: -90 
     5524                                }).render() ); 
     5525                        } 
     5526 
    56555527                        filters = this.options.filters; 
    56565528                        if ( 'uploaded' === filters ) { 
    56575529                                FiltersConstructor = media.view.AttachmentFilters.Uploaded; 
     
    57465618                        this.removeContent(); 
    57475619 
    57485620                        this.attachments = new media.view.Attachments({ 
    5749                                 controller: this.controller, 
    5750                                 collection: this.collection, 
    5751                                 selection:  this.options.selection, 
    5752                                 model:      this.model, 
    5753                                 sortable:   this.options.sortable, 
     5621                                controller:           this.controller, 
     5622                                collection:           this.collection, 
     5623                                selection:            this.options.selection, 
     5624                                model:                this.model, 
     5625                                sortable:             this.options.sortable, 
     5626                                showAttachmentFields: this.options.showAttachmentFields, 
    57545627 
    57555628                                // The single `Attachment` view to be used in the `Attachments` view. 
    57565629                                AttachmentView: this.options.AttachmentView 
  • src/wp-includes/media-template.php

     
    220220                </div> 
    221221        </script> 
    222222 
     223        <script type="text/html" id="tmpl-media-library-view-switcher"> 
     224                <a href="<?php echo esc_url( add_query_arg( 'mode', 'list', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-list"> 
     225                        <img id="view-switch-list" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="List View" alt="List View"/> 
     226                </a> 
     227                <a href="<?php echo esc_url( add_query_arg( 'mode', 'grid', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-grid current"> 
     228                        <img id="view-switch-excerpt" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="Grid View" alt="Grid View"/> 
     229                </a> 
     230        </script> 
     231 
    223232        <script type="text/html" id="tmpl-uploader-status"> 
    224233                <h3><?php _e( 'Uploading' ); ?></h3> 
    225234                <a class="upload-dismiss-errors" href="#"><?php _e('Dismiss Errors'); ?></a> 
     
    241250                <span class="upload-error-message">{{ data.message }}</span> 
    242251        </script> 
    243252 
     253        <script type="text/html" id="tmpl-edit-attachment-frame"> 
     254                <div class="edit-media-header"> 
     255                        <button class="left dashicons dashicons-no<# if ( ! data.hasPrevious ) { #> disabled <# } #>"><span class="screen-reader-text"><?php _e( 'Edit previous media item' ); ?></span></button> 
     256                        <button class="right dashicons dashicons-no<# if ( ! data.hasNext ) { #> disabled <# } #>"><span class="screen-reader-text"><?php _e( 'Edit next media item' ); ?></span></button> 
     257                </div> 
     258                <div class="media-frame-router"></div> 
     259                <div class="media-frame-content"></div> 
     260                <div class="media-frame-toolbar"></div> 
     261        </script> 
     262 
     263        <script type="text/html" id="tmpl-attachment-details-two-column"> 
     264                <h3> 
     265                        <?php _e('Attachment Details'); ?> 
     266 
     267                        <span class="settings-save-status"> 
     268                                <span class="spinner"></span> 
     269                                <span class="saved"><?php esc_html_e('Saved.'); ?></span> 
     270                        </span> 
     271                </h3> 
     272                <div class="attachment-info"> 
     273                        <div class="thumbnail thumbnail-{{ data.type }}"> 
     274                                <# if ( data.uploading ) { #> 
     275                                        <div class="media-progress-bar"><div></div></div> 
     276                                <# } else if ( 'image' === data.type ) { #> 
     277                                        <img src="{{ data.sizes.full.url }}" draggable="false" /> 
     278                                <# } else { #> 
     279                                        <img src="{{ data.icon }}" class="icon" draggable="false" /> 
     280                                <# } #> 
     281                        </div> 
     282                        <div class="details"> 
     283                                <div class="filename">{{ data.filename }}</div> 
     284                                <div class="uploaded">{{ data.dateFormatted }}</div> 
     285 
     286                                <div class="file-size">{{ data.filesizeHumanReadable }}</div> 
     287                                <# if ( 'image' === data.type && ! data.uploading ) { #> 
     288                                        <# if ( data.width && data.height ) { #> 
     289                                                <div class="dimensions">{{ data.width }} &times; {{ data.height }}</div> 
     290                                        <# } #> 
     291 
     292                                        <# if ( data.can.save ) { #> 
     293                                                <a class="edit-attachment" href="{{ data.editLink }}&amp;image-editor" target="_blank"><?php _e( 'Edit Image' ); ?></a> 
     294                                                <a class="refresh-attachment" href="#"><?php _e( 'Refresh' ); ?></a> 
     295                                        <# } #> 
     296                                <# } #> 
     297 
     298                                <# if ( data.fileLength ) { #> 
     299                                        <div class="file-length"><?php _e( 'Length:' ); ?> {{ data.fileLength }}</div> 
     300                                <# } #> 
     301 
     302                                <# if ( ! data.uploading && data.can.remove ) { #> 
     303                                        <?php if ( MEDIA_TRASH ): ?> 
     304                                                <a class="trash-attachment" href="#"><?php _e( 'Trash' ); ?></a> 
     305                                        <?php else: ?> 
     306                                                <a class="delete-attachment" href="#"><?php _e( 'Delete Permanently' ); ?></a> 
     307                                        <?php endif; ?> 
     308                                <# } #> 
     309 
     310                                <div class="compat-meta"> 
     311                                        <# if ( data.compat && data.compat.meta ) { #> 
     312                                                {{{ data.compat.meta }}} 
     313                                        <# } #> 
     314                                </div> 
     315                        </div> 
     316                </div> 
     317                <div class="attachment-fields"> 
     318                        <label class="setting" data-setting="url"> 
     319                                <span class="name"><?php _e('URL'); ?></span> 
     320                                <input type="text" value="{{ data.url }}" readonly /> 
     321                        </label> 
     322                        <# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #> 
     323                        <label class="setting" data-setting="title"> 
     324                                <span class="name"><?php _e('Title'); ?></span> 
     325                                <input type="text" value="{{ data.title }}" {{ maybeReadOnly }} /> 
     326                        </label> 
     327                        <label class="setting" data-setting="caption"> 
     328                                <span class="name"><?php _e('Caption'); ?></span> 
     329                                <textarea {{ maybeReadOnly }}>{{ data.caption }}</textarea> 
     330                        </label> 
     331                        <# if ( 'image' === data.type ) { #> 
     332                                <label class="setting" data-setting="alt"> 
     333                                        <span class="name"><?php _e('Alt Text'); ?></span> 
     334                                        <input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} /> 
     335                                </label> 
     336                        <# } #> 
     337                        <label class="setting" data-setting="description"> 
     338                                <span class="name"><?php _e('Description'); ?></span> 
     339                                <textarea {{ maybeReadOnly }}>{{ data.description }}</textarea> 
     340                        </label> 
     341                        <label class="setting"> 
     342                                        <span class="name"><?php _e( 'Uploaded By' ); ?></span> 
     343                                        <span class="value">{{ data.authorName }}</span> 
     344                                </label> 
     345                        <# if ( data.uploadedTo ) { #> 
     346                                <label class="setting"> 
     347                                        <span class="name"><?php _e('Uploaded To'); ?></span> 
     348                                        <span class="value"><a href="{{ data.uploadedToLink }}">{{ data.uploadedToTitle }}</a></span> 
     349                                </label> 
     350                        <# } #> 
     351                </div> 
     352        </script> 
     353 
    244354        <script type="text/html" id="tmpl-attachment"> 
     355                <# if ( _.contains( data.controller.options.mode, 'grid' ) ) { #> 
     356                <div class="inline-toolbar"> 
     357                        <div class="dashicons dashicons-edit edit edit-media"></div> 
     358                        <div class="dashicons dashicons-no-alt remove"></div> 
     359                        <# if ( 'audio' === data.type || 'video' === data.type ) { #> 
     360                        <a class="inline-media-control" href="{{ data.url }}" data-type="{{ data.type }}"><span></span></a> 
     361                        <# } #> 
     362                </div> 
     363                <# } #> 
    245364                <div class="attachment-preview type-{{ data.type }} subtype-{{ data.subtype }} {{ data.orientation }}"> 
    246365                        <# if ( data.uploading ) { #> 
    247366                                <div class="media-progress-bar"><div></div></div> 
     
    251370                                                <img src="{{ data.size.url }}" draggable="false" alt="" /> 
    252371                                        </div> 
    253372                                </div> 
    254                         <# } else { #> 
     373                        <# } else { 
     374                                if ( data.thumb && data.thumb.src && data.thumb.src !== data.icon ) { 
     375                                #><img src="{{ data.thumb.src }}" class="thumbnail" draggable="false" /><# 
     376                                } #> 
    255377                                <img src="{{ data.icon }}" class="icon" draggable="false" /> 
    256378                                <div class="filename"> 
    257379                                        <div>{{ data.filename }}</div> 
    258380                                </div> 
    259381                        <# } #> 
    260  
    261382                        <# if ( data.buttons.close ) { #> 
    262383                                <a class="close media-modal-icon" href="#" title="<?php esc_attr_e('Remove'); ?>"></a> 
    263384                        <# } #> 
     
    268389                </div> 
    269390                <# 
    270391                var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; 
    271                 if ( data.describe ) { #> 
    272                         <# if ( 'image' === data.type ) { #> 
     392                if ( data.describe ) { 
     393                        if ( 'image' === data.type ) { #> 
    273394                                <input type="text" value="{{ data.caption }}" class="describe" data-setting="caption" 
    274395                                        placeholder="<?php esc_attr_e('Caption this image&hellip;'); ?>" {{ maybeReadOnly }} /> 
    275396                        <# } else { #> 
     
    281402                                        <# } else { #> 
    282403                                                placeholder="<?php esc_attr_e('Describe this media file&hellip;'); ?>" 
    283404                                        <# } #> {{ maybeReadOnly }} /> 
    284                         <# } #> 
     405                        <# } 
     406                } 
     407 
     408                if ( _.contains( data.controller.options.mode, 'grid' ) ) { #> 
     409                <div class="data-fields"> 
     410                <# _.each( data.showAttachmentFields, function( field ) { #> 
     411                        <div class="data-field data-{{ field }}"><# 
     412                                if ( 'uploadedTo' === field ) { 
     413                                        if ( data[field] ) { 
     414                                        #><?php _e( 'Uploaded To:' ) ?><# 
     415                                        } else { 
     416                                        #><?php _e( 'Unattached' ) ?><# 
     417                                        } 
     418                                } else if ( 'title' === field && ! data[ field ] ) { 
     419                                #><?php _e( '(No title)' ) ?><# 
     420                                } 
     421 
     422                                if ( data[ field ] ) { 
     423                                        #>{{ data[ field ] }}<# 
     424                                } 
     425                        #></div> 
     426                <# }); #> 
     427                </div> 
    285428                <# } #> 
     429 
    286430        </script> 
    287431 
    288432        <script type="text/html" id="tmpl-attachment-details"> 
  • src/wp-includes/script-loader.php

     
    506506                $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox' ), false, 1 ); 
    507507 
    508508                $scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" ); 
    509  
     509                $scripts->add( 'media-grid', "/wp-includes/js/media-grid$suffix.js", array( 'media-editor' ), false, 1 ); 
    510510                $scripts->add( 'media', "/wp-admin/js/media$suffix.js", array( 'jquery' ), false, 1 ); 
    511511                did_action( 'init' ) && $scripts->localize( 'media', 'attachMediaBoxL10n', array( 
    512512                        'error' => __( 'An error has occurred. Please reload the page and try again.' ),