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

/html/blog/wp-includes/js/plupload/wp-plupload.js

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