media-video-widget.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /**
  2. * @output wp-admin/js/widgets/media-video-widget.js
  3. */
  4. /* eslint consistent-this: [ "error", "control" ] */
  5. (function( component ) {
  6. 'use strict';
  7. var VideoWidgetModel, VideoWidgetControl, VideoDetailsMediaFrame;
  8. /**
  9. * Custom video details frame that removes the replace-video state.
  10. *
  11. * @class wp.mediaWidgets.controlConstructors~VideoDetailsMediaFrame
  12. * @augments wp.media.view.MediaFrame.VideoDetails
  13. *
  14. * @private
  15. */
  16. VideoDetailsMediaFrame = wp.media.view.MediaFrame.VideoDetails.extend(/** @lends wp.mediaWidgets.controlConstructors~VideoDetailsMediaFrame.prototype */{
  17. /**
  18. * Create the default states.
  19. *
  20. * @return {void}
  21. */
  22. createStates: function createStates() {
  23. this.states.add([
  24. new wp.media.controller.VideoDetails({
  25. media: this.media
  26. }),
  27. new wp.media.controller.MediaLibrary({
  28. type: 'video',
  29. id: 'add-video-source',
  30. title: wp.media.view.l10n.videoAddSourceTitle,
  31. toolbar: 'add-video-source',
  32. media: this.media,
  33. menu: false
  34. }),
  35. new wp.media.controller.MediaLibrary({
  36. type: 'text',
  37. id: 'add-track',
  38. title: wp.media.view.l10n.videoAddTrackTitle,
  39. toolbar: 'add-track',
  40. media: this.media,
  41. menu: 'video-details'
  42. })
  43. ]);
  44. }
  45. });
  46. /**
  47. * Video widget model.
  48. *
  49. * See WP_Widget_Video::enqueue_admin_scripts() for amending prototype from PHP exports.
  50. *
  51. * @class wp.mediaWidgets.modelConstructors.media_video
  52. * @augments wp.mediaWidgets.MediaWidgetModel
  53. */
  54. VideoWidgetModel = component.MediaWidgetModel.extend({});
  55. /**
  56. * Video widget control.
  57. *
  58. * See WP_Widget_Video::enqueue_admin_scripts() for amending prototype from PHP exports.
  59. *
  60. * @class wp.mediaWidgets.controlConstructors.media_video
  61. * @augments wp.mediaWidgets.MediaWidgetControl
  62. */
  63. VideoWidgetControl = component.MediaWidgetControl.extend(/** @lends wp.mediaWidgets.controlConstructors.media_video.prototype */{
  64. /**
  65. * Show display settings.
  66. *
  67. * @type {boolean}
  68. */
  69. showDisplaySettings: false,
  70. /**
  71. * Cache of oembed responses.
  72. *
  73. * @type {Object}
  74. */
  75. oembedResponses: {},
  76. /**
  77. * Map model props to media frame props.
  78. *
  79. * @param {Object} modelProps - Model props.
  80. * @return {Object} Media frame props.
  81. */
  82. mapModelToMediaFrameProps: function mapModelToMediaFrameProps( modelProps ) {
  83. var control = this, mediaFrameProps;
  84. mediaFrameProps = component.MediaWidgetControl.prototype.mapModelToMediaFrameProps.call( control, modelProps );
  85. mediaFrameProps.link = 'embed';
  86. return mediaFrameProps;
  87. },
  88. /**
  89. * Fetches embed data for external videos.
  90. *
  91. * @return {void}
  92. */
  93. fetchEmbed: function fetchEmbed() {
  94. var control = this, url;
  95. url = control.model.get( 'url' );
  96. // If we already have a local cache of the embed response, return.
  97. if ( control.oembedResponses[ url ] ) {
  98. return;
  99. }
  100. // If there is an in-flight embed request, abort it.
  101. if ( control.fetchEmbedDfd && 'pending' === control.fetchEmbedDfd.state() ) {
  102. control.fetchEmbedDfd.abort();
  103. }
  104. control.fetchEmbedDfd = wp.apiRequest({
  105. url: wp.media.view.settings.oEmbedProxyUrl,
  106. data: {
  107. url: control.model.get( 'url' ),
  108. maxwidth: control.model.get( 'width' ),
  109. maxheight: control.model.get( 'height' ),
  110. discover: false
  111. },
  112. type: 'GET',
  113. dataType: 'json',
  114. context: control
  115. });
  116. control.fetchEmbedDfd.done( function( response ) {
  117. control.oembedResponses[ url ] = response;
  118. control.renderPreview();
  119. });
  120. control.fetchEmbedDfd.fail( function() {
  121. control.oembedResponses[ url ] = null;
  122. });
  123. },
  124. /**
  125. * Whether a url is a supported external host.
  126. *
  127. * @deprecated since 4.9.
  128. *
  129. * @return {boolean} Whether url is a supported video host.
  130. */
  131. isHostedVideo: function isHostedVideo() {
  132. return true;
  133. },
  134. /**
  135. * Render preview.
  136. *
  137. * @return {void}
  138. */
  139. renderPreview: function renderPreview() {
  140. var control = this, previewContainer, previewTemplate, attachmentId, attachmentUrl, poster, html = '', isOEmbed = false, mime, error, urlParser, matches;
  141. attachmentId = control.model.get( 'attachment_id' );
  142. attachmentUrl = control.model.get( 'url' );
  143. error = control.model.get( 'error' );
  144. if ( ! attachmentId && ! attachmentUrl ) {
  145. return;
  146. }
  147. // Verify the selected attachment mime is supported.
  148. mime = control.selectedAttachment.get( 'mime' );
  149. if ( mime && attachmentId ) {
  150. if ( ! _.contains( _.values( wp.media.view.settings.embedMimes ), mime ) ) {
  151. error = 'unsupported_file_type';
  152. }
  153. } else if ( ! attachmentId ) {
  154. urlParser = document.createElement( 'a' );
  155. urlParser.href = attachmentUrl;
  156. matches = urlParser.pathname.toLowerCase().match( /\.(\w+)$/ );
  157. if ( matches ) {
  158. if ( ! _.contains( _.keys( wp.media.view.settings.embedMimes ), matches[1] ) ) {
  159. error = 'unsupported_file_type';
  160. }
  161. } else {
  162. isOEmbed = true;
  163. }
  164. }
  165. if ( isOEmbed ) {
  166. control.fetchEmbed();
  167. if ( control.oembedResponses[ attachmentUrl ] ) {
  168. poster = control.oembedResponses[ attachmentUrl ].thumbnail_url;
  169. html = control.oembedResponses[ attachmentUrl ].html.replace( /\swidth="\d+"/, ' width="100%"' ).replace( /\sheight="\d+"/, '' );
  170. }
  171. }
  172. previewContainer = control.$el.find( '.media-widget-preview' );
  173. previewTemplate = wp.template( 'wp-media-widget-video-preview' );
  174. previewContainer.html( previewTemplate({
  175. model: {
  176. attachment_id: attachmentId,
  177. html: html,
  178. src: attachmentUrl,
  179. poster: poster
  180. },
  181. is_oembed: isOEmbed,
  182. error: error
  183. }));
  184. wp.mediaelement.initialize();
  185. },
  186. /**
  187. * Open the media image-edit frame to modify the selected item.
  188. *
  189. * @return {void}
  190. */
  191. editMedia: function editMedia() {
  192. var control = this, mediaFrame, metadata, updateCallback;
  193. metadata = control.mapModelToMediaFrameProps( control.model.toJSON() );
  194. // Set up the media frame.
  195. mediaFrame = new VideoDetailsMediaFrame({
  196. frame: 'video',
  197. state: 'video-details',
  198. metadata: metadata
  199. });
  200. wp.media.frame = mediaFrame;
  201. mediaFrame.$el.addClass( 'media-widget' );
  202. updateCallback = function( mediaFrameProps ) {
  203. // Update cached attachment object to avoid having to re-fetch. This also triggers re-rendering of preview.
  204. control.selectedAttachment.set( mediaFrameProps );
  205. control.model.set( _.extend(
  206. _.omit( control.model.defaults(), 'title' ),
  207. control.mapMediaToModelProps( mediaFrameProps ),
  208. { error: false }
  209. ) );
  210. };
  211. mediaFrame.state( 'video-details' ).on( 'update', updateCallback );
  212. mediaFrame.state( 'replace-video' ).on( 'replace', updateCallback );
  213. mediaFrame.on( 'close', function() {
  214. mediaFrame.detach();
  215. });
  216. mediaFrame.open();
  217. }
  218. });
  219. // Exports.
  220. component.controlConstructors.media_video = VideoWidgetControl;
  221. component.modelConstructors.media_video = VideoWidgetModel;
  222. })( wp.mediaWidgets );