diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2020-07-27 10:05:23 +0200 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2020-07-27 10:05:23 +0200 |
| commit | 5bf66662a9bdd62c5bccab15e607cd95cfb8fcab (patch) | |
| tree | 39a1a4629749056191c05dfd899f931701b7acf3 /srcs/wordpress/wp-admin/js/widgets/media-widgets.js | |
| parent | 5afd237bbd22028b85532b8c0b3fcead49a00764 (diff) | |
| download | ft_server-master.tar.gz ft_server-master.tar.bz2 ft_server-master.zip | |
Removed wordpress and phpmyadmin, my server doesn't handle it well and it brings shame on my famillyHEADmaster
Diffstat (limited to 'srcs/wordpress/wp-admin/js/widgets/media-widgets.js')
| -rw-r--r-- | srcs/wordpress/wp-admin/js/widgets/media-widgets.js | 1330 |
1 files changed, 0 insertions, 1330 deletions
diff --git a/srcs/wordpress/wp-admin/js/widgets/media-widgets.js b/srcs/wordpress/wp-admin/js/widgets/media-widgets.js deleted file mode 100644 index 9a243a9..0000000 --- a/srcs/wordpress/wp-admin/js/widgets/media-widgets.js +++ /dev/null @@ -1,1330 +0,0 @@ -/** - * @output wp-admin/js/widgets/media-widgets.js - */ - -/* eslint consistent-this: [ "error", "control" ] */ - -/** - * @namespace wp.mediaWidgets - * @memberOf wp - */ -wp.mediaWidgets = ( function( $ ) { - 'use strict'; - - var component = {}; - - /** - * Widget control (view) constructors, mapping widget id_base to subclass of MediaWidgetControl. - * - * Media widgets register themselves by assigning subclasses of MediaWidgetControl onto this object by widget ID base. - * - * @memberOf wp.mediaWidgets - * - * @type {Object.<string, wp.mediaWidgets.MediaWidgetModel>} - */ - component.controlConstructors = {}; - - /** - * Widget model constructors, mapping widget id_base to subclass of MediaWidgetModel. - * - * Media widgets register themselves by assigning subclasses of MediaWidgetControl onto this object by widget ID base. - * - * @memberOf wp.mediaWidgets - * - * @type {Object.<string, wp.mediaWidgets.MediaWidgetModel>} - */ - component.modelConstructors = {}; - - component.PersistentDisplaySettingsLibrary = wp.media.controller.Library.extend(/** @lends wp.mediaWidgets.PersistentDisplaySettingsLibrary.prototype */{ - - /** - * Library which persists the customized display settings across selections. - * - * @constructs wp.mediaWidgets.PersistentDisplaySettingsLibrary - * @augments wp.media.controller.Library - * - * @param {Object} options - Options. - * - * @returns {void} - */ - initialize: function initialize( options ) { - _.bindAll( this, 'handleDisplaySettingChange' ); - wp.media.controller.Library.prototype.initialize.call( this, options ); - }, - - /** - * Sync changes to the current display settings back into the current customized. - * - * @param {Backbone.Model} displaySettings - Modified display settings. - * @returns {void} - */ - handleDisplaySettingChange: function handleDisplaySettingChange( displaySettings ) { - this.get( 'selectedDisplaySettings' ).set( displaySettings.attributes ); - }, - - /** - * Get the display settings model. - * - * Model returned is updated with the current customized display settings, - * and an event listener is added so that changes made to the settings - * will sync back into the model storing the session's customized display - * settings. - * - * @param {Backbone.Model} model - Display settings model. - * @returns {Backbone.Model} Display settings model. - */ - display: function getDisplaySettingsModel( model ) { - var display, selectedDisplaySettings = this.get( 'selectedDisplaySettings' ); - display = wp.media.controller.Library.prototype.display.call( this, model ); - - display.off( 'change', this.handleDisplaySettingChange ); // Prevent duplicated event handlers. - display.set( selectedDisplaySettings.attributes ); - if ( 'custom' === selectedDisplaySettings.get( 'link_type' ) ) { - display.linkUrl = selectedDisplaySettings.get( 'link_url' ); - } - display.on( 'change', this.handleDisplaySettingChange ); - return display; - } - }); - - /** - * Extended view for managing the embed UI. - * - * @class wp.mediaWidgets.MediaEmbedView - * @augments wp.media.view.Embed - */ - component.MediaEmbedView = wp.media.view.Embed.extend(/** @lends wp.mediaWidgets.MediaEmbedView.prototype */{ - - /** - * Initialize. - * - * @since 4.9.0 - * - * @param {object} options - Options. - * @returns {void} - */ - initialize: function( options ) { - var view = this, embedController; // eslint-disable-line consistent-this - wp.media.view.Embed.prototype.initialize.call( view, options ); - if ( 'image' !== view.controller.options.mimeType ) { - embedController = view.controller.states.get( 'embed' ); - embedController.off( 'scan', embedController.scanImage, embedController ); - } - }, - - /** - * Refresh embed view. - * - * Forked override of {wp.media.view.Embed#refresh()} to suppress irrelevant "link text" field. - * - * @returns {void} - */ - refresh: function refresh() { - /** - * @class wp.mediaWidgets~Constructor - */ - var Constructor; - - if ( 'image' === this.controller.options.mimeType ) { - Constructor = wp.media.view.EmbedImage; - } else { - - // This should be eliminated once #40450 lands of when this is merged into core. - Constructor = wp.media.view.EmbedLink.extend(/** @lends wp.mediaWidgets~Constructor.prototype */{ - - /** - * Set the disabled state on the Add to Widget button. - * - * @param {boolean} disabled - Disabled. - * @returns {void} - */ - setAddToWidgetButtonDisabled: function setAddToWidgetButtonDisabled( disabled ) { - this.views.parent.views.parent.views.get( '.media-frame-toolbar' )[0].$el.find( '.media-button-select' ).prop( 'disabled', disabled ); - }, - - /** - * Set or clear an error notice. - * - * @param {string} notice - Notice. - * @returns {void} - */ - setErrorNotice: function setErrorNotice( notice ) { - var embedLinkView = this, noticeContainer; // eslint-disable-line consistent-this - - noticeContainer = embedLinkView.views.parent.$el.find( '> .notice:first-child' ); - if ( ! notice ) { - if ( noticeContainer.length ) { - noticeContainer.slideUp( 'fast' ); - } - } else { - if ( ! noticeContainer.length ) { - noticeContainer = $( '<div class="media-widget-embed-notice notice notice-error notice-alt"></div>' ); - noticeContainer.hide(); - embedLinkView.views.parent.$el.prepend( noticeContainer ); - } - noticeContainer.empty(); - noticeContainer.append( $( '<p>', { - html: notice - })); - noticeContainer.slideDown( 'fast' ); - } - }, - - /** - * Update oEmbed. - * - * @since 4.9.0 - * - * @returns {void} - */ - updateoEmbed: function() { - var embedLinkView = this, url; // eslint-disable-line consistent-this - - url = embedLinkView.model.get( 'url' ); - - // Abort if the URL field was emptied out. - if ( ! url ) { - embedLinkView.setErrorNotice( '' ); - embedLinkView.setAddToWidgetButtonDisabled( true ); - return; - } - - if ( ! url.match( /^(http|https):\/\/.+\// ) ) { - embedLinkView.controller.$el.find( '#embed-url-field' ).addClass( 'invalid' ); - embedLinkView.setAddToWidgetButtonDisabled( true ); - } - - wp.media.view.EmbedLink.prototype.updateoEmbed.call( embedLinkView ); - }, - - /** - * Fetch media. - * - * @returns {void} - */ - fetch: function() { - var embedLinkView = this, fetchSuccess, matches, fileExt, urlParser, url, re, youTubeEmbedMatch; // eslint-disable-line consistent-this - url = embedLinkView.model.get( 'url' ); - - if ( embedLinkView.dfd && 'pending' === embedLinkView.dfd.state() ) { - embedLinkView.dfd.abort(); - } - - fetchSuccess = function( response ) { - embedLinkView.renderoEmbed({ - data: { - body: response - } - }); - - embedLinkView.controller.$el.find( '#embed-url-field' ).removeClass( 'invalid' ); - embedLinkView.setErrorNotice( '' ); - embedLinkView.setAddToWidgetButtonDisabled( false ); - }; - - urlParser = document.createElement( 'a' ); - urlParser.href = url; - matches = urlParser.pathname.toLowerCase().match( /\.(\w+)$/ ); - if ( matches ) { - fileExt = matches[1]; - if ( ! wp.media.view.settings.embedMimes[ fileExt ] ) { - embedLinkView.renderFail(); - } else if ( 0 !== wp.media.view.settings.embedMimes[ fileExt ].indexOf( embedLinkView.controller.options.mimeType ) ) { - embedLinkView.renderFail(); - } else { - fetchSuccess( '<!--success-->' ); - } - return; - } - - // Support YouTube embed links. - re = /https?:\/\/www\.youtube\.com\/embed\/([^/]+)/; - youTubeEmbedMatch = re.exec( url ); - if ( youTubeEmbedMatch ) { - url = 'https://www.youtube.com/watch?v=' + youTubeEmbedMatch[ 1 ]; - // silently change url to proper oembed-able version. - embedLinkView.model.attributes.url = url; - } - - embedLinkView.dfd = wp.apiRequest({ - url: wp.media.view.settings.oEmbedProxyUrl, - data: { - url: url, - maxwidth: embedLinkView.model.get( 'width' ), - maxheight: embedLinkView.model.get( 'height' ), - discover: false - }, - type: 'GET', - dataType: 'json', - context: embedLinkView - }); - - embedLinkView.dfd.done( function( response ) { - if ( embedLinkView.controller.options.mimeType !== response.type ) { - embedLinkView.renderFail(); - return; - } - fetchSuccess( response.html ); - }); - embedLinkView.dfd.fail( _.bind( embedLinkView.renderFail, embedLinkView ) ); - }, - - /** - * Handle render failure. - * - * Overrides the {EmbedLink#renderFail()} method to prevent showing the "Link Text" field. - * The element is getting display:none in the stylesheet, but the underlying method uses - * uses {jQuery.fn.show()} which adds an inline style. This avoids the need for !important. - * - * @returns {void} - */ - renderFail: function renderFail() { - var embedLinkView = this; // eslint-disable-line consistent-this - embedLinkView.controller.$el.find( '#embed-url-field' ).addClass( 'invalid' ); - embedLinkView.setErrorNotice( embedLinkView.controller.options.invalidEmbedTypeError || 'ERROR' ); - embedLinkView.setAddToWidgetButtonDisabled( true ); - } - }); - } - - this.settings( new Constructor({ - controller: this.controller, - model: this.model.props, - priority: 40 - })); - } - }); - - /** - * Custom media frame for selecting uploaded media or providing media by URL. - * - * @class wp.mediaWidgets.MediaFrameSelect - * @augments wp.media.view.MediaFrame.Post - */ - component.MediaFrameSelect = wp.media.view.MediaFrame.Post.extend(/** @lends wp.mediaWidgets.MediaFrameSelect.prototype */{ - - /** - * Create the default states. - * - * @returns {void} - */ - createStates: function createStates() { - var mime = this.options.mimeType, specificMimes = []; - _.each( wp.media.view.settings.embedMimes, function( embedMime ) { - if ( 0 === embedMime.indexOf( mime ) ) { - specificMimes.push( embedMime ); - } - }); - if ( specificMimes.length > 0 ) { - mime = specificMimes; - } - - this.states.add([ - - // Main states. - new component.PersistentDisplaySettingsLibrary({ - id: 'insert', - title: this.options.title, - selection: this.options.selection, - priority: 20, - toolbar: 'main-insert', - filterable: 'dates', - library: wp.media.query({ - type: mime - }), - multiple: false, - editable: true, - - selectedDisplaySettings: this.options.selectedDisplaySettings, - displaySettings: _.isUndefined( this.options.showDisplaySettings ) ? true : this.options.showDisplaySettings, - displayUserSettings: false // We use the display settings from the current/default widget instance props. - }), - - new wp.media.controller.EditImage({ model: this.options.editImage }), - - // Embed states. - new wp.media.controller.Embed({ - metadata: this.options.metadata, - type: 'image' === this.options.mimeType ? 'image' : 'link', - invalidEmbedTypeError: this.options.invalidEmbedTypeError - }) - ]); - }, - - /** - * Main insert toolbar. - * - * Forked override of {wp.media.view.MediaFrame.Post#mainInsertToolbar()} to override text. - * - * @param {wp.Backbone.View} view - Toolbar view. - * @this {wp.media.controller.Library} - * @returns {void} - */ - mainInsertToolbar: function mainInsertToolbar( view ) { - var controller = this; // eslint-disable-line consistent-this - view.set( 'insert', { - style: 'primary', - priority: 80, - text: controller.options.text, // The whole reason for the fork. - requires: { selection: true }, - - /** - * Handle click. - * - * @ignore - * - * @fires wp.media.controller.State#insert() - * @returns {void} - */ - click: function onClick() { - var state = controller.state(), - selection = state.get( 'selection' ); - - controller.close(); - state.trigger( 'insert', selection ).reset(); - } - }); - }, - - /** - * Main embed toolbar. - * - * Forked override of {wp.media.view.MediaFrame.Post#mainEmbedToolbar()} to override text. - * - * @param {wp.Backbone.View} toolbar - Toolbar view. - * @this {wp.media.controller.Library} - * @returns {void} - */ - mainEmbedToolbar: function mainEmbedToolbar( toolbar ) { - toolbar.view = new wp.media.view.Toolbar.Embed({ - controller: this, - text: this.options.text, - event: 'insert' - }); - }, - - /** - * Embed content. - * - * Forked override of {wp.media.view.MediaFrame.Post#embedContent()} to suppress irrelevant "link text" field. - * - * @returns {void} - */ - embedContent: function embedContent() { - var view = new component.MediaEmbedView({ - controller: this, - model: this.state() - }).render(); - - this.content.set( view ); - } - }); - - component.MediaWidgetControl = Backbone.View.extend(/** @lends wp.mediaWidgets.MediaWidgetControl.prototype */{ - - /** - * Translation strings. - * - * The mapping of translation strings is handled by media widget subclasses, - * exported from PHP to JS such as is done in WP_Widget_Media_Image::enqueue_admin_scripts(). - * - * @type {Object} - */ - l10n: { - add_to_widget: '{{add_to_widget}}', - add_media: '{{add_media}}' - }, - - /** - * Widget ID base. - * - * This may be defined by the subclass. It may be exported from PHP to JS - * such as is done in WP_Widget_Media_Image::enqueue_admin_scripts(). If not, - * it will attempt to be discovered by looking to see if this control - * instance extends each member of component.controlConstructors, and if - * it does extend one, will use the key as the id_base. - * - * @type {string} - */ - id_base: '', - - /** - * Mime type. - * - * This must be defined by the subclass. It may be exported from PHP to JS - * such as is done in WP_Widget_Media_Image::enqueue_admin_scripts(). - * - * @type {string} - */ - mime_type: '', - - /** - * View events. - * - * @type {Object} - */ - events: { - 'click .notice-missing-attachment a': 'handleMediaLibraryLinkClick', - 'click .select-media': 'selectMedia', - 'click .placeholder': 'selectMedia', - 'click .edit-media': 'editMedia' - }, - - /** - * Show display settings. - * - * @type {boolean} - */ - showDisplaySettings: true, - - /** - * Media Widget Control. - * - * @constructs wp.mediaWidgets.MediaWidgetControl - * @augments Backbone.View - * @abstract - * - * @param {Object} options - Options. - * @param {Backbone.Model} options.model - Model. - * @param {jQuery} options.el - Control field container element. - * @param {jQuery} options.syncContainer - Container element where fields are synced for the server. - * - * @returns {void} - */ - initialize: function initialize( options ) { - var control = this; - - Backbone.View.prototype.initialize.call( control, options ); - - if ( ! ( control.model instanceof component.MediaWidgetModel ) ) { - throw new Error( 'Missing options.model' ); - } - if ( ! options.el ) { - throw new Error( 'Missing options.el' ); - } - if ( ! options.syncContainer ) { - throw new Error( 'Missing options.syncContainer' ); - } - - control.syncContainer = options.syncContainer; - - control.$el.addClass( 'media-widget-control' ); - - // Allow methods to be passed in with control context preserved. - _.bindAll( control, 'syncModelToInputs', 'render', 'updateSelectedAttachment', 'renderPreview' ); - - if ( ! control.id_base ) { - _.find( component.controlConstructors, function( Constructor, idBase ) { - if ( control instanceof Constructor ) { - control.id_base = idBase; - return true; - } - return false; - }); - if ( ! control.id_base ) { - throw new Error( 'Missing id_base.' ); - } - } - - // Track attributes needed to renderPreview in it's own model. - control.previewTemplateProps = new Backbone.Model( control.mapModelToPreviewTemplateProps() ); - - // Re-render the preview when the attachment changes. - control.selectedAttachment = new wp.media.model.Attachment(); - control.renderPreview = _.debounce( control.renderPreview ); - control.listenTo( control.previewTemplateProps, 'change', control.renderPreview ); - - // Make sure a copy of the selected attachment is always fetched. - control.model.on( 'change:attachment_id', control.updateSelectedAttachment ); - control.model.on( 'change:url', control.updateSelectedAttachment ); - control.updateSelectedAttachment(); - - /* - * Sync the widget instance model attributes onto the hidden inputs that widgets currently use to store the state. - * In the future, when widgets are JS-driven, the underlying widget instance data should be exposed as a model - * from the start, without having to sync with hidden fields. See <https://core.trac.wordpress.org/ticket/33507>. - */ - control.listenTo( control.model, 'change', control.syncModelToInputs ); - control.listenTo( control.model, 'change', control.syncModelToPreviewProps ); - control.listenTo( control.model, 'change', control.render ); - - // Update the title. - control.$el.on( 'input change', '.title', function updateTitle() { - control.model.set({ - title: $.trim( $( this ).val() ) - }); - }); - - // Update link_url attribute. - control.$el.on( 'input change', '.link', function updateLinkUrl() { - var linkUrl = $.trim( $( this ).val() ), linkType = 'custom'; - if ( control.selectedAttachment.get( 'linkUrl' ) === linkUrl || control.selectedAttachment.get( 'link' ) === linkUrl ) { - linkType = 'post'; - } else if ( control.selectedAttachment.get( 'url' ) === linkUrl ) { - linkType = 'file'; - } - control.model.set( { - link_url: linkUrl, - link_type: linkType - }); - - // Update display settings for the next time the user opens to select from the media library. - control.displaySettings.set( { - link: linkType, - linkUrl: linkUrl - }); - }); - - /* - * Copy current display settings from the widget model to serve as basis - * of customized display settings for the current media frame session. - * Changes to display settings will be synced into this model, and - * when a new selection is made, the settings from this will be synced - * into that AttachmentDisplay's model to persist the setting changes. - */ - control.displaySettings = new Backbone.Model( _.pick( - control.mapModelToMediaFrameProps( - _.extend( control.model.defaults(), control.model.toJSON() ) - ), - _.keys( wp.media.view.settings.defaultProps ) - ) ); - }, - - /** - * Update the selected attachment if necessary. - * - * @returns {void} - */ - updateSelectedAttachment: function updateSelectedAttachment() { - var control = this, attachment; - - if ( 0 === control.model.get( 'attachment_id' ) ) { - control.selectedAttachment.clear(); - control.model.set( 'error', false ); - } else if ( control.model.get( 'attachment_id' ) !== control.selectedAttachment.get( 'id' ) ) { - attachment = new wp.media.model.Attachment({ - id: control.model.get( 'attachment_id' ) - }); - attachment.fetch() - .done( function done() { - control.model.set( 'error', false ); - control.selectedAttachment.set( attachment.toJSON() ); - }) - .fail( function fail() { - control.model.set( 'error', 'missing_attachment' ); - }); - } - }, - - /** - * Sync the model attributes to the hidden inputs, and update previewTemplateProps. - * - * @returns {void} - */ - syncModelToPreviewProps: function syncModelToPreviewProps() { - var control = this; - control.previewTemplateProps.set( control.mapModelToPreviewTemplateProps() ); - }, - - /** - * Sync the model attributes to the hidden inputs, and update previewTemplateProps. - * - * @returns {void} - */ - syncModelToInputs: function syncModelToInputs() { - var control = this; - control.syncContainer.find( '.media-widget-instance-property' ).each( function() { - var input = $( this ), value, propertyName; - propertyName = input.data( 'property' ); - value = control.model.get( propertyName ); - if ( _.isUndefined( value ) ) { - return; - } - - if ( 'array' === control.model.schema[ propertyName ].type && _.isArray( value ) ) { - value = value.join( ',' ); - } else if ( 'boolean' === control.model.schema[ propertyName ].type ) { - value = value ? '1' : ''; // Because in PHP, strval( true ) === '1' && strval( false ) === ''. - } else { - value = String( value ); - } - - if ( input.val() !== value ) { - input.val( value ); - input.trigger( 'change' ); - } - }); - }, - - /** - * Get template. - * - * @returns {Function} Template. - */ - template: function template() { - var control = this; - if ( ! $( '#tmpl-widget-media-' + control.id_base + '-control' ).length ) { - throw new Error( 'Missing widget control template for ' + control.id_base ); - } - return wp.template( 'widget-media-' + control.id_base + '-control' ); - }, - - /** - * Render template. - * - * @returns {void} - */ - render: function render() { - var control = this, titleInput; - - if ( ! control.templateRendered ) { - control.$el.html( control.template()( control.model.toJSON() ) ); - control.renderPreview(); // Hereafter it will re-render when control.selectedAttachment changes. - control.templateRendered = true; - } - - titleInput = control.$el.find( '.title' ); - if ( ! titleInput.is( document.activeElement ) ) { - titleInput.val( control.model.get( 'title' ) ); - } - - control.$el.toggleClass( 'selected', control.isSelected() ); - }, - - /** - * Render media preview. - * - * @abstract - * @returns {void} - */ - renderPreview: function renderPreview() { - throw new Error( 'renderPreview must be implemented' ); - }, - - /** - * Whether a media item is selected. - * - * @returns {boolean} Whether selected and no error. - */ - isSelected: function isSelected() { - var control = this; - - if ( control.model.get( 'error' ) ) { - return false; - } - - return Boolean( control.model.get( 'attachment_id' ) || control.model.get( 'url' ) ); - }, - - /** - * Handle click on link to Media Library to open modal, such as the link that appears when in the missing attachment error notice. - * - * @param {jQuery.Event} event - Event. - * @returns {void} - */ - handleMediaLibraryLinkClick: function handleMediaLibraryLinkClick( event ) { - var control = this; - event.preventDefault(); - control.selectMedia(); - }, - - /** - * Open the media select frame to chose an item. - * - * @returns {void} - */ - selectMedia: function selectMedia() { - var control = this, selection, mediaFrame, defaultSync, mediaFrameProps, selectionModels = []; - - if ( control.isSelected() && 0 !== control.model.get( 'attachment_id' ) ) { - selectionModels.push( control.selectedAttachment ); - } - - selection = new wp.media.model.Selection( selectionModels, { multiple: false } ); - - mediaFrameProps = control.mapModelToMediaFrameProps( control.model.toJSON() ); - if ( mediaFrameProps.size ) { - control.displaySettings.set( 'size', mediaFrameProps.size ); - } - - mediaFrame = new component.MediaFrameSelect({ - title: control.l10n.add_media, - frame: 'post', - text: control.l10n.add_to_widget, - selection: selection, - mimeType: control.mime_type, - selectedDisplaySettings: control.displaySettings, - showDisplaySettings: control.showDisplaySettings, - metadata: mediaFrameProps, - state: control.isSelected() && 0 === control.model.get( 'attachment_id' ) ? 'embed' : 'insert', - invalidEmbedTypeError: control.l10n.unsupported_file_type - }); - wp.media.frame = mediaFrame; // See wp.media(). - - // Handle selection of a media item. - mediaFrame.on( 'insert', function onInsert() { - var attachment = {}, state = mediaFrame.state(); - - // Update cached attachment object to avoid having to re-fetch. This also triggers re-rendering of preview. - if ( 'embed' === state.get( 'id' ) ) { - _.extend( attachment, { id: 0 }, state.props.toJSON() ); - } else { - _.extend( attachment, state.get( 'selection' ).first().toJSON() ); - } - - control.selectedAttachment.set( attachment ); - control.model.set( 'error', false ); - - // Update widget instance. - control.model.set( control.getModelPropsFromMediaFrame( mediaFrame ) ); - }); - - // Disable syncing of attachment changes back to server (except for deletions). See <https://core.trac.wordpress.org/ticket/40403>. - defaultSync = wp.media.model.Attachment.prototype.sync; - wp.media.model.Attachment.prototype.sync = function( method ) { - if ( 'delete' === method ) { - return defaultSync.apply( this, arguments ); - } else { - return $.Deferred().rejectWith( this ).promise(); - } - }; - mediaFrame.on( 'close', function onClose() { - wp.media.model.Attachment.prototype.sync = defaultSync; - }); - - mediaFrame.$el.addClass( 'media-widget' ); - mediaFrame.open(); - - // Clear the selected attachment when it is deleted in the media select frame. - if ( selection ) { - selection.on( 'destroy', function onDestroy( attachment ) { - if ( control.model.get( 'attachment_id' ) === attachment.get( 'id' ) ) { - control.model.set({ - attachment_id: 0, - url: '' - }); - } - }); - } - - /* - * Make sure focus is set inside of modal so that hitting Esc will close - * the modal and not inadvertently cause the widget to collapse in the customizer. - */ - mediaFrame.$el.find( '.media-frame-menu .media-menu-item.active' ).focus(); - }, - - /** - * Get the instance props from the media selection frame. - * - * @param {wp.media.view.MediaFrame.Select} mediaFrame - Select frame. - * @returns {Object} Props. - */ - getModelPropsFromMediaFrame: function getModelPropsFromMediaFrame( mediaFrame ) { - var control = this, state, mediaFrameProps, modelProps; - - state = mediaFrame.state(); - if ( 'insert' === state.get( 'id' ) ) { - mediaFrameProps = state.get( 'selection' ).first().toJSON(); - mediaFrameProps.postUrl = mediaFrameProps.link; - - if ( control.showDisplaySettings ) { - _.extend( - mediaFrameProps, - mediaFrame.content.get( '.attachments-browser' ).sidebar.get( 'display' ).model.toJSON() - ); - } - if ( mediaFrameProps.sizes && mediaFrameProps.size && mediaFrameProps.sizes[ mediaFrameProps.size ] ) { - mediaFrameProps.url = mediaFrameProps.sizes[ mediaFrameProps.size ].url; - } - } else if ( 'embed' === state.get( 'id' ) ) { - mediaFrameProps = _.extend( - state.props.toJSON(), - { attachment_id: 0 }, // Because some media frames use `attachment_id` not `id`. - control.model.getEmbedResetProps() - ); - } else { - throw new Error( 'Unexpected state: ' + state.get( 'id' ) ); - } - - if ( mediaFrameProps.id ) { - mediaFrameProps.attachment_id = mediaFrameProps.id; - } - - modelProps = control.mapMediaToModelProps( mediaFrameProps ); - - // Clear the extension prop so sources will be reset for video and audio media. - _.each( wp.media.view.settings.embedExts, function( ext ) { - if ( ext in control.model.schema && modelProps.url !== modelProps[ ext ] ) { - modelProps[ ext ] = ''; - } - }); - - return modelProps; - }, - - /** - * Map media frame props to model props. - * - * @param {Object} mediaFrameProps - Media frame props. - * @returns {Object} Model props. - */ - mapMediaToModelProps: function mapMediaToModelProps( mediaFrameProps ) { - var control = this, mediaFramePropToModelPropMap = {}, modelProps = {}, extension; - _.each( control.model.schema, function( fieldSchema, modelProp ) { - - // Ignore widget title attribute. - if ( 'title' === modelProp ) { - return; - } - mediaFramePropToModelPropMap[ fieldSchema.media_prop || modelProp ] = modelProp; - }); - - _.each( mediaFrameProps, function( value, mediaProp ) { - var propName = mediaFramePropToModelPropMap[ mediaProp ] || mediaProp; - if ( control.model.schema[ propName ] ) { - modelProps[ propName ] = value; - } - }); - - if ( 'custom' === mediaFrameProps.size ) { - modelProps.width = mediaFrameProps.customWidth; - modelProps.height = mediaFrameProps.customHeight; - } - - if ( 'post' === mediaFrameProps.link ) { - modelProps.link_url = mediaFrameProps.postUrl || mediaFrameProps.linkUrl; - } else if ( 'file' === mediaFrameProps.link ) { - modelProps.link_url = mediaFrameProps.url; - } - - // Because some media frames use `id` instead of `attachment_id`. - if ( ! mediaFrameProps.attachment_id && mediaFrameProps.id ) { - modelProps.attachment_id = mediaFrameProps.id; - } - - if ( mediaFrameProps.url ) { - extension = mediaFrameProps.url.replace( /#.*$/, '' ).replace( /\?.*$/, '' ).split( '.' ).pop().toLowerCase(); - if ( extension in control.model.schema ) { - modelProps[ extension ] = mediaFrameProps.url; - } - } - - // Always omit the titles derived from mediaFrameProps. - return _.omit( modelProps, 'title' ); - }, - - /** - * Map model props to media frame props. - * - * @param {Object} modelProps - Model props. - * @returns {Object} Media frame props. - */ - mapModelToMediaFrameProps: function mapModelToMediaFrameProps( modelProps ) { - var control = this, mediaFrameProps = {}; - - _.each( modelProps, function( value, modelProp ) { - var fieldSchema = control.model.schema[ modelProp ] || {}; - mediaFrameProps[ fieldSchema.media_prop || modelProp ] = value; - }); - - // Some media frames use attachment_id. - mediaFrameProps.attachment_id = mediaFrameProps.id; - - if ( 'custom' === mediaFrameProps.size ) { - mediaFrameProps.customWidth = control.model.get( 'width' ); - mediaFrameProps.customHeight = control.model.get( 'height' ); - } - - return mediaFrameProps; - }, - - /** - * Map model props to previewTemplateProps. - * - * @returns {Object} Preview Template Props. - */ - mapModelToPreviewTemplateProps: function mapModelToPreviewTemplateProps() { - var control = this, previewTemplateProps = {}; - _.each( control.model.schema, function( value, prop ) { - if ( ! value.hasOwnProperty( 'should_preview_update' ) || value.should_preview_update ) { - previewTemplateProps[ prop ] = control.model.get( prop ); - } - }); - - // Templates need to be aware of the error. - previewTemplateProps.error = control.model.get( 'error' ); - return previewTemplateProps; - }, - - /** - * Open the media frame to modify the selected item. - * - * @abstract - * @returns {void} - */ - editMedia: function editMedia() { - throw new Error( 'editMedia not implemented' ); - } - }); - - /** - * Media widget model. - * - * @class wp.mediaWidgets.MediaWidgetModel - * @augments Backbone.Model - */ - component.MediaWidgetModel = Backbone.Model.extend(/** @lends wp.mediaWidgets.MediaWidgetModel.prototype */{ - - /** - * Id attribute. - * - * @type {string} - */ - idAttribute: 'widget_id', - - /** - * Instance schema. - * - * This adheres to JSON Schema and subclasses should have their schema - * exported from PHP to JS such as is done in WP_Widget_Media_Image::enqueue_admin_scripts(). - * - * @type {Object.<string, Object>} - */ - schema: { - title: { - type: 'string', - 'default': '' - }, - attachment_id: { - type: 'integer', - 'default': 0 - }, - url: { - type: 'string', - 'default': '' - } - }, - - /** - * Get default attribute values. - * - * @returns {Object} Mapping of property names to their default values. - */ - defaults: function() { - var defaults = {}; - _.each( this.schema, function( fieldSchema, field ) { - defaults[ field ] = fieldSchema['default']; - }); - return defaults; - }, - - /** - * Set attribute value(s). - * - * This is a wrapped version of Backbone.Model#set() which allows us to - * cast the attribute values from the hidden inputs' string values into - * the appropriate data types (integers or booleans). - * - * @param {string|Object} key - Attribute name or attribute pairs. - * @param {mixed|Object} [val] - Attribute value or options object. - * @param {Object} [options] - Options when attribute name and value are passed separately. - * @returns {wp.mediaWidgets.MediaWidgetModel} This model. - */ - set: function set( key, val, options ) { - var model = this, attrs, opts, castedAttrs; // eslint-disable-line consistent-this - if ( null === key ) { - return model; - } - if ( 'object' === typeof key ) { - attrs = key; - opts = val; - } else { - attrs = {}; - attrs[ key ] = val; - opts = options; - } - - castedAttrs = {}; - _.each( attrs, function( value, name ) { - var type; - if ( ! model.schema[ name ] ) { - castedAttrs[ name ] = value; - return; - } - type = model.schema[ name ].type; - if ( 'array' === type ) { - castedAttrs[ name ] = value; - if ( ! _.isArray( castedAttrs[ name ] ) ) { - castedAttrs[ name ] = castedAttrs[ name ].split( /,/ ); // Good enough for parsing an ID list. - } - if ( model.schema[ name ].items && 'integer' === model.schema[ name ].items.type ) { - castedAttrs[ name ] = _.filter( - _.map( castedAttrs[ name ], function( id ) { - return parseInt( id, 10 ); - }, - function( id ) { - return 'number' === typeof id; - } - ) ); - } - } else if ( 'integer' === type ) { - castedAttrs[ name ] = parseInt( value, 10 ); - } else if ( 'boolean' === type ) { - castedAttrs[ name ] = ! ( ! value || '0' === value || 'false' === value ); - } else { - castedAttrs[ name ] = value; - } - }); - - return Backbone.Model.prototype.set.call( this, castedAttrs, opts ); - }, - - /** - * Get props which are merged on top of the model when an embed is chosen (as opposed to an attachment). - * - * @returns {Object} Reset/override props. - */ - getEmbedResetProps: function getEmbedResetProps() { - return { - id: 0 - }; - } - }); - - /** - * Collection of all widget model instances. - * - * @memberOf wp.mediaWidgets - * - * @type {Backbone.Collection} - */ - component.modelCollection = new ( Backbone.Collection.extend( { - model: component.MediaWidgetModel - }) )(); - - /** - * Mapping of widget ID to instances of MediaWidgetControl subclasses. - * - * @memberOf wp.mediaWidgets - * - * @type {Object.<string, wp.mediaWidgets.MediaWidgetControl>} - */ - component.widgetControls = {}; - - /** - * Handle widget being added or initialized for the first time at the widget-added event. - * - * @memberOf wp.mediaWidgets - * - * @param {jQuery.Event} event - Event. - * @param {jQuery} widgetContainer - Widget container element. - * - * @returns {void} - */ - component.handleWidgetAdded = function handleWidgetAdded( event, widgetContainer ) { - var fieldContainer, syncContainer, widgetForm, idBase, ControlConstructor, ModelConstructor, modelAttributes, widgetControl, widgetModel, widgetId, animatedCheckDelay = 50, renderWhenAnimationDone; - widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); // Note: '.form' appears in the customizer, whereas 'form' on the widgets admin screen. - idBase = widgetForm.find( '> .id_base' ).val(); - widgetId = widgetForm.find( '> .widget-id' ).val(); - - // Prevent initializing already-added widgets. - if ( component.widgetControls[ widgetId ] ) { - return; - } - - ControlConstructor = component.controlConstructors[ idBase ]; - if ( ! ControlConstructor ) { - return; - } - - ModelConstructor = component.modelConstructors[ idBase ] || component.MediaWidgetModel; - - /* - * Create a container element for the widget control (Backbone.View). - * This is inserted into the DOM immediately before the .widget-content - * element because the contents of this element are essentially "managed" - * by PHP, where each widget update cause the entire element to be emptied - * and replaced with the rendered output of WP_Widget::form() which is - * sent back in Ajax request made to save/update the widget instance. - * To prevent a "flash of replaced DOM elements and re-initialized JS - * components", the JS template is rendered outside of the normal form - * container. - */ - fieldContainer = $( '<div></div>' ); - syncContainer = widgetContainer.find( '.widget-content:first' ); - syncContainer.before( fieldContainer ); - - /* - * Sync the widget instance model attributes onto the hidden inputs that widgets currently use to store the state. - * In the future, when widgets are JS-driven, the underlying widget instance data should be exposed as a model - * from the start, without having to sync with hidden fields. See <https://core.trac.wordpress.org/ticket/33507>. - */ - modelAttributes = {}; - syncContainer.find( '.media-widget-instance-property' ).each( function() { - var input = $( this ); - modelAttributes[ input.data( 'property' ) ] = input.val(); - }); - modelAttributes.widget_id = widgetId; - - widgetModel = new ModelConstructor( modelAttributes ); - - widgetControl = new ControlConstructor({ - el: fieldContainer, - syncContainer: syncContainer, - model: widgetModel - }); - - /* - * Render the widget once the widget parent's container finishes animating, - * as the widget-added event fires with a slideDown of the container. - * This ensures that the container's dimensions are fixed so that ME.js - * can initialize with the proper dimensions. - */ - renderWhenAnimationDone = function() { - if ( ! widgetContainer.hasClass( 'open' ) ) { - setTimeout( renderWhenAnimationDone, animatedCheckDelay ); - } else { - widgetControl.render(); - } - }; - renderWhenAnimationDone(); - - /* - * Note that the model and control currently won't ever get garbage-collected - * when a widget gets removed/deleted because there is no widget-removed event. - */ - component.modelCollection.add( [ widgetModel ] ); - component.widgetControls[ widgetModel.get( 'widget_id' ) ] = widgetControl; - }; - - /** - * Setup widget in accessibility mode. - * - * @memberOf wp.mediaWidgets - * - * @returns {void} - */ - component.setupAccessibleMode = function setupAccessibleMode() { - var widgetForm, widgetId, idBase, widgetControl, ControlConstructor, ModelConstructor, modelAttributes, fieldContainer, syncContainer; - widgetForm = $( '.editwidget > form' ); - if ( 0 === widgetForm.length ) { - return; - } - - idBase = widgetForm.find( '> .widget-control-actions > .id_base' ).val(); - - ControlConstructor = component.controlConstructors[ idBase ]; - if ( ! ControlConstructor ) { - return; - } - - widgetId = widgetForm.find( '> .widget-control-actions > .widget-id' ).val(); - - ModelConstructor = component.modelConstructors[ idBase ] || component.MediaWidgetModel; - fieldContainer = $( '<div></div>' ); - syncContainer = widgetForm.find( '> .widget-inside' ); - syncContainer.before( fieldContainer ); - - modelAttributes = {}; - syncContainer.find( '.media-widget-instance-property' ).each( function() { - var input = $( this ); - modelAttributes[ input.data( 'property' ) ] = input.val(); - }); - modelAttributes.widget_id = widgetId; - - widgetControl = new ControlConstructor({ - el: fieldContainer, - syncContainer: syncContainer, - model: new ModelConstructor( modelAttributes ) - }); - - component.modelCollection.add( [ widgetControl.model ] ); - component.widgetControls[ widgetControl.model.get( 'widget_id' ) ] = widgetControl; - - widgetControl.render(); - }; - - /** - * Sync widget instance data sanitized from server back onto widget model. - * - * This gets called via the 'widget-updated' event when saving a widget from - * the widgets admin screen and also via the 'widget-synced' event when making - * a change to a widget in the customizer. - * - * @memberOf wp.mediaWidgets - * - * @param {jQuery.Event} event - Event. - * @param {jQuery} widgetContainer - Widget container element. - * - * @returns {void} - */ - component.handleWidgetUpdated = function handleWidgetUpdated( event, widgetContainer ) { - var widgetForm, widgetContent, widgetId, widgetControl, attributes = {}; - widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); - widgetId = widgetForm.find( '> .widget-id' ).val(); - - widgetControl = component.widgetControls[ widgetId ]; - if ( ! widgetControl ) { - return; - } - - // Make sure the server-sanitized values get synced back into the model. - widgetContent = widgetForm.find( '> .widget-content' ); - widgetContent.find( '.media-widget-instance-property' ).each( function() { - var property = $( this ).data( 'property' ); - attributes[ property ] = $( this ).val(); - }); - - // Suspend syncing model back to inputs when syncing from inputs to model, preventing infinite loop. - widgetControl.stopListening( widgetControl.model, 'change', widgetControl.syncModelToInputs ); - widgetControl.model.set( attributes ); - widgetControl.listenTo( widgetControl.model, 'change', widgetControl.syncModelToInputs ); - }; - - /** - * Initialize functionality. - * - * This function exists to prevent the JS file from having to boot itself. - * When WordPress enqueues this script, it should have an inline script - * attached which calls wp.mediaWidgets.init(). - * - * @memberOf wp.mediaWidgets - * - * @returns {void} - */ - component.init = function init() { - var $document = $( document ); - $document.on( 'widget-added', component.handleWidgetAdded ); - $document.on( 'widget-synced widget-updated', component.handleWidgetUpdated ); - - /* - * Manually trigger widget-added events for media widgets on the admin - * screen once they are expanded. The widget-added event is not triggered - * for each pre-existing widget on the widgets admin screen like it is - * on the customizer. Likewise, the customizer only triggers widget-added - * when the widget is expanded to just-in-time construct the widget form - * when it is actually going to be displayed. So the following implements - * the same for the widgets admin screen, to invoke the widget-added - * handler when a pre-existing media widget is expanded. - */ - $( function initializeExistingWidgetContainers() { - var widgetContainers; - if ( 'widgets' !== window.pagenow ) { - return; - } - widgetContainers = $( '.widgets-holder-wrap:not(#available-widgets)' ).find( 'div.widget' ); - widgetContainers.one( 'click.toggle-widget-expanded', function toggleWidgetExpanded() { - var widgetContainer = $( this ); - component.handleWidgetAdded( new jQuery.Event( 'widget-added' ), widgetContainer ); - }); - - // Accessibility mode. - $( window ).on( 'load', function() { - component.setupAccessibleMode(); - }); - }); - }; - - return component; -})( jQuery ); |
