diff options
Diffstat (limited to 'srcs/wordpress/wp-includes/js/media-views.js')
| -rw-r--r-- | srcs/wordpress/wp-includes/js/media-views.js | 10164 |
1 files changed, 10164 insertions, 0 deletions
diff --git a/srcs/wordpress/wp-includes/js/media-views.js b/srcs/wordpress/wp-includes/js/media-views.js new file mode 100644 index 0000000..049e462 --- /dev/null +++ b/srcs/wordpress/wp-includes/js/media-views.js @@ -0,0 +1,10164 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 29); +/******/ }) +/************************************************************************/ +/******/ (Array(29).concat([ +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = __webpack_require__(30); + + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + +/** + * @output wp-includes/js/media-views.js + */ + +var media = wp.media, + $ = jQuery, + l10n; + +media.isTouchDevice = ( 'ontouchend' in document ); + +// Link any localized strings. +l10n = media.view.l10n = window._wpMediaViewsL10n || {}; + +// Link any settings. +media.view.settings = l10n.settings || {}; +delete l10n.settings; + +// Copy the `post` setting over to the model settings. +media.model.settings.post = media.view.settings.post; + +// Check if the browser supports CSS 3.0 transitions +$.support.transition = (function(){ + var style = document.documentElement.style, + transitions = { + WebkitTransition: 'webkitTransitionEnd', + MozTransition: 'transitionend', + OTransition: 'oTransitionEnd otransitionend', + transition: 'transitionend' + }, transition; + + transition = _.find( _.keys( transitions ), function( transition ) { + return ! _.isUndefined( style[ transition ] ); + }); + + return transition && { + end: transitions[ transition ] + }; +}()); + +/** + * A shared event bus used to provide events into + * the media workflows that 3rd-party devs can use to hook + * in. + */ +media.events = _.extend( {}, Backbone.Events ); + +/** + * Makes it easier to bind events using transitions. + * + * @param {string} selector + * @param {Number} sensitivity + * @returns {Promise} + */ +media.transition = function( selector, sensitivity ) { + var deferred = $.Deferred(); + + sensitivity = sensitivity || 2000; + + if ( $.support.transition ) { + if ( ! (selector instanceof $) ) { + selector = $( selector ); + } + + // Resolve the deferred when the first element finishes animating. + selector.first().one( $.support.transition.end, deferred.resolve ); + + // Just in case the event doesn't trigger, fire a callback. + _.delay( deferred.resolve, sensitivity ); + + // Otherwise, execute on the spot. + } else { + deferred.resolve(); + } + + return deferred.promise(); +}; + +media.controller.Region = __webpack_require__( 31 ); +media.controller.StateMachine = __webpack_require__( 32 ); +media.controller.State = __webpack_require__( 33 ); + +media.selectionSync = __webpack_require__( 34 ); +media.controller.Library = __webpack_require__( 35 ); +media.controller.ImageDetails = __webpack_require__( 36 ); +media.controller.GalleryEdit = __webpack_require__( 37 ); +media.controller.GalleryAdd = __webpack_require__( 38 ); +media.controller.CollectionEdit = __webpack_require__( 39 ); +media.controller.CollectionAdd = __webpack_require__( 40 ); +media.controller.FeaturedImage = __webpack_require__( 41 ); +media.controller.ReplaceImage = __webpack_require__( 42 ); +media.controller.EditImage = __webpack_require__( 43 ); +media.controller.MediaLibrary = __webpack_require__( 44 ); +media.controller.Embed = __webpack_require__( 45 ); +media.controller.Cropper = __webpack_require__( 46 ); +media.controller.CustomizeImageCropper = __webpack_require__( 47 ); +media.controller.SiteIconCropper = __webpack_require__( 48 ); + +media.View = __webpack_require__( 49 ); +media.view.Frame = __webpack_require__( 50 ); +media.view.MediaFrame = __webpack_require__( 51 ); +media.view.MediaFrame.Select = __webpack_require__( 52 ); +media.view.MediaFrame.Post = __webpack_require__( 53 ); +media.view.MediaFrame.ImageDetails = __webpack_require__( 54 ); +media.view.Modal = __webpack_require__( 55 ); +media.view.FocusManager = __webpack_require__( 56 ); +media.view.UploaderWindow = __webpack_require__( 57 ); +media.view.EditorUploader = __webpack_require__( 58 ); +media.view.UploaderInline = __webpack_require__( 59 ); +media.view.UploaderStatus = __webpack_require__( 60 ); +media.view.UploaderStatusError = __webpack_require__( 61 ); +media.view.Toolbar = __webpack_require__( 62 ); +media.view.Toolbar.Select = __webpack_require__( 63 ); +media.view.Toolbar.Embed = __webpack_require__( 64 ); +media.view.Button = __webpack_require__( 65 ); +media.view.ButtonGroup = __webpack_require__( 66 ); +media.view.PriorityList = __webpack_require__( 67 ); +media.view.MenuItem = __webpack_require__( 68 ); +media.view.Menu = __webpack_require__( 69 ); +media.view.RouterItem = __webpack_require__( 70 ); +media.view.Router = __webpack_require__( 71 ); +media.view.Sidebar = __webpack_require__( 72 ); +media.view.Attachment = __webpack_require__( 73 ); +media.view.Attachment.Library = __webpack_require__( 74 ); +media.view.Attachment.EditLibrary = __webpack_require__( 75 ); +media.view.Attachments = __webpack_require__( 76 ); +media.view.Search = __webpack_require__( 77 ); +media.view.AttachmentFilters = __webpack_require__( 78 ); +media.view.DateFilter = __webpack_require__( 79 ); +media.view.AttachmentFilters.Uploaded = __webpack_require__( 80 ); +media.view.AttachmentFilters.All = __webpack_require__( 81 ); +media.view.AttachmentsBrowser = __webpack_require__( 82 ); +media.view.Selection = __webpack_require__( 83 ); +media.view.Attachment.Selection = __webpack_require__( 84 ); +media.view.Attachments.Selection = __webpack_require__( 85 ); +media.view.Attachment.EditSelection = __webpack_require__( 86 ); +media.view.Settings = __webpack_require__( 87 ); +media.view.Settings.AttachmentDisplay = __webpack_require__( 88 ); +media.view.Settings.Gallery = __webpack_require__( 89 ); +media.view.Settings.Playlist = __webpack_require__( 90 ); +media.view.Attachment.Details = __webpack_require__( 91 ); +media.view.AttachmentCompat = __webpack_require__( 92 ); +media.view.Iframe = __webpack_require__( 93 ); +media.view.Embed = __webpack_require__( 94 ); +media.view.Label = __webpack_require__( 95 ); +media.view.EmbedUrl = __webpack_require__( 96 ); +media.view.EmbedLink = __webpack_require__( 97 ); +media.view.EmbedImage = __webpack_require__( 98 ); +media.view.ImageDetails = __webpack_require__( 99 ); +media.view.Cropper = __webpack_require__( 100 ); +media.view.SiteIconCropper = __webpack_require__( 101 ); +media.view.SiteIconPreview = __webpack_require__( 102 ); +media.view.EditImage = __webpack_require__( 103 ); +media.view.Spinner = __webpack_require__( 104 ); +media.view.Heading = __webpack_require__( 105 ); + + +/***/ }), +/* 31 */ +/***/ (function(module, exports) { + +/** + * wp.media.controller.Region + * + * A region is a persistent application layout area. + * + * A region assumes one mode at any time, and can be switched to another. + * + * When mode changes, events are triggered on the region's parent view. + * The parent view will listen to specific events and fill the region with an + * appropriate view depending on mode. For example, a frame listens for the + * 'browse' mode t be activated on the 'content' view and then fills the region + * with an AttachmentsBrowser view. + * + * @memberOf wp.media.controller + * + * @class + * + * @param {object} options Options hash for the region. + * @param {string} options.id Unique identifier for the region. + * @param {Backbone.View} options.view A parent view the region exists within. + * @param {string} options.selector jQuery selector for the region within the parent view. + */ +var Region = function( options ) { + _.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) ); +}; + +// Use Backbone's self-propagating `extend` inheritance method. +Region.extend = Backbone.Model.extend; + +_.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{ + /** + * Activate a mode. + * + * @since 3.5.0 + * + * @param {string} mode + * + * @fires Region#activate + * @fires Region#deactivate + * + * @returns {wp.media.controller.Region} Returns itself to allow chaining. + */ + mode: function( mode ) { + if ( ! mode ) { + return this._mode; + } + // Bail if we're trying to change to the current mode. + if ( mode === this._mode ) { + return this; + } + + /** + * Region mode deactivation event. + * + * @event wp.media.controller.Region#deactivate + */ + this.trigger('deactivate'); + + this._mode = mode; + this.render( mode ); + + /** + * Region mode activation event. + * + * @event wp.media.controller.Region#activate + */ + this.trigger('activate'); + return this; + }, + /** + * Render a mode. + * + * @since 3.5.0 + * + * @param {string} mode + * + * @fires Region#create + * @fires Region#render + * + * @returns {wp.media.controller.Region} Returns itself to allow chaining + */ + render: function( mode ) { + // If the mode isn't active, activate it. + if ( mode && mode !== this._mode ) { + return this.mode( mode ); + } + + var set = { view: null }, + view; + + /** + * Create region view event. + * + * Region view creation takes place in an event callback on the frame. + * + * @event wp.media.controller.Region#create + * @type {object} + * @property {object} view + */ + this.trigger( 'create', set ); + view = set.view; + + /** + * Render region view event. + * + * Region view creation takes place in an event callback on the frame. + * + * @event wp.media.controller.Region#render + * @type {object} + */ + this.trigger( 'render', view ); + if ( view ) { + this.set( view ); + } + return this; + }, + + /** + * Get the region's view. + * + * @since 3.5.0 + * + * @returns {wp.media.View} + */ + get: function() { + return this.view.views.first( this.selector ); + }, + + /** + * Set the region's view as a subview of the frame. + * + * @since 3.5.0 + * + * @param {Array|Object} views + * @param {Object} [options={}] + * @returns {wp.Backbone.Subviews} Subviews is returned to allow chaining + */ + set: function( views, options ) { + if ( options ) { + options.add = false; + } + return this.view.views.set( this.selector, views, options ); + }, + + /** + * Trigger regional view events on the frame. + * + * @since 3.5.0 + * + * @param {string} event + * @returns {undefined|wp.media.controller.Region} Returns itself to allow chaining. + */ + trigger: function( event ) { + var base, args; + + if ( ! this._mode ) { + return; + } + + args = _.toArray( arguments ); + base = this.id + ':' + event; + + // Trigger `{this.id}:{event}:{this._mode}` event on the frame. + args[0] = base + ':' + this._mode; + this.view.trigger.apply( this.view, args ); + + // Trigger `{this.id}:{event}` event on the frame. + args[0] = base; + this.view.trigger.apply( this.view, args ); + return this; + } +}); + +module.exports = Region; + + +/***/ }), +/* 32 */ +/***/ (function(module, exports) { + +/** + * wp.media.controller.StateMachine + * + * A state machine keeps track of state. It is in one state at a time, + * and can change from one state to another. + * + * States are stored as models in a Backbone collection. + * + * @memberOf wp.media.controller + * + * @since 3.5.0 + * + * @class + * @augments Backbone.Model + * @mixin + * @mixes Backbone.Events + */ +var StateMachine = function() { + return { + // Use Backbone's self-propagating `extend` inheritance method. + extend: Backbone.Model.extend + }; +}; + +_.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{ + /** + * Fetch a state. + * + * If no `id` is provided, returns the active state. + * + * Implicitly creates states. + * + * Ensure that the `states` collection exists so the `StateMachine` + * can be used as a mixin. + * + * @since 3.5.0 + * + * @param {string} id + * @returns {wp.media.controller.State} Returns a State model + * from the StateMachine collection + */ + state: function( id ) { + this.states = this.states || new Backbone.Collection(); + + // Default to the active state. + id = id || this._state; + + if ( id && ! this.states.get( id ) ) { + this.states.add({ id: id }); + } + return this.states.get( id ); + }, + + /** + * Sets the active state. + * + * Bail if we're trying to select the current state, if we haven't + * created the `states` collection, or are trying to select a state + * that does not exist. + * + * @since 3.5.0 + * + * @param {string} id + * + * @fires wp.media.controller.State#deactivate + * @fires wp.media.controller.State#activate + * + * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining + */ + setState: function( id ) { + var previous = this.state(); + + if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) { + return this; + } + + if ( previous ) { + previous.trigger('deactivate'); + this._lastState = previous.id; + } + + this._state = id; + this.state().trigger('activate'); + + return this; + }, + + /** + * Returns the previous active state. + * + * Call the `state()` method with no parameters to retrieve the current + * active state. + * + * @since 3.5.0 + * + * @returns {wp.media.controller.State} Returns a State model + * from the StateMachine collection + */ + lastState: function() { + if ( this._lastState ) { + return this.state( this._lastState ); + } + } +}); + +// Map all event binding and triggering on a StateMachine to its `states` collection. +_.each([ 'on', 'off', 'trigger' ], function( method ) { + /** + * @function on + * @memberOf wp.media.controller.StateMachine + * @instance + * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining. + */ + /** + * @function off + * @memberOf wp.media.controller.StateMachine + * @instance + * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining. + */ + /** + * @function trigger + * @memberOf wp.media.controller.StateMachine + * @instance + * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining. + */ + StateMachine.prototype[ method ] = function() { + // Ensure that the `states` collection exists so the `StateMachine` + // can be used as a mixin. + this.states = this.states || new Backbone.Collection(); + // Forward the method to the `states` collection. + this.states[ method ].apply( this.states, arguments ); + return this; + }; +}); + +module.exports = StateMachine; + + +/***/ }), +/* 33 */ +/***/ (function(module, exports) { + +/** + * wp.media.controller.State + * + * A state is a step in a workflow that when set will trigger the controllers + * for the regions to be updated as specified in the frame. + * + * A state has an event-driven lifecycle: + * + * 'ready' triggers when a state is added to a state machine's collection. + * 'activate' triggers when a state is activated by a state machine. + * 'deactivate' triggers when a state is deactivated by a state machine. + * 'reset' is not triggered automatically. It should be invoked by the + * proper controller to reset the state to its default. + * + * @memberOf wp.media.controller + * + * @class + * @augments Backbone.Model + */ +var State = Backbone.Model.extend(/** @lends wp.media.controller.State.prototype */{ + /** + * Constructor. + * + * @since 3.5.0 + */ + constructor: function() { + this.on( 'activate', this._preActivate, this ); + this.on( 'activate', this.activate, this ); + this.on( 'activate', this._postActivate, this ); + this.on( 'deactivate', this._deactivate, this ); + this.on( 'deactivate', this.deactivate, this ); + this.on( 'reset', this.reset, this ); + this.on( 'ready', this._ready, this ); + this.on( 'ready', this.ready, this ); + /** + * Call parent constructor with passed arguments + */ + Backbone.Model.apply( this, arguments ); + this.on( 'change:menu', this._updateMenu, this ); + }, + /** + * Ready event callback. + * + * @abstract + * @since 3.5.0 + */ + ready: function() {}, + + /** + * Activate event callback. + * + * @abstract + * @since 3.5.0 + */ + activate: function() {}, + + /** + * Deactivate event callback. + * + * @abstract + * @since 3.5.0 + */ + deactivate: function() {}, + + /** + * Reset event callback. + * + * @abstract + * @since 3.5.0 + */ + reset: function() {}, + + /** + * @access private + * @since 3.5.0 + */ + _ready: function() { + this._updateMenu(); + }, + + /** + * @access private + * @since 3.5.0 + */ + _preActivate: function() { + this.active = true; + }, + + /** + * @access private + * @since 3.5.0 + */ + _postActivate: function() { + this.on( 'change:menu', this._menu, this ); + this.on( 'change:titleMode', this._title, this ); + this.on( 'change:content', this._content, this ); + this.on( 'change:toolbar', this._toolbar, this ); + + this.frame.on( 'title:render:default', this._renderTitle, this ); + + this._title(); + this._menu(); + this._toolbar(); + this._content(); + this._router(); + }, + + /** + * @access private + * @since 3.5.0 + */ + _deactivate: function() { + this.active = false; + + this.frame.off( 'title:render:default', this._renderTitle, this ); + + this.off( 'change:menu', this._menu, this ); + this.off( 'change:titleMode', this._title, this ); + this.off( 'change:content', this._content, this ); + this.off( 'change:toolbar', this._toolbar, this ); + }, + + /** + * @access private + * @since 3.5.0 + */ + _title: function() { + this.frame.title.render( this.get('titleMode') || 'default' ); + }, + + /** + * @access private + * @since 3.5.0 + */ + _renderTitle: function( view ) { + view.$el.text( this.get('title') || '' ); + }, + + /** + * @access private + * @since 3.5.0 + */ + _router: function() { + var router = this.frame.router, + mode = this.get('router'), + view; + + this.frame.$el.toggleClass( 'hide-router', ! mode ); + if ( ! mode ) { + return; + } + + this.frame.router.render( mode ); + + view = router.get(); + if ( view && view.select ) { + view.select( this.frame.content.mode() ); + } + }, + + /** + * @access private + * @since 3.5.0 + */ + _menu: function() { + var menu = this.frame.menu, + mode = this.get('menu'), + view; + + this.frame.$el.toggleClass( 'hide-menu', ! mode ); + if ( ! mode ) { + return; + } + + menu.mode( mode ); + + view = menu.get(); + if ( view && view.select ) { + view.select( this.id ); + } + }, + + /** + * @access private + * @since 3.5.0 + */ + _updateMenu: function() { + var previous = this.previous('menu'), + menu = this.get('menu'); + + if ( previous ) { + this.frame.off( 'menu:render:' + previous, this._renderMenu, this ); + } + + if ( menu ) { + this.frame.on( 'menu:render:' + menu, this._renderMenu, this ); + } + }, + + /** + * Create a view in the media menu for the state. + * + * @access private + * @since 3.5.0 + * + * @param {media.view.Menu} view The menu view. + */ + _renderMenu: function( view ) { + var menuItem = this.get('menuItem'), + title = this.get('title'), + priority = this.get('priority'); + + if ( ! menuItem && title ) { + menuItem = { text: title }; + + if ( priority ) { + menuItem.priority = priority; + } + } + + if ( ! menuItem ) { + return; + } + + view.set( this.id, menuItem ); + } +}); + +_.each(['toolbar','content'], function( region ) { + /** + * @access private + */ + State.prototype[ '_' + region ] = function() { + var mode = this.get( region ); + if ( mode ) { + this.frame[ region ].render( mode ); + } + }; +}); + +module.exports = State; + + +/***/ }), +/* 34 */ +/***/ (function(module, exports) { + +/** + * wp.media.selectionSync + * + * Sync an attachments selection in a state with another state. + * + * Allows for selecting multiple images in the Add Media workflow, and then + * switching to the Insert Gallery workflow while preserving the attachments selection. + * + * @memberOf wp.media + * + * @mixin + */ +var selectionSync = { + /** + * @since 3.5.0 + */ + syncSelection: function() { + var selection = this.get('selection'), + manager = this.frame._selection; + + if ( ! this.get('syncSelection') || ! manager || ! selection ) { + return; + } + + // If the selection supports multiple items, validate the stored + // attachments based on the new selection's conditions. Record + // the attachments that are not included; we'll maintain a + // reference to those. Other attachments are considered in flux. + if ( selection.multiple ) { + selection.reset( [], { silent: true }); + selection.validateAll( manager.attachments ); + manager.difference = _.difference( manager.attachments.models, selection.models ); + } + + // Sync the selection's single item with the master. + selection.single( manager.single ); + }, + + /** + * Record the currently active attachments, which is a combination + * of the selection's attachments and the set of selected + * attachments that this specific selection considered invalid. + * Reset the difference and record the single attachment. + * + * @since 3.5.0 + */ + recordSelection: function() { + var selection = this.get('selection'), + manager = this.frame._selection; + + if ( ! this.get('syncSelection') || ! manager || ! selection ) { + return; + } + + if ( selection.multiple ) { + manager.attachments.reset( selection.toArray().concat( manager.difference ) ); + manager.difference = []; + } else { + manager.attachments.add( selection.toArray() ); + } + + manager.single = selection._single; + } +}; + +module.exports = selectionSync; + + +/***/ }), +/* 35 */ +/***/ (function(module, exports) { + +var l10n = wp.media.view.l10n, + getUserSetting = window.getUserSetting, + setUserSetting = window.setUserSetting, + Library; + +/** + * wp.media.controller.Library + * + * A state for choosing an attachment or group of attachments from the media library. + * + * @memberOf wp.media.controller + * + * @class + * @augments wp.media.controller.State + * @augments Backbone.Model + * @mixes media.selectionSync + * + * @param {object} [attributes] The attributes hash passed to the state. + * @param {string} [attributes.id=library] Unique identifier. + * @param {string} [attributes.title=Media library] Title for the state. Displays in the media menu and the frame's title region. + * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse. + * If one is not supplied, a collection of all attachments will be created. + * @param {wp.media.model.Selection|object} [attributes.selection] A collection to contain attachment selections within the state. + * If the 'selection' attribute is a plain JS object, + * a Selection will be created using its values as the selection instance's `props` model. + * Otherwise, it will copy the library's `props` model. + * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled. + * @param {string} [attributes.content=upload] Initial mode for the content region. + * Overridden by persistent user setting if 'contentUserSetting' is true. + * @param {string} [attributes.menu=default] Initial mode for the menu region. + * @param {string} [attributes.router=browse] Initial mode for the router region. + * @param {string} [attributes.toolbar=select] Initial mode for the toolbar region. + * @param {boolean} [attributes.searchable=true] Whether the library is searchable. + * @param {boolean|string} [attributes.filterable=false] Whether the library is filterable, and if so what filters should be shown. + * Accepts 'all', 'uploaded', or 'unattached'. + * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. + * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection. + * @param {boolean} [attributes.describe=false] Whether to offer UI to describe attachments - e.g. captioning images in a gallery. + * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user. + * @param {boolean} [attributes.syncSelection=true] Whether the Attachments selection should be persisted from the last state. + */ +Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Library.prototype */{ + defaults: { + id: 'library', + title: l10n.mediaLibraryTitle, + multiple: false, + content: 'upload', + menu: 'default', + router: 'browse', + toolbar: 'select', + searchable: true, + filterable: false, + sortable: true, + autoSelect: true, + describe: false, + contentUserSetting: true, + syncSelection: true + }, + + /** + * If a library isn't provided, query all media items. + * If a selection instance isn't provided, create one. + * + * @since 3.5.0 + */ + initialize: function() { + var selection = this.get('selection'), + props; + + if ( ! this.get('library') ) { + this.set( 'library', wp.media.query() ); + } + + if ( ! ( selection instanceof wp.media.model.Selection ) ) { + props = selection; + + if ( ! props ) { + props = this.get('library').props.toJSON(); + props = _.omit( props, 'orderby', 'query' ); + } + + this.set( 'selection', new wp.media.model.Selection( null, { + multiple: this.get('multiple'), + props: props + }) ); + } + + this.resetDisplays(); + }, + + /** + * @since 3.5.0 + */ + activate: function() { + this.syncSelection(); + + wp.Uploader.queue.on( 'add', this.uploading, this ); + + this.get('selection').on( 'add remove reset', this.refreshContent, this ); + + if ( this.get( 'router' ) && this.get('contentUserSetting') ) { + this.frame.on( 'content:activate', this.saveContentMode, this ); + this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) ); + } + }, + + /** + * @since 3.5.0 + */ + deactivate: function() { + this.recordSelection(); + + this.frame.off( 'content:activate', this.saveContentMode, this ); + + // Unbind all event handlers that use this state as the context + // from the selection. + this.get('selection').off( null, null, this ); + + wp.Uploader.queue.off( null, null, this ); + }, + + /** + * Reset the library to its initial state. + * + * @since 3.5.0 + */ + reset: function() { + this.get('selection').reset(); + this.resetDisplays(); + this.refreshContent(); + }, + + /** + * Reset the attachment display settings defaults to the site options. + * + * If site options don't define them, fall back to a persistent user setting. + * + * @since 3.5.0 + */ + resetDisplays: function() { + var defaultProps = wp.media.view.settings.defaultProps; + this._displays = []; + this._defaultDisplaySettings = { + align: getUserSetting( 'align', defaultProps.align ) || 'none', + size: getUserSetting( 'imgsize', defaultProps.size ) || 'medium', + link: getUserSetting( 'urlbutton', defaultProps.link ) || 'none' + }; + }, + + /** + * Create a model to represent display settings (alignment, etc.) for an attachment. + * + * @since 3.5.0 + * + * @param {wp.media.model.Attachment} attachment + * @returns {Backbone.Model} + */ + display: function( attachment ) { + var displays = this._displays; + + if ( ! displays[ attachment.cid ] ) { + displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) ); + } + return displays[ attachment.cid ]; + }, + + /** + * Given an attachment, create attachment display settings properties. + * + * @since 3.6.0 + * + * @param {wp.media.model.Attachment} attachment + * @returns {Object} + */ + defaultDisplaySettings: function( attachment ) { + var settings = _.clone( this._defaultDisplaySettings ); + + if ( settings.canEmbed = this.canEmbed( attachment ) ) { + settings.link = 'embed'; + } else if ( ! this.isImageAttachment( attachment ) && settings.link === 'none' ) { + settings.link = 'file'; + } + + return settings; + }, + + /** + * Whether an attachment is image. + * + * @since 4.4.1 + * + * @param {wp.media.model.Attachment} attachment + * @returns {Boolean} + */ + isImageAttachment: function( attachment ) { + // If uploading, we know the filename but not the mime type. + if ( attachment.get('uploading') ) { + return /\.(jpe?g|png|gif)$/i.test( attachment.get('filename') ); + } + + return attachment.get('type') === 'image'; + }, + + /** + * Whether an attachment can be embedded (audio or video). + * + * @since 3.6.0 + * + * @param {wp.media.model.Attachment} attachment + * @returns {Boolean} + */ + canEmbed: function( attachment ) { + // If uploading, we know the filename but not the mime type. + if ( ! attachment.get('uploading') ) { + var type = attachment.get('type'); + if ( type !== 'audio' && type !== 'video' ) { + return false; + } + } + + return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() ); + }, + + + /** + * If the state is active, no items are selected, and the current + * content mode is not an option in the state's router (provided + * the state has a router), reset the content mode to the default. + * + * @since 3.5.0 + */ + refreshContent: function() { + var selection = this.get('selection'), + frame = this.frame, + router = frame.router.get(), + mode = frame.content.mode(); + + if ( this.active && ! selection.length && router && ! router.get( mode ) ) { + this.frame.content.render( this.get('content') ); + } + }, + + /** + * Callback handler when an attachment is uploaded. + * |
