From 1cc9c42bc47d40f0924d9548c7de49776d1ed0ab Mon Sep 17 00:00:00 2001 From: Daryl Koopersmith Date: Tue, 11 Sep 2012 16:55:58 +0000 Subject: [PATCH] Use JS Attachment models in wp.Uploader. fixes #21868. Moves the uploading Attachments queue from the media workspace view to the uploader itself. This ensures that all attachments are added to the central attachmnet store. Updates wp.Uploader to pass Attachment models to callbacks instead of Plupload file objects. Attachments in the process of uploading have a reference to the file object (which can be fetched by calling `attachment.get('file');`). Also updates the customizer to be compatible with the API changes. git-svn-id: https://develop.svn.wordpress.org/trunk@21814 602fd350-edb4-49c9-b593-d223f7449a82 --- wp-admin/includes/ajax-actions.php | 29 +++-------- wp-admin/js/customize-controls.js | 19 +++---- wp-includes/js/media-views.js | 72 +++++++------------------- wp-includes/js/plupload/wp-plupload.js | 68 +++++++++++++++++------- wp-includes/script-loader.php | 2 +- 5 files changed, 88 insertions(+), 102 deletions(-) diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index b6dcca4bb5..5dbe74e23b 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -1611,12 +1611,12 @@ function wp_ajax_upload_attachment() { check_ajax_referer( 'media-form' ); if ( ! current_user_can( 'upload_files' ) ) - wp_die( -1 ); + wp_send_json_error(); if ( isset( $_REQUEST['post_id'] ) ) { $post_id = $_REQUEST['post_id']; if ( ! current_user_can( 'edit_post', $post_id ) ) - wp_die( -1 ); + wp_send_json_error(); } else { $post_id = null; } @@ -1626,14 +1626,10 @@ function wp_ajax_upload_attachment() { $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data ); if ( is_wp_error( $attachment_id ) ) { - echo json_encode( array( - 'type' => 'error', - 'data' => array( - 'message' => $attachment_id->get_error_message(), - 'filename' => $_FILES['async-upload']['name'], - ), + wp_send_json_error( array( + 'message' => $attachment_id->get_error_message(), + 'filename' => $_FILES['async-upload']['name'], ) ); - wp_die(); } if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) { @@ -1644,19 +1640,10 @@ function wp_ajax_upload_attachment() { update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] ); } - $post = get_post( $attachment_id ); + if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) ) + wp_send_json_error(); - echo json_encode( array( - 'type' => 'success', - 'data' => array( - 'id' => $attachment_id, - 'title' => esc_attr( $post->post_title ), - 'filename' => esc_html( basename( $post->guid ) ), - 'url' => wp_get_attachment_url( $attachment_id ), - 'meta' => wp_get_attachment_metadata( $attachment_id ), - ), - ) ); - wp_die(); + wp_send_json_success( $attachment ); } function wp_ajax_image_editor() { diff --git a/wp-admin/js/customize-controls.js b/wp-admin/js/customize-controls.js index 900ab13c01..12e0f16a7e 100644 --- a/wp-admin/js/customize-controls.js +++ b/wp-admin/js/customize-controls.js @@ -168,7 +168,7 @@ this.removerVisibility( this.setting.get() ); }, success: function( attachment ) { - this.setting.set( attachment.url ); + this.setting.set( attachment.get('url') ); }, removerVisibility: function( to ) { this.remover.toggle( to != this.params.removed ); @@ -272,9 +272,10 @@ if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) { this.tabs.uploaded.both.removeClass('hidden'); + // @todo: Do NOT store this on the attachment model. That is bad. attachment.element = $( '' ) - .data( 'customizeImageValue', attachment.url ) - .append( '' ) + .data( 'customizeImageValue', attachment.get('url') ) + .append( '' ) .appendTo( this.tabs.uploaded.target ); } }, @@ -945,16 +946,16 @@ api.ImageControl.prototype.success.call( control, attachment ); data = { - attachment_id: attachment.id, - url: attachment.url, - thumbnail_url: attachment.url, - height: attachment.meta.height, - width: attachment.meta.width + attachment_id: attachment.get('id'), + url: attachment.get('url'), + thumbnail_url: attachment.get('url'), + height: attachment.get('height'), + width: attachment.get('width') }; attachment.element.data( 'customizeHeaderImageData', data ); control.settings.data.set( data ); - } + }; }); api.trigger( 'ready' ); diff --git a/wp-includes/js/media-views.js b/wp-includes/js/media-views.js index 032b5d85f2..49a33f750e 100644 --- a/wp-includes/js/media-views.js +++ b/wp-includes/js/media-views.js @@ -279,26 +279,14 @@ this.$content.append( this.attachmentsView.$el ); // Track uploading attachments. - this.pending = new Attachments( [], { query: false }); - this.pending.on( 'add remove reset change:percent', function() { - this.$el.toggleClass( 'uploading', !! this.pending.length ); - - if ( ! this.$bar || ! this.pending.length ) - return; - - this.$bar.width( ( this.pending.reduce( function( memo, attachment ) { - if ( attachment.get('uploading') ) - return memo + ( attachment.get('percent') || 0 ); - else - return memo + 100; - }, 0 ) / this.pending.length ) + '%' ); - }, this ); + wp.Uploader.queue.on( 'add remove reset change:percent', this.renderUploadProgress, this ); }, render: function() { this.attachmentsView.render(); + this.renderUploadProgress(); this.$el.html( this.template( this.options ) ).append( this.$content ); - this.$bar = this.$('.media-progress-bar div'); + this.$bar = this.$('.upload-attachments .media-progress-bar div'); return this; }, @@ -312,46 +300,26 @@ this.uploader = new wp.Uploader( _.extend({ container: this.$el, dropzone: this.$el, - browser: this.$('.upload-attachments a'), - - added: function( file ) { - file.attachment = Attachment.create( _.extend({ - file: file, - uploading: true, - date: new Date() - }, _.pick( file, 'loaded', 'size', 'percent' ) ) ); - - workspace.pending.add( file.attachment ); - }, - - progress: function( file ) { - file.attachment.set( _.pick( file, 'loaded', 'percent' ) ); - }, - - success: function( resp, file ) { - var complete; - - _.each(['file','loaded','size','uploading','percent'], function( key ) { - file.attachment.unset( key ); - }); - - file.attachment.set( 'id', resp.id ); - Attachment.get( resp.id, file.attachment ).fetch(); - - complete = workspace.pending.all( function( attachment ) { - return ! attachment.get('uploading'); - }); - - if ( complete ) - workspace.pending.reset(); - }, - - error: function( message, error, file ) { - file.attachment.destroy(); - } + browser: this.$('.upload-attachments a') }, this.options.uploader ) ); }, + renderUploadProgress: function() { + var queue = wp.Uploader.queue; + + this.$el.toggleClass( 'uploading', !! queue.length ); + + if ( ! this.$bar || ! queue.length ) + return; + + this.$bar.width( ( queue.reduce( function( memo, attachment ) { + if ( attachment.get('uploading') ) + return memo + ( attachment.get('percent') || 0 ); + else + return memo + 100; + }, 0 ) / queue.length ) + '%' ); + }, + // Initializes the toolbar view. Currently uses defaults set for // inserting media into a post. This should be pulled out into the // appropriate workflow when the time comes, but is currently here diff --git a/wp-includes/js/plupload/wp-plupload.js b/wp-includes/js/plupload/wp-plupload.js index e9ec49292a..31f21f6260 100644 --- a/wp-includes/js/plupload/wp-plupload.js +++ b/wp-includes/js/plupload/wp-plupload.js @@ -28,7 +28,7 @@ if ( typeof wp === 'undefined' ) browser: 'browse_button', dropzone: 'drop_element' }, - key; + key, error; this.supports = { upload: Uploader.browser.supported @@ -84,6 +84,12 @@ if ( typeof wp === 'undefined' ) this.param( this.params || {} ); delete this.params; + error = function( message, data, file ) { + if ( file.attachment ) + file.attachment.destroy(); + self.error( message, data, file ); + }; + this.uploader.init(); this.supports.dragdrop = this.uploader.features.dragdrop && ! Uploader.browser.mobile; @@ -134,26 +140,57 @@ if ( typeof wp === 'undefined' ) $('#' + this.uploader.id + '_html5_container').hide(); } + this.uploader.bind( 'FilesAdded', function( up, files ) { + _.each( files, function( file ) { + file.attachment = wp.media.model.Attachment.create( _.extend({ + file: file, + uploading: true, + date: new Date() + }, _.pick( file, 'loaded', 'size', 'percent' ) ) ); + + Uploader.queue.add( file.attachment ); + + self.added( file.attachment ); + }); + + up.refresh(); + up.start(); + }); + this.uploader.bind( 'UploadProgress', function( up, file ) { - self.progress( file ); + file.attachment.set( _.pick( file, 'loaded', 'percent' ) ); + self.progress( file.attachment ); }); this.uploader.bind( 'FileUploaded', function( up, file, response ) { + var complete; + try { response = JSON.parse( response.response ); } catch ( e ) { - return self.error( pluploadL10n.default_error, e ); + return error( pluploadL10n.default_error, e, file ); } - if ( ! response || ! response.type || ! response.data ) - return self.error( pluploadL10n.default_error ); + if ( ! _.isObject( response ) || _.isUndefined( response.success ) ) + return error( pluploadL10n.default_error, null, file ); + else if ( ! response.success ) + return error( response.data.message, response.data, file ); - if ( 'error' === response.type ) - return self.error( response.data.message, response.data, file ); + _.each(['file','loaded','size','uploading','percent'], function( key ) { + file.attachment.unset( key ); + }); - if ( 'success' === response.type ) - return self.success( response.data, file ); + file.attachment.set( response.data ); + wp.media.model.Attachment.get( response.data.id, file.attachment ); + complete = Uploader.queue.all( function( attachment ) { + return ! attachment.get('uploading'); + }); + + if ( complete ) + Uploader.queue.reset(); + + self.success( file.attachment ); }); this.uploader.bind( 'Error', function( up, error ) { @@ -168,19 +205,10 @@ if ( typeof wp === 'undefined' ) } } - self.error( message, error, error.file ); + error( message, error, error.file ); up.refresh(); }); - this.uploader.bind( 'FilesAdded', function( up, files ) { - $.each( files, function() { - self.added( this ); - }); - - up.refresh(); - up.start(); - }); - this.init(); }; @@ -237,5 +265,7 @@ if ( typeof wp === 'undefined' ) } }); + Uploader.queue = new wp.media.model.Attachments( [], { query: false }); + exports.Uploader = Uploader; })( wp, jQuery ); diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index 5fdc7e5335..6a03efeb29 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -232,7 +232,7 @@ function wp_default_scripts( &$scripts ) { $scripts->add( 'plupload-handlers', "/wp-includes/js/plupload/handlers$suffix.js", array('plupload-all', 'jquery') ); did_action( 'init' ) && $scripts->localize( 'plupload-handlers', 'pluploadL10n', $uploader_l10n ); - $scripts->add( 'wp-plupload', "/wp-includes/js/plupload/wp-plupload$suffix.js", array('plupload-all', 'jquery', 'json2') ); + $scripts->add( 'wp-plupload', "/wp-includes/js/plupload/wp-plupload$suffix.js", array('plupload-all', 'jquery', 'json2', 'media-models'), false, 1 ); did_action( 'init' ) && $scripts->localize( 'wp-plupload', 'pluploadL10n', $uploader_l10n ); // keep 'swfupload' for back-compat.