media-image-widget.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* eslint consistent-this: [ "error", "control" ] */
  2. (function( component, $ ) {
  3. 'use strict';
  4. var ImageWidgetModel, ImageWidgetControl;
  5. /**
  6. * Image widget model.
  7. *
  8. * See WP_Widget_Media_Image::enqueue_admin_scripts() for amending prototype from PHP exports.
  9. *
  10. * @class ImageWidgetModel
  11. * @constructor
  12. */
  13. ImageWidgetModel = component.MediaWidgetModel.extend({});
  14. /**
  15. * Image widget control.
  16. *
  17. * See WP_Widget_Media_Image::enqueue_admin_scripts() for amending prototype from PHP exports.
  18. *
  19. * @class ImageWidgetModel
  20. * @constructor
  21. */
  22. ImageWidgetControl = component.MediaWidgetControl.extend({
  23. /**
  24. * View events.
  25. *
  26. * @type {object}
  27. */
  28. events: _.extend( {}, component.MediaWidgetControl.prototype.events, {
  29. 'click .media-widget-preview.populated': 'editMedia'
  30. } ),
  31. /**
  32. * Render preview.
  33. *
  34. * @returns {void}
  35. */
  36. renderPreview: function renderPreview() {
  37. var control = this, previewContainer, previewTemplate, fieldsContainer, fieldsTemplate, linkInput;
  38. if ( ! control.model.get( 'attachment_id' ) && ! control.model.get( 'url' ) ) {
  39. return;
  40. }
  41. previewContainer = control.$el.find( '.media-widget-preview' );
  42. previewTemplate = wp.template( 'wp-media-widget-image-preview' );
  43. previewContainer.html( previewTemplate( control.previewTemplateProps.toJSON() ) );
  44. previewContainer.addClass( 'populated' );
  45. linkInput = control.$el.find( '.link' );
  46. if ( ! linkInput.is( document.activeElement ) ) {
  47. fieldsContainer = control.$el.find( '.media-widget-fields' );
  48. fieldsTemplate = wp.template( 'wp-media-widget-image-fields' );
  49. fieldsContainer.html( fieldsTemplate( control.previewTemplateProps.toJSON() ) );
  50. }
  51. },
  52. /**
  53. * Open the media image-edit frame to modify the selected item.
  54. *
  55. * @returns {void}
  56. */
  57. editMedia: function editMedia() {
  58. var control = this, mediaFrame, updateCallback, defaultSync, metadata;
  59. metadata = control.mapModelToMediaFrameProps( control.model.toJSON() );
  60. // Needed or else none will not be selected if linkUrl is not also empty.
  61. if ( 'none' === metadata.link ) {
  62. metadata.linkUrl = '';
  63. }
  64. // Set up the media frame.
  65. mediaFrame = wp.media({
  66. frame: 'image',
  67. state: 'image-details',
  68. metadata: metadata
  69. });
  70. mediaFrame.$el.addClass( 'media-widget' );
  71. updateCallback = function() {
  72. var mediaProps, linkType;
  73. // Update cached attachment object to avoid having to re-fetch. This also triggers re-rendering of preview.
  74. mediaProps = mediaFrame.state().attributes.image.toJSON();
  75. linkType = mediaProps.link;
  76. mediaProps.link = mediaProps.linkUrl;
  77. control.selectedAttachment.set( mediaProps );
  78. control.displaySettings.set( 'link', linkType );
  79. control.model.set( _.extend(
  80. control.mapMediaToModelProps( mediaProps ),
  81. { error: false }
  82. ) );
  83. };
  84. mediaFrame.state( 'image-details' ).on( 'update', updateCallback );
  85. mediaFrame.state( 'replace-image' ).on( 'replace', updateCallback );
  86. // Disable syncing of attachment changes back to server. See <https://core.trac.wordpress.org/ticket/40403>.
  87. defaultSync = wp.media.model.Attachment.prototype.sync;
  88. wp.media.model.Attachment.prototype.sync = function rejectedSync() {
  89. return $.Deferred().rejectWith( this ).promise();
  90. };
  91. mediaFrame.on( 'close', function onClose() {
  92. mediaFrame.detach();
  93. wp.media.model.Attachment.prototype.sync = defaultSync;
  94. });
  95. mediaFrame.open();
  96. },
  97. /**
  98. * Get props which are merged on top of the model when an embed is chosen (as opposed to an attachment).
  99. *
  100. * @returns {Object} Reset/override props.
  101. */
  102. getEmbedResetProps: function getEmbedResetProps() {
  103. return _.extend(
  104. component.MediaWidgetControl.prototype.getEmbedResetProps.call( this ),
  105. {
  106. size: 'full',
  107. width: 0,
  108. height: 0
  109. }
  110. );
  111. },
  112. /**
  113. * Get the instance props from the media selection frame.
  114. *
  115. * Prevent the image_title attribute from being initially set when adding an image from the media library.
  116. *
  117. * @param {wp.media.view.MediaFrame.Select} mediaFrame - Select frame.
  118. * @returns {Object} Props.
  119. */
  120. getModelPropsFromMediaFrame: function getModelPropsFromMediaFrame( mediaFrame ) {
  121. var control = this;
  122. return _.omit(
  123. component.MediaWidgetControl.prototype.getModelPropsFromMediaFrame.call( control, mediaFrame ),
  124. 'image_title'
  125. );
  126. },
  127. /**
  128. * Map model props to preview template props.
  129. *
  130. * @returns {Object} Preview template props.
  131. */
  132. mapModelToPreviewTemplateProps: function mapModelToPreviewTemplateProps() {
  133. var control = this, previewTemplateProps, url;
  134. url = control.model.get( 'url' );
  135. previewTemplateProps = component.MediaWidgetControl.prototype.mapModelToPreviewTemplateProps.call( control );
  136. previewTemplateProps.currentFilename = url ? url.replace( /\?.*$/, '' ).replace( /^.+\//, '' ) : '';
  137. previewTemplateProps.link_url = control.model.get( 'link_url' );
  138. return previewTemplateProps;
  139. }
  140. });
  141. // Exports.
  142. component.controlConstructors.media_image = ImageWidgetControl;
  143. component.modelConstructors.media_image = ImageWidgetModel;
  144. })( wp.mediaWidgets, jQuery );