wp/wp-includes/js/media-editor.js
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 // WordPress, TinyMCE, and Media
       
     2 // -----------------------------
       
     3 (function($){
       
     4 	// Stores the editors' `wp.media.controller.Frame` instances.
       
     5 	var workflows = {};
       
     6 
       
     7 	wp.media.string = {
       
     8 		// Joins the `props` and `attachment` objects,
       
     9 		// outputting the proper object format based on the
       
    10 		// attachment's type.
       
    11 		props: function( props, attachment ) {
       
    12 			var link, linkUrl, size, sizes, fallbacks,
       
    13 				defaultProps = wp.media.view.settings.defaultProps;
       
    14 
       
    15 			// Final fallbacks run after all processing has been completed.
       
    16 			fallbacks = function( props ) {
       
    17 				// Generate alt fallbacks and strip tags.
       
    18 				if ( 'image' === props.type && ! props.alt ) {
       
    19 					props.alt = props.caption || props.title || '';
       
    20 					props.alt = props.alt.replace( /<\/?[^>]+>/g, '' );
       
    21 					props.alt = props.alt.replace( /[\r\n]+/g, ' ' );
       
    22 				}
       
    23 
       
    24 				return props;
       
    25 			};
       
    26 
       
    27 			props = props ? _.clone( props ) : {};
       
    28 
       
    29 			if ( attachment && attachment.type )
       
    30 				props.type = attachment.type;
       
    31 
       
    32 			if ( 'image' === props.type ) {
       
    33 				props = _.defaults( props || {}, {
       
    34 					align:   defaultProps.align || getUserSetting( 'align', 'none' ),
       
    35 					size:    defaultProps.size  || getUserSetting( 'imgsize', 'medium' ),
       
    36 					url:     '',
       
    37 					classes: []
       
    38 				});
       
    39 			}
       
    40 
       
    41 			// All attachment-specific settings follow.
       
    42 			if ( ! attachment )
       
    43 				return fallbacks( props );
       
    44 
       
    45 			props.title = props.title || attachment.title;
       
    46 
       
    47 			link = props.link || defaultProps.link || getUserSetting( 'urlbutton', 'file' );
       
    48 			if ( 'file' === link || 'embed' === link )
       
    49 				linkUrl = attachment.url;
       
    50 			else if ( 'post' === link )
       
    51 				linkUrl = attachment.link;
       
    52 			else if ( 'custom' === link )
       
    53 				linkUrl = props.linkUrl;
       
    54 			props.linkUrl = linkUrl || '';
       
    55 
       
    56 			// Format properties for images.
       
    57 			if ( 'image' === attachment.type ) {
       
    58 				props.classes.push( 'wp-image-' + attachment.id );
       
    59 
       
    60 				sizes = attachment.sizes;
       
    61 				size = sizes && sizes[ props.size ] ? sizes[ props.size ] : attachment;
       
    62 
       
    63 				_.extend( props, _.pick( attachment, 'align', 'caption', 'alt' ), {
       
    64 					width:     size.width,
       
    65 					height:    size.height,
       
    66 					src:       size.url,
       
    67 					captionId: 'attachment_' + attachment.id
       
    68 				});
       
    69 			} else if ( 'video' === attachment.type || 'audio' === attachment.type ) {
       
    70 				_.extend( props, _.pick( attachment, 'title', 'type', 'icon', 'mime' ) );
       
    71 			// Format properties for non-images.
       
    72 			} else {
       
    73 				props.title = props.title || attachment.filename;
       
    74 				props.rel = props.rel || 'attachment wp-att-' + attachment.id;
       
    75 			}
       
    76 
       
    77 			return fallbacks( props );
       
    78 		},
       
    79 
       
    80 		link: function( props, attachment ) {
       
    81 			var options;
       
    82 
       
    83 			props = wp.media.string.props( props, attachment );
       
    84 
       
    85 			options = {
       
    86 				tag:     'a',
       
    87 				content: props.title,
       
    88 				attrs:   {
       
    89 					href: props.linkUrl
       
    90 				}
       
    91 			};
       
    92 
       
    93 			if ( props.rel )
       
    94 				options.attrs.rel = props.rel;
       
    95 
       
    96 			return wp.html.string( options );
       
    97 		},
       
    98 
       
    99 		audio: function( props, attachment ) {
       
   100 			return wp.media.string._audioVideo( 'audio', props, attachment );
       
   101 		},
       
   102 
       
   103 		video: function( props, attachment ) {
       
   104 			return wp.media.string._audioVideo( 'video', props, attachment );
       
   105 		},
       
   106 
       
   107 		_audioVideo: function( type, props, attachment ) {
       
   108 			var shortcode, html, extension;
       
   109 
       
   110 			props = wp.media.string.props( props, attachment );
       
   111 			if ( props.link !== 'embed' )
       
   112 				return wp.media.string.link( props );
       
   113 
       
   114 			shortcode = {};
       
   115 
       
   116 			if ( 'video' === type ) {
       
   117 				if ( attachment.width )
       
   118 					shortcode.width = attachment.width;
       
   119 
       
   120 				if ( attachment.height )
       
   121 					shortcode.height = attachment.height;
       
   122 			}
       
   123 
       
   124 			extension = attachment.filename.split('.').pop();
       
   125 
       
   126 			if ( _.contains( wp.media.view.settings.embedExts, extension ) ) {
       
   127 				shortcode[extension] = attachment.url;
       
   128 			} else {
       
   129 				// Render unsupported audio and video files as links.
       
   130 				return wp.media.string.link( props );
       
   131 			}
       
   132 
       
   133 			html = wp.shortcode.string({
       
   134 				tag:     type,
       
   135 				attrs:   shortcode
       
   136 			});
       
   137 
       
   138 			return html;
       
   139 		},
       
   140 
       
   141 		image: function( props, attachment ) {
       
   142 			var img = {},
       
   143 				options, classes, shortcode, html;
       
   144 
       
   145 			props = wp.media.string.props( props, attachment );
       
   146 			classes = props.classes || [];
       
   147 
       
   148 			img.src = typeof attachment !== 'undefined' ? attachment.url : props.url;
       
   149 			_.extend( img, _.pick( props, 'width', 'height', 'alt' ) );
       
   150 
       
   151 			// Only assign the align class to the image if we're not printing
       
   152 			// a caption, since the alignment is sent to the shortcode.
       
   153 			if ( props.align && ! props.caption )
       
   154 				classes.push( 'align' + props.align );
       
   155 
       
   156 			if ( props.size )
       
   157 				classes.push( 'size-' + props.size );
       
   158 
       
   159 			img['class'] = _.compact( classes ).join(' ');
       
   160 
       
   161 			// Generate `img` tag options.
       
   162 			options = {
       
   163 				tag:    'img',
       
   164 				attrs:  img,
       
   165 				single: true
       
   166 			};
       
   167 
       
   168 			// Generate the `a` element options, if they exist.
       
   169 			if ( props.linkUrl ) {
       
   170 				options = {
       
   171 					tag:   'a',
       
   172 					attrs: {
       
   173 						href: props.linkUrl
       
   174 					},
       
   175 					content: options
       
   176 				};
       
   177 			}
       
   178 
       
   179 			html = wp.html.string( options );
       
   180 
       
   181 			// Generate the caption shortcode.
       
   182 			if ( props.caption ) {
       
   183 				shortcode = {};
       
   184 
       
   185 				if ( img.width )
       
   186 					shortcode.width = img.width;
       
   187 
       
   188 				if ( props.captionId )
       
   189 					shortcode.id = props.captionId;
       
   190 
       
   191 				if ( props.align )
       
   192 					shortcode.align = 'align' + props.align;
       
   193 
       
   194 				html = wp.shortcode.string({
       
   195 					tag:     'caption',
       
   196 					attrs:   shortcode,
       
   197 					content: html + ' ' + props.caption
       
   198 				});
       
   199 			}
       
   200 
       
   201 			return html;
       
   202 		}
       
   203 	};
       
   204 
       
   205 	wp.media.gallery = (function() {
       
   206 		var galleries = {};
       
   207 
       
   208 		return {
       
   209 			defaults: {
       
   210 				order:      'ASC',
       
   211 				id:         wp.media.view.settings.post.id,
       
   212 				itemtag:    'dl',
       
   213 				icontag:    'dt',
       
   214 				captiontag: 'dd',
       
   215 				columns:    '3',
       
   216 				link:       'post',
       
   217 				size:       'thumbnail',
       
   218 				orderby:    'menu_order ID'
       
   219 			},
       
   220 
       
   221 			attachments: function( shortcode ) {
       
   222 				var shortcodeString = shortcode.string(),
       
   223 					result = galleries[ shortcodeString ],
       
   224 					attrs, args, query, others;
       
   225 
       
   226 				delete galleries[ shortcodeString ];
       
   227 
       
   228 				if ( result )
       
   229 					return result;
       
   230 
       
   231 				// Fill the default shortcode attributes.
       
   232 				attrs = _.defaults( shortcode.attrs.named, wp.media.gallery.defaults );
       
   233 				args  = _.pick( attrs, 'orderby', 'order' );
       
   234 
       
   235 				args.type    = 'image';
       
   236 				args.perPage = -1;
       
   237 
       
   238 				// Mark the `orderby` override attribute.
       
   239 				if( undefined !== attrs.orderby )
       
   240 					attrs._orderByField = attrs.orderby;
       
   241 
       
   242 				if ( 'rand' === attrs.orderby )
       
   243 					attrs._orderbyRandom = true;
       
   244 
       
   245 				// Map the `orderby` attribute to the corresponding model property.
       
   246 				if ( ! attrs.orderby || /^menu_order(?: ID)?$/i.test( attrs.orderby ) )
       
   247 					args.orderby = 'menuOrder';
       
   248 
       
   249 				// Map the `ids` param to the correct query args.
       
   250 				if ( attrs.ids ) {
       
   251 					args.post__in = attrs.ids.split(',');
       
   252 					args.orderby  = 'post__in';
       
   253 				} else if ( attrs.include ) {
       
   254 					args.post__in = attrs.include.split(',');
       
   255 				}
       
   256 
       
   257 				if ( attrs.exclude )
       
   258 					args.post__not_in = attrs.exclude.split(',');
       
   259 
       
   260 				if ( ! args.post__in )
       
   261 					args.uploadedTo = attrs.id;
       
   262 
       
   263 				// Collect the attributes that were not included in `args`.
       
   264 				others = _.omit( attrs, 'id', 'ids', 'include', 'exclude', 'orderby', 'order' );
       
   265 
       
   266 				query = wp.media.query( args );
       
   267 				query.gallery = new Backbone.Model( others );
       
   268 				return query;
       
   269 			},
       
   270 
       
   271 			shortcode: function( attachments ) {
       
   272 				var props = attachments.props.toJSON(),
       
   273 					attrs = _.pick( props, 'orderby', 'order' ),
       
   274 					shortcode, clone;
       
   275 
       
   276 				if ( attachments.gallery )
       
   277 					_.extend( attrs, attachments.gallery.toJSON() );
       
   278 
       
   279 				// Convert all gallery shortcodes to use the `ids` property.
       
   280 				// Ignore `post__in` and `post__not_in`; the attachments in
       
   281 				// the collection will already reflect those properties.
       
   282 				attrs.ids = attachments.pluck('id');
       
   283 
       
   284 				// Copy the `uploadedTo` post ID.
       
   285 				if ( props.uploadedTo )
       
   286 					attrs.id = props.uploadedTo;
       
   287 
       
   288 				// Check if the gallery is randomly ordered.
       
   289 				delete attrs.orderby;
       
   290 
       
   291 				if ( attrs._orderbyRandom )
       
   292 					attrs.orderby = 'rand';
       
   293 				else if ( attrs._orderByField && attrs._orderByField != 'rand' )
       
   294 					attrs.orderby = attrs._orderByField;
       
   295 
       
   296 				delete attrs._orderbyRandom;
       
   297 				delete attrs._orderByField;
       
   298 
       
   299 				// If the `ids` attribute is set and `orderby` attribute
       
   300 				// is the default value, clear it for cleaner output.
       
   301 				if ( attrs.ids && 'post__in' === attrs.orderby )
       
   302 					delete attrs.orderby;
       
   303 
       
   304 				// Remove default attributes from the shortcode.
       
   305 				_.each( wp.media.gallery.defaults, function( value, key ) {
       
   306 					if ( value === attrs[ key ] )
       
   307 						delete attrs[ key ];
       
   308 				});
       
   309 
       
   310 				shortcode = new wp.shortcode({
       
   311 					tag:    'gallery',
       
   312 					attrs:  attrs,
       
   313 					type:   'single'
       
   314 				});
       
   315 
       
   316 				// Use a cloned version of the gallery.
       
   317 				clone = new wp.media.model.Attachments( attachments.models, {
       
   318 					props: props
       
   319 				});
       
   320 				clone.gallery = attachments.gallery;
       
   321 				galleries[ shortcode.string() ] = clone;
       
   322 
       
   323 				return shortcode;
       
   324 			},
       
   325 
       
   326 			edit: function( content ) {
       
   327 				var shortcode = wp.shortcode.next( 'gallery', content ),
       
   328 					defaultPostId = wp.media.gallery.defaults.id,
       
   329 					attachments, selection;
       
   330 
       
   331 				// Bail if we didn't match the shortcode or all of the content.
       
   332 				if ( ! shortcode || shortcode.content !== content )
       
   333 					return;
       
   334 
       
   335 				// Ignore the rest of the match object.
       
   336 				shortcode = shortcode.shortcode;
       
   337 
       
   338 				if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) )
       
   339 					shortcode.set( 'id', defaultPostId );
       
   340 
       
   341 				attachments = wp.media.gallery.attachments( shortcode );
       
   342 
       
   343 				selection = new wp.media.model.Selection( attachments.models, {
       
   344 					props:    attachments.props.toJSON(),
       
   345 					multiple: true
       
   346 				});
       
   347 
       
   348 				selection.gallery = attachments.gallery;
       
   349 
       
   350 				// Fetch the query's attachments, and then break ties from the
       
   351 				// query to allow for sorting.
       
   352 				selection.more().done( function() {
       
   353 					// Break ties with the query.
       
   354 					selection.props.set({ query: false });
       
   355 					selection.unmirror();
       
   356 					selection.props.unset('orderby');
       
   357 				});
       
   358 
       
   359 				// Destroy the previous gallery frame.
       
   360 				if ( this.frame )
       
   361 					this.frame.dispose();
       
   362 
       
   363 				// Store the current gallery frame.
       
   364 				this.frame = wp.media({
       
   365 					frame:     'post',
       
   366 					state:     'gallery-edit',
       
   367 					title:     wp.media.view.l10n.editGalleryTitle,
       
   368 					editing:   true,
       
   369 					multiple:  true,
       
   370 					selection: selection
       
   371 				}).open();
       
   372 
       
   373 				return this.frame;
       
   374 			}
       
   375 		};
       
   376 	}());
       
   377 
       
   378 	wp.media.featuredImage = {
       
   379 		get: function() {
       
   380 			return wp.media.view.settings.post.featuredImageId;
       
   381 		},
       
   382 
       
   383 		set: function( id ) {
       
   384 			var settings = wp.media.view.settings;
       
   385 
       
   386 			settings.post.featuredImageId = id;
       
   387 
       
   388 			wp.media.post( 'set-post-thumbnail', {
       
   389 				json:         true,
       
   390 				post_id:      settings.post.id,
       
   391 				thumbnail_id: settings.post.featuredImageId,
       
   392 				_wpnonce:     settings.post.nonce
       
   393 			}).done( function( html ) {
       
   394 				$( '.inside', '#postimagediv' ).html( html );
       
   395 			});
       
   396 		},
       
   397 
       
   398 		frame: function() {
       
   399 			if ( this._frame )
       
   400 				return this._frame;
       
   401 
       
   402 			this._frame = wp.media({
       
   403 				state: 'featured-image',
       
   404 				states: [ new wp.media.controller.FeaturedImage() ]
       
   405 			});
       
   406 
       
   407 			this._frame.on( 'toolbar:create:featured-image', function( toolbar ) {
       
   408 				this.createSelectToolbar( toolbar, {
       
   409 					text: wp.media.view.l10n.setFeaturedImage
       
   410 				});
       
   411 			}, this._frame );
       
   412 
       
   413 			this._frame.state('featured-image').on( 'select', this.select );
       
   414 			return this._frame;
       
   415 		},
       
   416 
       
   417 		select: function() {
       
   418 			var settings = wp.media.view.settings,
       
   419 				selection = this.get('selection').single();
       
   420 
       
   421 			if ( ! settings.post.featuredImageId )
       
   422 				return;
       
   423 
       
   424 			wp.media.featuredImage.set( selection ? selection.id : -1 );
       
   425 		},
       
   426 
       
   427 		init: function() {
       
   428 			// Open the content media manager to the 'featured image' tab when
       
   429 			// the post thumbnail is clicked.
       
   430 			$('#postimagediv').on( 'click', '#set-post-thumbnail', function( event ) {
       
   431 				event.preventDefault();
       
   432 				// Stop propagation to prevent thickbox from activating.
       
   433 				event.stopPropagation();
       
   434 
       
   435 				wp.media.featuredImage.frame().open();
       
   436 
       
   437 			// Update the featured image id when the 'remove' link is clicked.
       
   438 			}).on( 'click', '#remove-post-thumbnail', function() {
       
   439 				wp.media.view.settings.post.featuredImageId = -1;
       
   440 			});
       
   441 		}
       
   442 	};
       
   443 
       
   444 	$( wp.media.featuredImage.init );
       
   445 
       
   446 	wp.media.editor = {
       
   447 		insert: function( h ) {
       
   448 			var mce = typeof(tinymce) != 'undefined',
       
   449 				qt = typeof(QTags) != 'undefined',
       
   450 				wpActiveEditor = window.wpActiveEditor,
       
   451 				ed;
       
   452 
       
   453 			// Delegate to the global `send_to_editor` if it exists.
       
   454 			// This attempts to play nice with any themes/plugins that have
       
   455 			// overridden the insert functionality.
       
   456 			if ( window.send_to_editor )
       
   457 				return window.send_to_editor.apply( this, arguments );
       
   458 
       
   459 			if ( ! wpActiveEditor ) {
       
   460 				if ( mce && tinymce.activeEditor ) {
       
   461 					ed = tinymce.activeEditor;
       
   462 					wpActiveEditor = window.wpActiveEditor = ed.id;
       
   463 				} else if ( !qt ) {
       
   464 					return false;
       
   465 				}
       
   466 			} else if ( mce ) {
       
   467 				if ( tinymce.activeEditor && (tinymce.activeEditor.id == 'mce_fullscreen' || tinymce.activeEditor.id == 'wp_mce_fullscreen') )
       
   468 					ed = tinymce.activeEditor;
       
   469 				else
       
   470 					ed = tinymce.get(wpActiveEditor);
       
   471 			}
       
   472 
       
   473 			if ( ed && !ed.isHidden() ) {
       
   474 				// restore caret position on IE
       
   475 				if ( tinymce.isIE && ed.windowManager.insertimagebookmark )
       
   476 					ed.selection.moveToBookmark(ed.windowManager.insertimagebookmark);
       
   477 
       
   478 				if ( h.indexOf('[caption') !== -1 ) {
       
   479 					if ( ed.wpSetImgCaption )
       
   480 						h = ed.wpSetImgCaption(h);
       
   481 				} else if ( h.indexOf('[gallery') !== -1 ) {
       
   482 					if ( ed.plugins.wpgallery )
       
   483 						h = ed.plugins.wpgallery._do_gallery(h);
       
   484 				} else if ( h.indexOf('[embed') === 0 ) {
       
   485 					if ( ed.plugins.wordpress )
       
   486 						h = ed.plugins.wordpress._setEmbed(h);
       
   487 				}
       
   488 
       
   489 				ed.execCommand('mceInsertContent', false, h);
       
   490 			} else if ( qt ) {
       
   491 				QTags.insertContent(h);
       
   492 			} else {
       
   493 				document.getElementById(wpActiveEditor).value += h;
       
   494 			}
       
   495 
       
   496 			// If the old thickbox remove function exists, call it in case
       
   497 			// a theme/plugin overloaded it.
       
   498 			if ( window.tb_remove )
       
   499 				try { window.tb_remove(); } catch( e ) {}
       
   500 		},
       
   501 
       
   502 		add: function( id, options ) {
       
   503 			var workflow = this.get( id );
       
   504 
       
   505 			if ( workflow ) // only add once: if exists return existing
       
   506 				return workflow;
       
   507 
       
   508 			workflow = workflows[ id ] = wp.media( _.defaults( options || {}, {
       
   509 				frame:    'post',
       
   510 				state:    'insert',
       
   511 				title:    wp.media.view.l10n.addMedia,
       
   512 				multiple: true
       
   513 			} ) );
       
   514 
       
   515 			workflow.on( 'insert', function( selection ) {
       
   516 				var state = workflow.state();
       
   517 
       
   518 				selection = selection || state.get('selection');
       
   519 
       
   520 				if ( ! selection )
       
   521 					return;
       
   522 
       
   523 				$.when.apply( $, selection.map( function( attachment ) {
       
   524 					var display = state.display( attachment ).toJSON();
       
   525 					return this.send.attachment( display, attachment.toJSON() );
       
   526 				}, this ) ).done( function() {
       
   527 					wp.media.editor.insert( _.toArray( arguments ).join("\n\n") );
       
   528 				});
       
   529 			}, this );
       
   530 
       
   531 			workflow.state('gallery-edit').on( 'update', function( selection ) {
       
   532 				this.insert( wp.media.gallery.shortcode( selection ).string() );
       
   533 			}, this );
       
   534 
       
   535 			workflow.state('embed').on( 'select', function() {
       
   536 				var state = workflow.state(),
       
   537 					type = state.get('type'),
       
   538 					embed = state.props.toJSON();
       
   539 
       
   540 				embed.url = embed.url || '';
       
   541 
       
   542 				if ( 'link' === type ) {
       
   543 					_.defaults( embed, {
       
   544 						title:   embed.url,
       
   545 						linkUrl: embed.url
       
   546 					});
       
   547 
       
   548 					this.send.link( embed ).done( function( resp ) {
       
   549 						wp.media.editor.insert( resp );
       
   550 					});
       
   551 
       
   552 				} else if ( 'image' === type ) {
       
   553 					_.defaults( embed, {
       
   554 						title:   embed.url,
       
   555 						linkUrl: '',
       
   556 						align:   'none',
       
   557 						link:    'none'
       
   558 					});
       
   559 
       
   560 					if ( 'none' === embed.link )
       
   561 						embed.linkUrl = '';
       
   562 					else if ( 'file' === embed.link )
       
   563 						embed.linkUrl = embed.url;
       
   564 
       
   565 					this.insert( wp.media.string.image( embed ) );
       
   566 				}
       
   567 			}, this );
       
   568 
       
   569 			workflow.state('featured-image').on( 'select', wp.media.featuredImage.select );
       
   570 			workflow.setState( workflow.options.state );
       
   571 			return workflow;
       
   572 		},
       
   573 
       
   574 		id: function( id ) {
       
   575 			if ( id )
       
   576 				return id;
       
   577 
       
   578 			// If an empty `id` is provided, default to `wpActiveEditor`.
       
   579 			id = wpActiveEditor;
       
   580 
       
   581 			// If that doesn't work, fall back to `tinymce.activeEditor.id`.
       
   582 			if ( ! id && typeof tinymce !== 'undefined' && tinymce.activeEditor )
       
   583 				id = tinymce.activeEditor.id;
       
   584 
       
   585 			// Last but not least, fall back to the empty string.
       
   586 			id = id || '';
       
   587 			return id;
       
   588 		},
       
   589 
       
   590 		get: function( id ) {
       
   591 			id = this.id( id );
       
   592 			return workflows[ id ];
       
   593 		},
       
   594 
       
   595 		remove: function( id ) {
       
   596 			id = this.id( id );
       
   597 			delete workflows[ id ];
       
   598 		},
       
   599 
       
   600 		send: {
       
   601 			attachment: function( props, attachment ) {
       
   602 				var caption = attachment.caption,
       
   603 					options, html;
       
   604 
       
   605 				// If captions are disabled, clear the caption.
       
   606 				if ( ! wp.media.view.settings.captions )
       
   607 					delete attachment.caption;
       
   608 
       
   609 				props = wp.media.string.props( props, attachment );
       
   610 
       
   611 				options = {
       
   612 					id:           attachment.id,
       
   613 					post_content: attachment.description,
       
   614 					post_excerpt: caption
       
   615 				};
       
   616 
       
   617 				if ( props.linkUrl )
       
   618 					options.url = props.linkUrl;
       
   619 
       
   620 				if ( 'image' === attachment.type ) {
       
   621 					html = wp.media.string.image( props );
       
   622 
       
   623 					_.each({
       
   624 						align: 'align',
       
   625 						size:  'image-size',
       
   626 						alt:   'image_alt'
       
   627 					}, function( option, prop ) {
       
   628 						if ( props[ prop ] )
       
   629 							options[ option ] = props[ prop ];
       
   630 					});
       
   631 				} else if ( 'video' === attachment.type ) {
       
   632 					html = wp.media.string.video( props, attachment );
       
   633 				} else if ( 'audio' === attachment.type ) {
       
   634 					html = wp.media.string.audio( props, attachment );
       
   635 				} else {
       
   636 					html = wp.media.string.link( props );
       
   637 					options.post_title = props.title;
       
   638 				}
       
   639 
       
   640 				return wp.media.post( 'send-attachment-to-editor', {
       
   641 					nonce:      wp.media.view.settings.nonce.sendToEditor,
       
   642 					attachment: options,
       
   643 					html:       html,
       
   644 					post_id:    wp.media.view.settings.post.id
       
   645 				});
       
   646 			},
       
   647 
       
   648 			link: function( embed ) {
       
   649 				return wp.media.post( 'send-link-to-editor', {
       
   650 					nonce:   wp.media.view.settings.nonce.sendToEditor,
       
   651 					src:     embed.linkUrl,
       
   652 					title:   embed.title,
       
   653 					html:    wp.media.string.link( embed ),
       
   654 					post_id: wp.media.view.settings.post.id
       
   655 				});
       
   656 			}
       
   657 		},
       
   658 
       
   659 		open: function( id, options ) {
       
   660 			var workflow, editor;
       
   661 
       
   662 			options = options || {};
       
   663 
       
   664 			id = this.id( id );
       
   665 
       
   666 			// Save a bookmark of the caret position in IE.
       
   667 			if ( typeof tinymce !== 'undefined' ) {
       
   668 				editor = tinymce.get( id );
       
   669 
       
   670 				if ( tinymce.isIE && editor && ! editor.isHidden() ) {
       
   671 					editor.focus();
       
   672 					editor.windowManager.insertimagebookmark = editor.selection.getBookmark();
       
   673 				}
       
   674 			}
       
   675 
       
   676 			workflow = this.get( id );
       
   677 
       
   678 			// Redo workflow if state has changed
       
   679 			if ( ! workflow || ( workflow.options && options.state !== workflow.options.state ) )
       
   680 				workflow = this.add( id, options );
       
   681 
       
   682 			return workflow.open();
       
   683 		},
       
   684 
       
   685 		init: function() {
       
   686 			$(document.body).on( 'click', '.insert-media', function( event ) {
       
   687 				var $this = $(this),
       
   688 					editor = $this.data('editor'),
       
   689 					options = {
       
   690 						frame:    'post',
       
   691 						state:    'insert',
       
   692 						title:    wp.media.view.l10n.addMedia,
       
   693 						multiple: true
       
   694 					};
       
   695 
       
   696 				event.preventDefault();
       
   697 
       
   698 				// Remove focus from the `.insert-media` button.
       
   699 				// Prevents Opera from showing the outline of the button
       
   700 				// above the modal.
       
   701 				//
       
   702 				// See: http://core.trac.wordpress.org/ticket/22445
       
   703 				$this.blur();
       
   704 
       
   705 				if ( $this.hasClass( 'gallery' ) ) {
       
   706 					options.state = 'gallery';
       
   707 					options.title = wp.media.view.l10n.createGalleryTitle;
       
   708 				}
       
   709 
       
   710 				wp.media.editor.open( editor, options );
       
   711 			});
       
   712 		}
       
   713 	};
       
   714 
       
   715 	_.bindAll( wp.media.editor, 'open' );
       
   716 	$( wp.media.editor.init );
       
   717 }(jQuery));