X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/5964d2279dc52bdfe105f9bfa17e04337d47a3fa..85ad385665744d9cc3bcd939906309be7268edb3:/wp-includes/js/media-views.js
diff --git a/wp-includes/js/media-views.js b/wp-includes/js/media-views.js
index 6ce8470a..3ac04c56 100644
--- a/wp-includes/js/media-views.js
+++ b/wp-includes/js/media-views.js
@@ -1,8 +1,8 @@
+/* global _wpMediaViewsL10n, confirm, getUserSetting, setUserSetting */
(function($){
var media = wp.media,
Attachment = media.model.Attachment,
Attachments = media.model.Attachments,
- Query = media.model.Query,
l10n;
// Link any localized strings.
@@ -118,11 +118,12 @@
},
trigger: function( event ) {
- var base;
+ var base, args;
+
if ( ! this._mode )
return;
- var args = _.toArray( arguments );
+ args = _.toArray( arguments );
base = this.id + ':' + event;
// Trigger `region:action:mode` event.
@@ -223,10 +224,8 @@
this.on( 'reset', this.reset, this );
this.on( 'ready', this._ready, this );
this.on( 'ready', this.ready, this );
-
- this.on( 'change:menu', this._updateMenu, this );
-
Backbone.Model.apply( this, arguments );
+ this.on( 'change:menu', this._updateMenu, this );
},
ready: function() {},
@@ -413,8 +412,6 @@
this.get('selection').on( 'add remove reset', this.refreshContent, this );
- this.on( 'insert', this._insertDisplaySettings, this );
-
if ( this.get('contentUserSetting') ) {
this.frame.on( 'content:activate', this.saveContentMode, this );
this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
@@ -440,11 +437,12 @@
},
resetDisplays: function() {
+ var defaultProps = media.view.settings.defaultProps;
this._displays = [];
this._defaultDisplaySettings = {
- align: getUserSetting( 'align', 'none' ),
- size: getUserSetting( 'imgsize', 'medium' ),
- link: getUserSetting( 'urlbutton', 'post' )
+ align: defaultProps.align || getUserSetting( 'align', 'none' ),
+ size: defaultProps.size || getUserSetting( 'imgsize', 'medium' ),
+ link: defaultProps.link || getUserSetting( 'urlbutton', 'file' )
};
},
@@ -452,25 +450,27 @@
var displays = this._displays;
if ( ! displays[ attachment.cid ] )
- displays[ attachment.cid ] = new Backbone.Model( this._defaultDisplaySettings );
+ displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );
return displays[ attachment.cid ];
},
- _insertDisplaySettings: function() {
- var selection = this.get('selection'),
- display;
-
- // If inserting one image, set those display properties as the
- // default user setting.
- if ( selection.length !== 1 )
- return;
+ defaultDisplaySettings: function( attachment ) {
+ var settings = this._defaultDisplaySettings;
+ if ( settings.canEmbed = this.canEmbed( attachment ) )
+ settings.link = 'embed';
+ return settings;
+ },
- display = this.display( selection.first() ).toJSON();
+ 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;
+ }
- setUserSetting( 'align', display.align );
- setUserSetting( 'imgsize', display.size );
- setUserSetting( 'urlbutton', display.link );
+ return _.contains( media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
},
syncSelection: function() {
@@ -496,8 +496,7 @@
recordSelection: function() {
var selection = this.get('selection'),
- manager = this.frame._selection,
- filtered;
+ manager = this.frame._selection;
if ( ! this.get('syncSelection') || ! manager || ! selection )
return;
@@ -522,7 +521,10 @@
router = frame.router.get(),
mode = frame.content.mode();
- if ( this.active && ! selection.length && ! router.get( mode ) )
+ // 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.
+ if ( this.active && ! selection.length && router && ! router.get( mode ) )
this.frame.content.render( this.get('content') );
},
@@ -533,10 +535,12 @@
if ( 'upload' === content.mode() )
this.frame.content.mode('browse');
- // If we're in a workflow that supports multiple attachments,
- // automatically select any uploading attachments.
- if ( this.get('multiple') )
- this.get('selection').add( attachment );
+ // Automatically select any uploading attachments.
+ //
+ // Selections that don't support multiple attachments automatically
+ // limit themselves to one attachment (in this case, the last
+ // attachment in the upload queue).
+ this.get('selection').add( attachment );
},
saveContentMode: function() {
@@ -670,9 +674,13 @@
// Accepts attachments that exist in the original library and
// that do not exist in gallery's library.
library.validator = function( attachment ) {
- return !! this.mirroring.getByCid( attachment.cid ) && ! edit.getByCid( attachment.cid ) && media.model.Selection.prototype.validator.apply( this, arguments );
+ return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && media.model.Selection.prototype.validator.apply( this, arguments );
};
+ // Reset the library to ensure that all attachments are re-added
+ // to the collection. Do so silently, as calling `observe` will
+ // trigger the `reset` event.
+ library.reset( library.mirroring.models, { silent: true });
library.observe( edit );
this.editLibrary = edit;
@@ -709,8 +717,8 @@
// Overload the library's comparator to push items that are not in
// the mirrored query to the front of the aggregate collection.
library.comparator = function( a, b ) {
- var aInQuery = !! this.mirroring.getByCid( a.cid ),
- bInQuery = !! this.mirroring.getByCid( b.cid );
+ var aInQuery = !! this.mirroring.get( a.cid ),
+ bInQuery = !! this.mirroring.get( b.cid );
if ( ! aInQuery && bInQuery )
return -1;
@@ -853,355 +861,29 @@
* ========================================================================
*/
- // wp.media.Views
- // -------------
- //
- // A subview manager.
-
- media.Views = function( view, views ) {
- this.view = view;
- this._views = _.isArray( views ) ? { '': views } : views || {};
- };
-
- media.Views.extend = Backbone.Model.extend;
-
- _.extend( media.Views.prototype, {
- // ### Fetch all of the subviews
- //
- // Returns an array of all subviews.
- all: function() {
- return _.flatten( this._views );
- },
-
- // ### Get a selector's subviews
- //
- // Fetches all subviews that match a given `selector`.
- //
- // If no `selector` is provided, it will grab all subviews attached
- // to the view's root.
- get: function( selector ) {
- selector = selector || '';
- return this._views[ selector ];
- },
-
- // ### Get a selector's first subview
- //
- // Fetches the first subview that matches a given `selector`.
- //
- // If no `selector` is provided, it will grab the first subview
- // attached to the view's root.
- //
- // Useful when a selector only has one subview at a time.
- first: function( selector ) {
- var views = this.get( selector );
- return views && views.length ? views[0] : null;
- },
-
- // ### Register subview(s)
- //
- // Registers any number of `views` to a `selector`.
- //
- // When no `selector` is provided, the root selector (the empty string)
- // is used. `views` accepts a `Backbone.View` instance or an array of
- // `Backbone.View` instances.
- //
- // ---
- //
- // Accepts an `options` object, which has a significant effect on the
- // resulting behavior.
- //
- // `options.silent` – *boolean, `false`*
- // > If `options.silent` is true, no DOM modifications will be made.
- //
- // `options.add` – *boolean, `false`*
- // > Use `Views.add()` as a shortcut for setting `options.add` to true.
- //
- // > By default, the provided `views` will replace
- // any existing views associated with the selector. If `options.add`
- // is true, the provided `views` will be added to the existing views.
- //
- // `options.at` – *integer, `undefined`*
- // > When adding, to insert `views` at a specific index, use
- // `options.at`. By default, `views` are added to the end of the array.
- set: function( selector, views, options ) {
- var existing, next;
-
- if ( ! _.isString( selector ) ) {
- options = views;
- views = selector;
- selector = '';
- }
-
- options = options || {};
- views = _.isArray( views ) ? views : [ views ];
- existing = this.get( selector );
- next = views;
-
- if ( existing ) {
- if ( options.add ) {
- if ( _.isUndefined( options.at ) ) {
- next = existing.concat( views );
- } else {
- next = existing;
- next.splice.apply( next, [ options.at, 0 ].concat( views ) );
- }
- } else {
- _.each( next, function( view ) {
- view.__detach = true;
- });
-
- _.each( existing, function( view ) {
- if ( view.__detach )
- view.$el.detach();
- else
- view.dispose();
- });
-
- _.each( next, function( view ) {
- delete view.__detach;
- });
- }
- }
-
- this._views[ selector ] = next;
-
- _.each( views, function( subview ) {
- var constructor = subview.Views || media.Views,
- subviews = subview.views = subview.views || new constructor( subview );
- subviews.parent = this.view;
- subviews.selector = selector;
- }, this );
-
- if ( ! options.silent )
- this._attach( selector, views, _.extend({ ready: this._isReady() }, options ) );
-
- return this;
- },
-
- // ### Add subview(s) to existing subviews
- //
- // An alias to `Views.set()`, which defaults `options.add` to true.
- //
- // Adds any number of `views` to a `selector`.
- //
- // When no `selector` is provided, the root selector (the empty string)
- // is used. `views` accepts a `Backbone.View` instance or an array of
- // `Backbone.View` instances.
- //
- // Use `Views.set()` when setting `options.add` to `false`.
- //
- // Accepts an `options` object. By default, provided `views` will be
- // inserted at the end of the array of existing views. To insert
- // `views` at a specific index, use `options.at`. If `options.silent`
- // is true, no DOM modifications will be made.
- //
- // For more information on the `options` object, see `Views.set()`.
- add: function( selector, views, options ) {
- if ( ! _.isString( selector ) ) {
- options = views;
- views = selector;
- selector = '';
- }
-
- return this.set( selector, views, _.extend({ add: true }, options ) );
- },
-
- // ### Stop tracking subviews
- //
- // Stops tracking `views` registered to a `selector`. If no `views` are
- // set, then all of the `selector`'s subviews will be unregistered and
- // disposed.
- //
- // Accepts an `options` object. If `options.silent` is set, `dispose`
- // will *not* be triggered on the unregistered views.
- unset: function( selector, views, options ) {
- var existing;
-
- if ( ! _.isString( selector ) ) {
- options = views;
- views = selector;
- selector = '';
- }
-
- views = views || [];
-
- if ( existing = this.get( selector ) ) {
- views = _.isArray( views ) ? views : [ views ];
- this._views[ selector ] = views.length ? _.difference( existing, views ) : [];
- }
-
- if ( ! options || ! options.silent )
- _.invoke( views, 'dispose' );
-
- return this;
- },
-
- // ### Detach all subviews
- //
- // Detaches all subviews from the DOM.
- //
- // Helps to preserve all subview events when re-rendering the master
- // view. Used in conjunction with `Views.render()`.
- detach: function() {
- $( _.pluck( this.all(), 'el' ) ).detach();
- return this;
- },
-
- // ### Render all subviews
- //
- // Renders all subviews. Used in conjunction with `Views.detach()`.
- render: function() {
- var options = {
- ready: this._isReady()
- };
-
- _.each( this._views, function( views, selector ) {
- this._attach( selector, views, options );
- }, this );
-
- this.rendered = true;
- return this;
- },
-
- // ### Dispose all subviews
- //
- // Triggers the `dispose()` method on all subviews. Detaches the master
- // view from its parent. Resets the internals of the views manager.
- //
- // Accepts an `options` object. If `options.silent` is set, `unset`
- // will *not* be triggered on the master view's parent.
- dispose: function( options ) {
- if ( ! options || ! options.silent ) {
- if ( this.parent && this.parent.views )
- this.parent.views.unset( this.selector, this.view, { silent: true });
- delete this.parent;
- delete this.selector;
- }
-
- _.invoke( this.all(), 'dispose' );
- this._views = [];
- return this;
- },
-
- // ### Replace a selector's subviews
- //
- // By default, sets the `$target` selector's html to the subview `els`.
- //
- // Can be overridden in subclasses.
- replace: function( $target, els ) {
- $target.html( els );
- return this;
- },
-
- // ### Insert subviews into a selector
- //
- // By default, appends the subview `els` to the end of the `$target`
- // selector. If `options.at` is set, inserts the subview `els` at the
- // provided index.
- //
- // Can be overridden in subclasses.
- insert: function( $target, els, options ) {
- var at = options && options.at,
- $children;
-
- if ( _.isNumber( at ) && ($children = $target.children()).length > at )
- $children.eq( at ).before( els );
- else
- $target.append( els );
-
- return this;
- },
-
- // ### Trigger the ready event
- //
- // **Only use this method if you know what you're doing.**
- // For performance reasons, this method does not check if the view is
- // actually attached to the DOM. It's taking your word for it.
- //
- // Fires the ready event on the current view and all attached subviews.
- ready: function() {
- this.view.trigger('ready');
-
- // Find all attached subviews, and call ready on them.
- _.chain( this.all() ).map( function( view ) {
- return view.views;
- }).flatten().where({ attached: true }).invoke('ready');
- },
-
- // #### Internal. Attaches a series of views to a selector.
- //
- // Checks to see if a matching selector exists, renders the views,
- // performs the proper DOM operation, and then checks if the view is
- // attached to the document.
- _attach: function( selector, views, options ) {
- var $selector = selector ? this.view.$( selector ) : this.view.$el,
- managers;
-
- // Check if we found a location to attach the views.
- if ( ! $selector.length )
- return this;
-
- managers = _.chain( views ).pluck('views').flatten().value();
-
- // Render the views if necessary.
- _.each( managers, function( manager ) {
- if ( manager.rendered )
- return;
-
- manager.view.render();
- manager.rendered = true;
- }, this );
-
- // Insert or replace the views.
- this[ options.add ? 'insert' : 'replace' ]( $selector, _.pluck( views, 'el' ), options );
-
- // Set attached and trigger ready if the current view is already
- // attached to the DOM.
- _.each( managers, function( manager ) {
- manager.attached = true;
-
- if ( options.ready )
- manager.ready();
- }, this );
-
- return this;
- },
-
- // #### Internal. Checks if the current view is in the DOM.
- _isReady: function() {
- var node = this.view.el;
- while ( node ) {
- if ( node === document.body )
- return true;
- node = node.parentNode;
- }
-
- return false;
- }
- });
-
// wp.media.View
// -------------
//
// The base view class.
- media.View = Backbone.View.extend({
- // The constructor for the `Views` manager.
- Views: media.Views,
-
+ //
+ // Undelegating events, removing events from the model, and
+ // removing events from the controller mirror the code for
+ // `Backbone.View.dispose` in Backbone 0.9.8 development.
+ //
+ // This behavior has since been removed, and should not be used
+ // outside of the media manager.
+ media.View = wp.Backbone.View.extend({
constructor: function( options ) {
- this.views = new this.Views( this, this.views );
- this.on( 'ready', this.ready, this );
-
if ( options && options.controller )
this.controller = options.controller;
- Backbone.View.apply( this, arguments );
+ wp.Backbone.View.apply( this, arguments );
},
dispose: function() {
// Undelegating events, removing events from the model, and
// removing events from the controller mirror the code for
- // `Backbone.View.dispose` in Backbone master.
+ // `Backbone.View.dispose` in Backbone 0.9.8 development.
this.undelegateEvents();
if ( this.model && this.model.off )
@@ -1214,41 +896,13 @@
if ( this.controller && this.controller.off )
this.controller.off( null, null, this );
- // Recursively dispose child views.
- if ( this.views )
- this.views.dispose();
-
return this;
},
remove: function() {
this.dispose();
- return Backbone.View.prototype.remove.apply( this, arguments );
- },
-
- render: function() {
- var options;
-
- if ( this.prepare )
- options = this.prepare();
-
- this.views.detach();
-
- if ( this.template ) {
- options = options || {};
- this.trigger( 'prepare', options );
- this.$el.html( this.template( options ) );
- }
-
- this.views.render();
- return this;
- },
-
- prepare: function() {
- return this.options;
- },
-
- ready: function() {}
+ return wp.Backbone.View.prototype.remove.apply( this, arguments );
+ }
});
/**
@@ -1405,7 +1059,7 @@
// Generate the tab states.
_.each( tabs, function( title, id ) {
- var frame = this.state( 'iframe:' + id ).set( _.defaults({
+ this.state( 'iframe:' + id ).set( _.defaults({
tab: id,
src: tabUrl + '&tab=' + id,
title: title,
@@ -1469,7 +1123,7 @@
// Map some of the modal's methods to the frame.
_.each(['open','close','attach','detach','escape'], function( method ) {
- media.view.MediaFrame.prototype[ method ] = function( view ) {
+ media.view.MediaFrame.prototype[ method ] = function() {
if ( this.modal )
this.modal[ method ].apply( this.modal, arguments );
return this;
@@ -1496,8 +1150,7 @@
},
createSelection: function() {
- var controller = this,
- selection = this.options.selection;
+ var selection = this.options.selection;
if ( ! (selection instanceof media.model.Selection) ) {
this.options.selection = new media.model.Selection( selection, {
@@ -1839,7 +1492,7 @@
featuredImageToolbar: function( toolbar ) {
this.createSelectToolbar( toolbar, {
text: l10n.setFeaturedImage,
- state: this.options.state || 'upload'
+ state: this.options.state
});
},
@@ -1867,9 +1520,9 @@
controller.close();
state.trigger( 'update', state.get('library') );
+ // Restore and reset the default state.
+ controller.setState( controller.options.state );
controller.reset();
- // @todo: Make the state activated dynamic (instead of hardcoded).
- controller.setState('upload');
}
}
}
@@ -2277,8 +1930,7 @@
progress: function() {
var queue = this.queue,
- $bar = this.$bar,
- memo = 0;
+ $bar = this.$bar;
if ( ! $bar || ! queue.length )
return;
@@ -2438,6 +2090,11 @@
var requires = button.options.requires,
disabled = false;
+ // Prevent insertion of attachments if any of them are still uploading
+ disabled = _.some( selection.models, function( attachment ) {
+ return attachment.get('uploading') === true;
+ });
+
if ( requires.selection && selection && ! selection.length )
disabled = true;
else if ( requires.library && library && ! library.length )
@@ -2452,9 +2109,7 @@
// ----------------------------
media.view.Toolbar.Select = media.view.Toolbar.extend({
initialize: function() {
- var options = this.options,
- controller = options.controller,
- selection = controller.state().get('selection');
+ var options = this.options;
_.bindAll( this, 'clickSelect' );
@@ -2494,11 +2149,11 @@
if ( options.event )
controller.state().trigger( options.event );
- if ( options.reset )
- controller.reset();
-
if ( options.state )
controller.setState( options.state );
+
+ if ( options.reset )
+ controller.reset();
}
});
@@ -2854,7 +2509,9 @@
initialize: function() {
var selection = this.options.selection;
- this.model.on( 'change:sizes change:uploading change:caption change:title', this.render, this );
+ this.model.on( 'change:sizes change:uploading', this.render, this );
+ this.model.on( 'change:title', this._syncTitle, this );
+ this.model.on( 'change:caption', this._syncCaption, this );
this.model.on( 'change:percent', this.progress, this );
// Update the selection.
@@ -2957,7 +2614,7 @@
selection = this.options.selection,
model = this.model,
method = options && options.method,
- single, between, models, singleIndex, modelIndex;
+ single, models, singleIndex, modelIndex;
if ( ! selection )
return;
@@ -3013,7 +2670,7 @@
selected: function() {
var selection = this.options.selection;
if ( selection )
- return !! selection.getByCid( this.model.cid );
+ return !! selection.get( this.model.cid );
},
select: function( model, collection ) {
@@ -3172,6 +2829,28 @@
}
});
+ // Ensure settings remain in sync between attachment views.
+ _.each({
+ caption: '_syncCaption',
+ title: '_syncTitle'
+ }, function( method, setting ) {
+ media.view.Attachment.prototype[ method ] = function( model, value ) {
+ var $setting = this.$('[data-setting="' + setting + '"]');
+
+ if ( ! $setting.length )
+ return this;
+
+ // If the updated value is in sync with the value in the DOM, there
+ // is no need to re-render. If we're currently editing the value,
+ // it will automatically be in sync, suppressing the re-render for
+ // the view we're editing, while updating any others.
+ if ( value === $setting.find('input, textarea, select, [value]').val() )
+ return this;
+
+ return this.render();
+ };
+ });
+
/**
* wp.media.view.Attachment.Library
*/
@@ -3216,13 +2895,13 @@
this._viewsByCid = {};
- this.collection.on( 'add', function( attachment, attachments, options ) {
+ this.collection.on( 'add', function( attachment ) {
this.views.add( this.createAttachmentView( attachment ), {
- at: options.index
+ at: this.collection.indexOf( attachment )
});
}, this );
- this.collection.on( 'remove', function( attachment, attachments, options ) {
+ this.collection.on( 'remove', function( attachment ) {
var view = this._viewsByCid[ attachment.cid ];
delete this._viewsByCid[ attachment.cid ];
@@ -3383,7 +3062,7 @@
this.scroll();
},
- scroll: function( event ) {
+ scroll: function() {
// @todo: is this still necessary?
if ( ! this.$el.is(':visible') )
return;
@@ -3453,7 +3132,7 @@
// Build `').val(value).text(filter.text)[0],
priority: filter.priority || 50
};
}, this ).sortBy('priority').pluck('el').value() );
@@ -3466,7 +3145,7 @@
this.filters = {};
},
- change: function( event ) {
+ change: function() {
var filter = this.filters[ this.el.value ];
if ( filter )
@@ -3713,8 +3392,7 @@
createSingle: function() {
var sidebar = this.sidebar,
- single = this.options.selection.single(),
- views = {};
+ single = this.options.selection.single();
sidebar.set( 'details', new media.view.Attachment.Details({
controller: this.controller,
@@ -3947,9 +3625,9 @@
setUserSetting( userSetting, value );
},
- updateChanges: function( model, options ) {
- if ( options.changes )
- _( options.changes ).chain().keys().each( this.update, this );
+ updateChanges: function( model ) {
+ if ( model.hasChanged() )
+ _( model.changed ).chain().keys().each( this.update, this );
}
});
@@ -4001,7 +3679,7 @@
$input = this.$('.link-to-custom'),
attachment = this.options.attachment;
- if ( 'none' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
+ if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
$input.hide();
return;
}
@@ -4073,7 +3751,7 @@
this.model.destroy();
},
- editAttachment: function( event ) {
+ editAttachment: function() {
this.$el.addClass('needs-refresh');
},
@@ -4220,16 +3898,10 @@
},
initialize: function() {
- this.input = this.make( 'input', {
- type: 'text',
- value: this.model.get('url') || ''
- });
-
- this.spinner = this.make( 'span', {
- 'class': 'spinner'
- });
+ this.$input = $('').attr( 'type', 'text' ).val( this.model.get('url') );
+ this.input = this.$input[0];
- this.$input = $( this.input );
+ this.spinner = $('')[0];
this.$el.append([ this.input, this.spinner ]);
this.model.on( 'change:url', this.render, this );
@@ -4286,4 +3958,4 @@
this.$('img').attr( 'src', this.model.get('url') );
}
});
-}(jQuery));
+}(jQuery));
\ No newline at end of file