PageRenderTime 93ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/js/plupload/wp-plupload.js

https://gitlab.com/Blueprint-Marketing/WordPress-1
JavaScript | 345 lines | 217 code | 69 blank | 59 comment | 43 complexity | 9f525a1f1daa87dfbc70e3799598177b MD5 | raw file
  1. /* global pluploadL10n, plupload, _wpPluploadSettings */
  2. window.wp = window.wp || {};
  3. (function( exports, $ ) {
  4. var Uploader;
  5. if ( typeof _wpPluploadSettings === 'undefined' )
  6. return;
  7. /**
  8. * An object that helps create a WordPress uploader using plupload.
  9. *
  10. * @param options - object - The options passed to the new plupload instance.
  11. * Accepts the following parameters:
  12. * - container - The id of uploader container.
  13. * - browser - The id of button to trigger the file select.
  14. * - dropzone - The id of file drop target.
  15. * - plupload - An object of parameters to pass to the plupload instance.
  16. * - params - An object of parameters to pass to $_POST when uploading the file.
  17. * Extends this.plupload.multipart_params under the hood.
  18. *
  19. * @param attributes - object - Attributes and methods for this specific instance.
  20. */
  21. Uploader = function( options ) {
  22. var self = this,
  23. elements = {
  24. container: 'container',
  25. browser: 'browse_button',
  26. dropzone: 'drop_element'
  27. },
  28. key, error;
  29. this.supports = {
  30. upload: Uploader.browser.supported
  31. };
  32. this.supported = this.supports.upload;
  33. if ( ! this.supported )
  34. return;
  35. // Use deep extend to ensure that multipart_params and other objects are cloned.
  36. this.plupload = $.extend( true, { multipart_params: {} }, Uploader.defaults );
  37. this.container = document.body; // Set default container.
  38. // Extend the instance with options
  39. //
  40. // Use deep extend to allow options.plupload to override individual
  41. // default plupload keys.
  42. $.extend( true, this, options );
  43. // Proxy all methods so this always refers to the current instance.
  44. for ( key in this ) {
  45. if ( $.isFunction( this[ key ] ) )
  46. this[ key ] = $.proxy( this[ key ], this );
  47. }
  48. // Ensure all elements are jQuery elements and have id attributes
  49. // Then set the proper plupload arguments to the ids.
  50. for ( key in elements ) {
  51. if ( ! this[ key ] )
  52. continue;
  53. this[ key ] = $( this[ key ] ).first();
  54. if ( ! this[ key ].length ) {
  55. delete this[ key ];
  56. continue;
  57. }
  58. if ( ! this[ key ].prop('id') )
  59. this[ key ].prop( 'id', '__wp-uploader-id-' + Uploader.uuid++ );
  60. this.plupload[ elements[ key ] ] = this[ key ].prop('id');
  61. }
  62. // If the uploader has neither a browse button nor a dropzone, bail.
  63. if ( ! ( this.browser && this.browser.length ) && ! ( this.dropzone && this.dropzone.length ) )
  64. return;
  65. this.uploader = new plupload.Uploader( this.plupload );
  66. delete this.plupload;
  67. // Set default params and remove this.params alias.
  68. this.param( this.params || {} );
  69. delete this.params;
  70. error = function( message, data, file ) {
  71. if ( file.attachment )
  72. file.attachment.destroy();
  73. Uploader.errors.unshift({
  74. message: message || pluploadL10n.default_error,
  75. data: data,
  76. file: file
  77. });
  78. self.error( message, data, file );
  79. };
  80. this.uploader.init();
  81. this.supports.dragdrop = this.uploader.features.dragdrop && ! Uploader.browser.mobile;
  82. // Generate drag/drop helper classes.
  83. (function( dropzone, supported ) {
  84. var timer, active;
  85. if ( ! dropzone )
  86. return;
  87. dropzone.toggleClass( 'supports-drag-drop', !! supported );
  88. if ( ! supported )
  89. return dropzone.unbind('.wp-uploader');
  90. // 'dragenter' doesn't fire correctly,
  91. // simulate it with a limited 'dragover'
  92. dropzone.bind( 'dragover.wp-uploader', function(){
  93. if ( timer )
  94. clearTimeout( timer );
  95. if ( active )
  96. return;
  97. dropzone.trigger('dropzone:enter').addClass('drag-over');
  98. active = true;
  99. });
  100. dropzone.bind('dragleave.wp-uploader, drop.wp-uploader', function(){
  101. // Using an instant timer prevents the drag-over class from
  102. // being quickly removed and re-added when elements inside the
  103. // dropzone are repositioned.
  104. //
  105. // See http://core.trac.wordpress.org/ticket/21705
  106. timer = setTimeout( function() {
  107. active = false;
  108. dropzone.trigger('dropzone:leave').removeClass('drag-over');
  109. }, 0 );
  110. });
  111. }( this.dropzone, this.supports.dragdrop ));
  112. if ( this.browser ) {
  113. this.browser.on( 'mouseenter', this.refresh );
  114. } else {
  115. this.uploader.disableBrowse( true );
  116. // If HTML5 mode, hide the auto-created file container.
  117. $('#' + this.uploader.id + '_html5_container').hide();
  118. }
  119. this.uploader.bind( 'FilesAdded', function( up, files ) {
  120. _.each( files, function( file ) {
  121. var attributes, image;
  122. // Ignore failed uploads.
  123. if ( plupload.FAILED === file.status )
  124. return;
  125. // Generate attributes for a new `Attachment` model.
  126. attributes = _.extend({
  127. file: file,
  128. uploading: true,
  129. date: new Date(),
  130. filename: file.name,
  131. menuOrder: 0,
  132. uploadedTo: wp.media.model.settings.post.id
  133. }, _.pick( file, 'loaded', 'size', 'percent' ) );
  134. // Handle early mime type scanning for images.
  135. image = /(?:jpe?g|png|gif)$/i.exec( file.name );
  136. // Did we find an image?
  137. if ( image ) {
  138. attributes.type = 'image';
  139. // `jpeg`, `png` and `gif` are valid subtypes.
  140. // `jpg` is not, so map it to `jpeg`.
  141. attributes.subtype = ( 'jpg' === image[0] ) ? 'jpeg' : image[0];
  142. }
  143. // Create the `Attachment`.
  144. file.attachment = wp.media.model.Attachment.create( attributes );
  145. Uploader.queue.add( file.attachment );
  146. self.added( file.attachment );
  147. });
  148. up.refresh();
  149. up.start();
  150. });
  151. this.uploader.bind( 'UploadProgress', function( up, file ) {
  152. file.attachment.set( _.pick( file, 'loaded', 'percent' ) );
  153. self.progress( file.attachment );
  154. });
  155. this.uploader.bind( 'FileUploaded', function( up, file, response ) {
  156. var complete;
  157. try {
  158. response = JSON.parse( response.response );
  159. } catch ( e ) {
  160. return error( pluploadL10n.default_error, e, file );
  161. }
  162. if ( ! _.isObject( response ) || _.isUndefined( response.success ) )
  163. return error( pluploadL10n.default_error, null, file );
  164. else if ( ! response.success )
  165. return error( response.data && response.data.message, response.data, file );
  166. _.each(['file','loaded','size','percent'], function( key ) {
  167. file.attachment.unset( key );
  168. });
  169. file.attachment.set( _.extend( response.data, { uploading: false }) );
  170. wp.media.model.Attachment.get( response.data.id, file.attachment );
  171. complete = Uploader.queue.all( function( attachment ) {
  172. return ! attachment.get('uploading');
  173. });
  174. if ( complete )
  175. Uploader.queue.reset();
  176. self.success( file.attachment );
  177. });
  178. this.uploader.bind( 'Error', function( up, pluploadError ) {
  179. var message = pluploadL10n.default_error,
  180. key;
  181. // Check for plupload errors.
  182. for ( key in Uploader.errorMap ) {
  183. if ( pluploadError.code === plupload[ key ] ) {
  184. message = Uploader.errorMap[ key ];
  185. if ( _.isFunction( message ) )
  186. message = message( pluploadError.file, pluploadError );
  187. break;
  188. }
  189. }
  190. error( message, pluploadError, pluploadError.file );
  191. up.refresh();
  192. });
  193. this.init();
  194. };
  195. // Adds the 'defaults' and 'browser' properties.
  196. $.extend( Uploader, _wpPluploadSettings );
  197. Uploader.uuid = 0;
  198. Uploader.errorMap = {
  199. 'FAILED': pluploadL10n.upload_failed,
  200. 'FILE_EXTENSION_ERROR': pluploadL10n.invalid_filetype,
  201. 'IMAGE_FORMAT_ERROR': pluploadL10n.not_an_image,
  202. 'IMAGE_MEMORY_ERROR': pluploadL10n.image_memory_exceeded,
  203. 'IMAGE_DIMENSIONS_ERROR': pluploadL10n.image_dimensions_exceeded,
  204. 'GENERIC_ERROR': pluploadL10n.upload_failed,
  205. 'IO_ERROR': pluploadL10n.io_error,
  206. 'HTTP_ERROR': pluploadL10n.http_error,
  207. 'SECURITY_ERROR': pluploadL10n.security_error,
  208. 'FILE_SIZE_ERROR': function( file ) {
  209. return pluploadL10n.file_exceeds_size_limit.replace('%s', file.name);
  210. }
  211. };
  212. $.extend( Uploader.prototype, {
  213. /**
  214. * Acts as a shortcut to extending the uploader's multipart_params object.
  215. *
  216. * param( key )
  217. * Returns the value of the key.
  218. *
  219. * param( key, value )
  220. * Sets the value of a key.
  221. *
  222. * param( map )
  223. * Sets values for a map of data.
  224. */
  225. param: function( key, value ) {
  226. if ( arguments.length === 1 && typeof key === 'string' )
  227. return this.uploader.settings.multipart_params[ key ];
  228. if ( arguments.length > 1 ) {
  229. this.uploader.settings.multipart_params[ key ] = value;
  230. } else {
  231. $.extend( this.uploader.settings.multipart_params, key );
  232. }
  233. },
  234. init: function() {},
  235. error: function() {},
  236. success: function() {},
  237. added: function() {},
  238. progress: function() {},
  239. complete: function() {},
  240. refresh: function() {
  241. var node, attached, container, id;
  242. if ( this.browser ) {
  243. node = this.browser[0];
  244. // Check if the browser node is in the DOM.
  245. while ( node ) {
  246. if ( node === document.body ) {
  247. attached = true;
  248. break;
  249. }
  250. node = node.parentNode;
  251. }
  252. // If the browser node is not attached to the DOM, use a
  253. // temporary container to house it, as the browser button
  254. // shims require the button to exist in the DOM at all times.
  255. if ( ! attached ) {
  256. id = 'wp-uploader-browser-' + this.uploader.id;
  257. container = $( '#' + id );
  258. if ( ! container.length ) {
  259. container = $('<div class="wp-uploader-browser" />').css({
  260. position: 'fixed',
  261. top: '-1000px',
  262. left: '-1000px',
  263. height: 0,
  264. width: 0
  265. }).attr( 'id', 'wp-uploader-browser-' + this.uploader.id ).appendTo('body');
  266. }
  267. container.append( this.browser );
  268. }
  269. }
  270. this.uploader.refresh();
  271. }
  272. });
  273. Uploader.queue = new wp.media.model.Attachments( [], { query: false });
  274. Uploader.errors = new Backbone.Collection();
  275. exports.Uploader = Uploader;
  276. })( wp, jQuery );