|
1 /* global getUserSetting, tinymce, QTags */ |
|
2 |
1 // WordPress, TinyMCE, and Media |
3 // WordPress, TinyMCE, and Media |
2 // ----------------------------- |
4 // ----------------------------- |
3 (function($){ |
5 (function($, _){ |
4 // Stores the editors' `wp.media.controller.Frame` instances. |
6 /** |
|
7 * Stores the editors' `wp.media.controller.Frame` instances. |
|
8 * |
|
9 * @static |
|
10 */ |
5 var workflows = {}; |
11 var workflows = {}; |
6 |
12 |
|
13 /** |
|
14 * A helper mixin function to avoid truthy and falsey values being |
|
15 * passed as an input that expects booleans. If key is undefined in the map, |
|
16 * but has a default value, set it. |
|
17 * |
|
18 * @param {object} attrs Map of props from a shortcode or settings. |
|
19 * @param {string} key The key within the passed map to check for a value. |
|
20 * @returns {mixed|undefined} The original or coerced value of key within attrs |
|
21 */ |
|
22 wp.media.coerce = function ( attrs, key ) { |
|
23 if ( _.isUndefined( attrs[ key ] ) && ! _.isUndefined( this.defaults[ key ] ) ) { |
|
24 attrs[ key ] = this.defaults[ key ]; |
|
25 } else if ( 'true' === attrs[ key ] ) { |
|
26 attrs[ key ] = true; |
|
27 } else if ( 'false' === attrs[ key ] ) { |
|
28 attrs[ key ] = false; |
|
29 } |
|
30 return attrs[ key ]; |
|
31 }; |
|
32 |
|
33 /** |
|
34 * wp.media.string |
|
35 * @namespace |
|
36 */ |
7 wp.media.string = { |
37 wp.media.string = { |
8 // Joins the `props` and `attachment` objects, |
38 /** |
9 // outputting the proper object format based on the |
39 * Joins the `props` and `attachment` objects, |
10 // attachment's type. |
40 * outputting the proper object format based on the |
|
41 * attachment's type. |
|
42 * |
|
43 * @global wp.media.view.settings |
|
44 * @global getUserSetting() |
|
45 * |
|
46 * @param {Object} [props={}] Attachment details (align, link, size, etc). |
|
47 * @param {Object} attachment The attachment object, media version of Post. |
|
48 * @returns {Object} Joined props |
|
49 */ |
11 props: function( props, attachment ) { |
50 props: function( props, attachment ) { |
12 var link, linkUrl, size, sizes, fallbacks, |
51 var link, linkUrl, size, sizes, fallbacks, |
13 defaultProps = wp.media.view.settings.defaultProps; |
52 defaultProps = wp.media.view.settings.defaultProps; |
14 |
53 |
15 // Final fallbacks run after all processing has been completed. |
54 // Final fallbacks run after all processing has been completed. |
88 attrs: { |
138 attrs: { |
89 href: props.linkUrl |
139 href: props.linkUrl |
90 } |
140 } |
91 }; |
141 }; |
92 |
142 |
93 if ( props.rel ) |
143 if ( props.rel ) { |
94 options.attrs.rel = props.rel; |
144 options.attrs.rel = props.rel; |
|
145 } |
95 |
146 |
96 return wp.html.string( options ); |
147 return wp.html.string( options ); |
97 }, |
148 }, |
98 |
149 /** |
|
150 * Create an Audio shortcode string that is suitable for passing to the editor |
|
151 * |
|
152 * @param {Object} props Attachment details (align, link, size, etc). |
|
153 * @param {Object} attachment The attachment object, media version of Post. |
|
154 * @returns {string} The audio shortcode |
|
155 */ |
99 audio: function( props, attachment ) { |
156 audio: function( props, attachment ) { |
100 return wp.media.string._audioVideo( 'audio', props, attachment ); |
157 return wp.media.string._audioVideo( 'audio', props, attachment ); |
101 }, |
158 }, |
102 |
159 /** |
|
160 * Create a Video shortcode string that is suitable for passing to the editor |
|
161 * |
|
162 * @param {Object} props Attachment details (align, link, size, etc). |
|
163 * @param {Object} attachment The attachment object, media version of Post. |
|
164 * @returns {string} The video shortcode |
|
165 */ |
103 video: function( props, attachment ) { |
166 video: function( props, attachment ) { |
104 return wp.media.string._audioVideo( 'video', props, attachment ); |
167 return wp.media.string._audioVideo( 'video', props, attachment ); |
105 }, |
168 }, |
106 |
169 /** |
|
170 * Helper function to create a media shortcode string |
|
171 * |
|
172 * @access private |
|
173 * |
|
174 * @global wp.shortcode |
|
175 * @global wp.media.view.settings |
|
176 * |
|
177 * @param {string} type The shortcode tag name: 'audio' or 'video'. |
|
178 * @param {Object} props Attachment details (align, link, size, etc). |
|
179 * @param {Object} attachment The attachment object, media version of Post. |
|
180 * @returns {string} The media shortcode |
|
181 */ |
107 _audioVideo: function( type, props, attachment ) { |
182 _audioVideo: function( type, props, attachment ) { |
108 var shortcode, html, extension; |
183 var shortcode, html, extension; |
109 |
184 |
110 props = wp.media.string.props( props, attachment ); |
185 props = wp.media.string.props( props, attachment ); |
111 if ( props.link !== 'embed' ) |
186 if ( props.link !== 'embed' ) |
112 return wp.media.string.link( props ); |
187 return wp.media.string.link( props ); |
113 |
188 |
114 shortcode = {}; |
189 shortcode = {}; |
115 |
190 |
116 if ( 'video' === type ) { |
191 if ( 'video' === type ) { |
117 if ( attachment.width ) |
192 if ( attachment.image && -1 === attachment.image.src.indexOf( attachment.icon ) ) { |
|
193 shortcode.poster = attachment.image.src; |
|
194 } |
|
195 |
|
196 if ( attachment.width ) { |
118 shortcode.width = attachment.width; |
197 shortcode.width = attachment.width; |
119 |
198 } |
120 if ( attachment.height ) |
199 |
|
200 if ( attachment.height ) { |
121 shortcode.height = attachment.height; |
201 shortcode.height = attachment.height; |
|
202 } |
122 } |
203 } |
123 |
204 |
124 extension = attachment.filename.split('.').pop(); |
205 extension = attachment.filename.split('.').pop(); |
125 |
206 |
126 if ( _.contains( wp.media.view.settings.embedExts, extension ) ) { |
207 if ( _.contains( wp.media.view.settings.embedExts, extension ) ) { |
200 |
296 |
201 return html; |
297 return html; |
202 } |
298 } |
203 }; |
299 }; |
204 |
300 |
205 wp.media.gallery = (function() { |
301 wp.media.embed = { |
206 var galleries = {}; |
302 coerce : wp.media.coerce, |
207 |
303 |
208 return { |
304 defaults : { |
209 defaults: { |
305 url : '', |
210 order: 'ASC', |
306 width: '', |
211 id: wp.media.view.settings.post.id, |
307 height: '' |
212 itemtag: 'dl', |
308 }, |
213 icontag: 'dt', |
309 |
214 captiontag: 'dd', |
310 edit : function( data, isURL ) { |
215 columns: '3', |
311 var frame, props = {}, shortcode; |
216 link: 'post', |
312 |
217 size: 'thumbnail', |
313 if ( isURL ) { |
218 orderby: 'menu_order ID' |
314 props.url = data.replace(/<[^>]+>/g, ''); |
219 }, |
315 } else { |
220 |
316 shortcode = wp.shortcode.next( 'embed', data ).shortcode; |
|
317 |
|
318 props = _.defaults( shortcode.attrs.named, this.defaults ); |
|
319 if ( shortcode.content ) { |
|
320 props.url = shortcode.content; |
|
321 } |
|
322 } |
|
323 |
|
324 frame = wp.media({ |
|
325 frame: 'post', |
|
326 state: 'embed', |
|
327 metadata: props |
|
328 }); |
|
329 |
|
330 return frame; |
|
331 }, |
|
332 |
|
333 shortcode : function( model ) { |
|
334 var self = this, content; |
|
335 |
|
336 _.each( this.defaults, function( value, key ) { |
|
337 model[ key ] = self.coerce( model, key ); |
|
338 |
|
339 if ( value === model[ key ] ) { |
|
340 delete model[ key ]; |
|
341 } |
|
342 }); |
|
343 |
|
344 content = model.url; |
|
345 delete model.url; |
|
346 |
|
347 return new wp.shortcode({ |
|
348 tag: 'embed', |
|
349 attrs: model, |
|
350 content: content |
|
351 }); |
|
352 } |
|
353 }; |
|
354 |
|
355 wp.media.collection = function(attributes) { |
|
356 var collections = {}; |
|
357 |
|
358 return _.extend( { |
|
359 coerce : wp.media.coerce, |
|
360 /** |
|
361 * Retrieve attachments based on the properties of the passed shortcode |
|
362 * |
|
363 * @global wp.media.query |
|
364 * |
|
365 * @param {wp.shortcode} shortcode An instance of wp.shortcode(). |
|
366 * @returns {wp.media.model.Attachments} A Backbone.Collection containing |
|
367 * the media items belonging to a collection. |
|
368 * The query[ this.tag ] property is a Backbone.Model |
|
369 * containing the 'props' for the collection. |
|
370 */ |
221 attachments: function( shortcode ) { |
371 attachments: function( shortcode ) { |
222 var shortcodeString = shortcode.string(), |
372 var shortcodeString = shortcode.string(), |
223 result = galleries[ shortcodeString ], |
373 result = collections[ shortcodeString ], |
224 attrs, args, query, others; |
374 attrs, args, query, others, self = this; |
225 |
375 |
226 delete galleries[ shortcodeString ]; |
376 delete collections[ shortcodeString ]; |
227 |
377 if ( result ) { |
228 if ( result ) |
|
229 return result; |
378 return result; |
230 |
379 } |
231 // Fill the default shortcode attributes. |
380 // Fill the default shortcode attributes. |
232 attrs = _.defaults( shortcode.attrs.named, wp.media.gallery.defaults ); |
381 attrs = _.defaults( shortcode.attrs.named, this.defaults ); |
233 args = _.pick( attrs, 'orderby', 'order' ); |
382 args = _.pick( attrs, 'orderby', 'order' ); |
234 |
383 |
235 args.type = 'image'; |
384 args.type = this.type; |
236 args.perPage = -1; |
385 args.perPage = -1; |
237 |
386 |
238 // Mark the `orderby` override attribute. |
387 // Mark the `orderby` override attribute. |
239 if( undefined !== attrs.orderby ) |
388 if ( undefined !== attrs.orderby ) { |
240 attrs._orderByField = attrs.orderby; |
389 attrs._orderByField = attrs.orderby; |
241 |
390 } |
242 if ( 'rand' === attrs.orderby ) |
391 |
|
392 if ( 'rand' === attrs.orderby ) { |
243 attrs._orderbyRandom = true; |
393 attrs._orderbyRandom = true; |
|
394 } |
244 |
395 |
245 // Map the `orderby` attribute to the corresponding model property. |
396 // Map the `orderby` attribute to the corresponding model property. |
246 if ( ! attrs.orderby || /^menu_order(?: ID)?$/i.test( attrs.orderby ) ) |
397 if ( ! attrs.orderby || /^menu_order(?: ID)?$/i.test( attrs.orderby ) ) { |
247 args.orderby = 'menuOrder'; |
398 args.orderby = 'menuOrder'; |
|
399 } |
248 |
400 |
249 // Map the `ids` param to the correct query args. |
401 // Map the `ids` param to the correct query args. |
250 if ( attrs.ids ) { |
402 if ( attrs.ids ) { |
251 args.post__in = attrs.ids.split(','); |
403 args.post__in = attrs.ids.split(','); |
252 args.orderby = 'post__in'; |
404 args.orderby = 'post__in'; |
253 } else if ( attrs.include ) { |
405 } else if ( attrs.include ) { |
254 args.post__in = attrs.include.split(','); |
406 args.post__in = attrs.include.split(','); |
255 } |
407 } |
256 |
408 |
257 if ( attrs.exclude ) |
409 if ( attrs.exclude ) { |
258 args.post__not_in = attrs.exclude.split(','); |
410 args.post__not_in = attrs.exclude.split(','); |
259 |
411 } |
260 if ( ! args.post__in ) |
412 |
|
413 if ( ! args.post__in ) { |
261 args.uploadedTo = attrs.id; |
414 args.uploadedTo = attrs.id; |
|
415 } |
262 |
416 |
263 // Collect the attributes that were not included in `args`. |
417 // Collect the attributes that were not included in `args`. |
264 others = _.omit( attrs, 'id', 'ids', 'include', 'exclude', 'orderby', 'order' ); |
418 others = _.omit( attrs, 'id', 'ids', 'include', 'exclude', 'orderby', 'order' ); |
265 |
419 |
|
420 _.each( this.defaults, function( value, key ) { |
|
421 others[ key ] = self.coerce( others, key ); |
|
422 }); |
|
423 |
266 query = wp.media.query( args ); |
424 query = wp.media.query( args ); |
267 query.gallery = new Backbone.Model( others ); |
425 query[ this.tag ] = new Backbone.Model( others ); |
268 return query; |
426 return query; |
269 }, |
427 }, |
270 |
428 /** |
|
429 * Triggered when clicking 'Insert {label}' or 'Update {label}' |
|
430 * |
|
431 * @global wp.shortcode |
|
432 * @global wp.media.model.Attachments |
|
433 * |
|
434 * @param {wp.media.model.Attachments} attachments A Backbone.Collection containing |
|
435 * the media items belonging to a collection. |
|
436 * The query[ this.tag ] property is a Backbone.Model |
|
437 * containing the 'props' for the collection. |
|
438 * @returns {wp.shortcode} |
|
439 */ |
271 shortcode: function( attachments ) { |
440 shortcode: function( attachments ) { |
272 var props = attachments.props.toJSON(), |
441 var props = attachments.props.toJSON(), |
273 attrs = _.pick( props, 'orderby', 'order' ), |
442 attrs = _.pick( props, 'orderby', 'order' ), |
274 shortcode, clone; |
443 shortcode, clone; |
275 |
444 |
276 if ( attachments.gallery ) |
445 if ( attachments.type ) { |
277 _.extend( attrs, attachments.gallery.toJSON() ); |
446 attrs.type = attachments.type; |
|
447 delete attachments.type; |
|
448 } |
|
449 |
|
450 if ( attachments[this.tag] ) { |
|
451 _.extend( attrs, attachments[this.tag].toJSON() ); |
|
452 } |
278 |
453 |
279 // Convert all gallery shortcodes to use the `ids` property. |
454 // Convert all gallery shortcodes to use the `ids` property. |
280 // Ignore `post__in` and `post__not_in`; the attachments in |
455 // Ignore `post__in` and `post__not_in`; the attachments in |
281 // the collection will already reflect those properties. |
456 // the collection will already reflect those properties. |
282 attrs.ids = attachments.pluck('id'); |
457 attrs.ids = attachments.pluck('id'); |
283 |
458 |
284 // Copy the `uploadedTo` post ID. |
459 // Copy the `uploadedTo` post ID. |
285 if ( props.uploadedTo ) |
460 if ( props.uploadedTo ) { |
286 attrs.id = props.uploadedTo; |
461 attrs.id = props.uploadedTo; |
287 |
462 } |
288 // Check if the gallery is randomly ordered. |
463 // Check if the gallery is randomly ordered. |
289 delete attrs.orderby; |
464 delete attrs.orderby; |
290 |
465 |
291 if ( attrs._orderbyRandom ) |
466 if ( attrs._orderbyRandom ) { |
292 attrs.orderby = 'rand'; |
467 attrs.orderby = 'rand'; |
293 else if ( attrs._orderByField && attrs._orderByField != 'rand' ) |
468 } else if ( attrs._orderByField && attrs._orderByField != 'rand' ) { |
294 attrs.orderby = attrs._orderByField; |
469 attrs.orderby = attrs._orderByField; |
|
470 } |
295 |
471 |
296 delete attrs._orderbyRandom; |
472 delete attrs._orderbyRandom; |
297 delete attrs._orderByField; |
473 delete attrs._orderByField; |
298 |
474 |
299 // If the `ids` attribute is set and `orderby` attribute |
475 // If the `ids` attribute is set and `orderby` attribute |
300 // is the default value, clear it for cleaner output. |
476 // is the default value, clear it for cleaner output. |
301 if ( attrs.ids && 'post__in' === attrs.orderby ) |
477 if ( attrs.ids && 'post__in' === attrs.orderby ) { |
302 delete attrs.orderby; |
478 delete attrs.orderby; |
303 |
479 } |
304 // Remove default attributes from the shortcode. |
480 |
305 _.each( wp.media.gallery.defaults, function( value, key ) { |
481 attrs = this.setDefaults( attrs ); |
306 if ( value === attrs[ key ] ) |
|
307 delete attrs[ key ]; |
|
308 }); |
|
309 |
482 |
310 shortcode = new wp.shortcode({ |
483 shortcode = new wp.shortcode({ |
311 tag: 'gallery', |
484 tag: this.tag, |
312 attrs: attrs, |
485 attrs: attrs, |
313 type: 'single' |
486 type: 'single' |
314 }); |
487 }); |
315 |
488 |
316 // Use a cloned version of the gallery. |
489 // Use a cloned version of the gallery. |
317 clone = new wp.media.model.Attachments( attachments.models, { |
490 clone = new wp.media.model.Attachments( attachments.models, { |
318 props: props |
491 props: props |
319 }); |
492 }); |
320 clone.gallery = attachments.gallery; |
493 clone[ this.tag ] = attachments[ this.tag ]; |
321 galleries[ shortcode.string() ] = clone; |
494 collections[ shortcode.string() ] = clone; |
322 |
495 |
323 return shortcode; |
496 return shortcode; |
324 }, |
497 }, |
325 |
498 /** |
|
499 * Triggered when double-clicking a collection shortcode placeholder |
|
500 * in the editor |
|
501 * |
|
502 * @global wp.shortcode |
|
503 * @global wp.media.model.Selection |
|
504 * @global wp.media.view.l10n |
|
505 * |
|
506 * @param {string} content Content that is searched for possible |
|
507 * shortcode markup matching the passed tag name, |
|
508 * |
|
509 * @this wp.media.{prop} |
|
510 * |
|
511 * @returns {wp.media.view.MediaFrame.Select} A media workflow. |
|
512 */ |
326 edit: function( content ) { |
513 edit: function( content ) { |
327 var shortcode = wp.shortcode.next( 'gallery', content ), |
514 var shortcode = wp.shortcode.next( this.tag, content ), |
328 defaultPostId = wp.media.gallery.defaults.id, |
515 defaultPostId = this.defaults.id, |
329 attachments, selection; |
516 attachments, selection, state; |
330 |
517 |
331 // Bail if we didn't match the shortcode or all of the content. |
518 // Bail if we didn't match the shortcode or all of the content. |
332 if ( ! shortcode || shortcode.content !== content ) |
519 if ( ! shortcode || shortcode.content !== content ) { |
333 return; |
520 return; |
|
521 } |
334 |
522 |
335 // Ignore the rest of the match object. |
523 // Ignore the rest of the match object. |
336 shortcode = shortcode.shortcode; |
524 shortcode = shortcode.shortcode; |
337 |
525 |
338 if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) |
526 if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) ) { |
339 shortcode.set( 'id', defaultPostId ); |
527 shortcode.set( 'id', defaultPostId ); |
340 |
528 } |
341 attachments = wp.media.gallery.attachments( shortcode ); |
529 |
|
530 attachments = this.attachments( shortcode ); |
342 |
531 |
343 selection = new wp.media.model.Selection( attachments.models, { |
532 selection = new wp.media.model.Selection( attachments.models, { |
344 props: attachments.props.toJSON(), |
533 props: attachments.props.toJSON(), |
345 multiple: true |
534 multiple: true |
346 }); |
535 }); |
347 |
536 |
348 selection.gallery = attachments.gallery; |
537 selection[ this.tag ] = attachments[ this.tag ]; |
349 |
538 |
350 // Fetch the query's attachments, and then break ties from the |
539 // Fetch the query's attachments, and then break ties from the |
351 // query to allow for sorting. |
540 // query to allow for sorting. |
352 selection.more().done( function() { |
541 selection.more().done( function() { |
353 // Break ties with the query. |
542 // Break ties with the query. |
355 selection.unmirror(); |
544 selection.unmirror(); |
356 selection.props.unset('orderby'); |
545 selection.props.unset('orderby'); |
357 }); |
546 }); |
358 |
547 |
359 // Destroy the previous gallery frame. |
548 // Destroy the previous gallery frame. |
360 if ( this.frame ) |
549 if ( this.frame ) { |
361 this.frame.dispose(); |
550 this.frame.dispose(); |
362 |
551 } |
363 // Store the current gallery frame. |
552 |
|
553 if ( shortcode.attrs.named.type && 'video' === shortcode.attrs.named.type ) { |
|
554 state = 'video-' + this.tag + '-edit'; |
|
555 } else { |
|
556 state = this.tag + '-edit'; |
|
557 } |
|
558 |
|
559 // Store the current frame. |
364 this.frame = wp.media({ |
560 this.frame = wp.media({ |
365 frame: 'post', |
561 frame: 'post', |
366 state: 'gallery-edit', |
562 state: state, |
367 title: wp.media.view.l10n.editGalleryTitle, |
563 title: this.editTitle, |
368 editing: true, |
564 editing: true, |
369 multiple: true, |
565 multiple: true, |
370 selection: selection |
566 selection: selection |
371 }).open(); |
567 }).open(); |
372 |
568 |
373 return this.frame; |
569 return this.frame; |
374 } |
570 }, |
375 }; |
571 |
376 }()); |
572 setDefaults: function( attrs ) { |
377 |
573 var self = this; |
|
574 // Remove default attributes from the shortcode. |
|
575 _.each( this.defaults, function( value, key ) { |
|
576 attrs[ key ] = self.coerce( attrs, key ); |
|
577 if ( value === attrs[ key ] ) { |
|
578 delete attrs[ key ]; |
|
579 } |
|
580 }); |
|
581 |
|
582 return attrs; |
|
583 } |
|
584 }, attributes ); |
|
585 }; |
|
586 |
|
587 wp.media._galleryDefaults = { |
|
588 itemtag: 'dl', |
|
589 icontag: 'dt', |
|
590 captiontag: 'dd', |
|
591 columns: '3', |
|
592 link: 'post', |
|
593 size: 'thumbnail', |
|
594 order: 'ASC', |
|
595 id: wp.media.view.settings.post && wp.media.view.settings.post.id, |
|
596 orderby : 'menu_order ID' |
|
597 }; |
|
598 |
|
599 if ( wp.media.view.settings.galleryDefaults ) { |
|
600 wp.media.galleryDefaults = _.extend( {}, wp.media._galleryDefaults, wp.media.view.settings.galleryDefaults ); |
|
601 } else { |
|
602 wp.media.galleryDefaults = wp.media._galleryDefaults; |
|
603 } |
|
604 |
|
605 wp.media.gallery = new wp.media.collection({ |
|
606 tag: 'gallery', |
|
607 type : 'image', |
|
608 editTitle : wp.media.view.l10n.editGalleryTitle, |
|
609 defaults : wp.media.galleryDefaults, |
|
610 |
|
611 setDefaults: function( attrs ) { |
|
612 var self = this, changed = ! _.isEqual( wp.media.galleryDefaults, wp.media._galleryDefaults ); |
|
613 _.each( this.defaults, function( value, key ) { |
|
614 attrs[ key ] = self.coerce( attrs, key ); |
|
615 if ( value === attrs[ key ] && ( ! changed || value === wp.media._galleryDefaults[ key ] ) ) { |
|
616 delete attrs[ key ]; |
|
617 } |
|
618 } ); |
|
619 return attrs; |
|
620 } |
|
621 }); |
|
622 |
|
623 /** |
|
624 * wp.media.featuredImage |
|
625 * @namespace |
|
626 */ |
378 wp.media.featuredImage = { |
627 wp.media.featuredImage = { |
|
628 /** |
|
629 * Get the featured image post ID |
|
630 * |
|
631 * @global wp.media.view.settings |
|
632 * |
|
633 * @returns {wp.media.view.settings.post.featuredImageId|number} |
|
634 */ |
379 get: function() { |
635 get: function() { |
380 return wp.media.view.settings.post.featuredImageId; |
636 return wp.media.view.settings.post.featuredImageId; |
381 }, |
637 }, |
382 |
638 /** |
|
639 * Set the featured image id, save the post thumbnail data and |
|
640 * set the HTML in the post meta box to the new featured image. |
|
641 * |
|
642 * @global wp.media.view.settings |
|
643 * @global wp.media.post |
|
644 * |
|
645 * @param {number} id The post ID of the featured image, or -1 to unset it. |
|
646 */ |
383 set: function( id ) { |
647 set: function( id ) { |
384 var settings = wp.media.view.settings; |
648 var settings = wp.media.view.settings; |
385 |
649 |
386 settings.post.featuredImageId = id; |
650 settings.post.featuredImageId = id; |
387 |
651 |
392 _wpnonce: settings.post.nonce |
656 _wpnonce: settings.post.nonce |
393 }).done( function( html ) { |
657 }).done( function( html ) { |
394 $( '.inside', '#postimagediv' ).html( html ); |
658 $( '.inside', '#postimagediv' ).html( html ); |
395 }); |
659 }); |
396 }, |
660 }, |
397 |
661 /** |
|
662 * The Featured Image workflow |
|
663 * |
|
664 * @global wp.media.controller.FeaturedImage |
|
665 * @global wp.media.view.l10n |
|
666 * |
|
667 * @this wp.media.featuredImage |
|
668 * |
|
669 * @returns {wp.media.view.MediaFrame.Select} A media workflow. |
|
670 */ |
398 frame: function() { |
671 frame: function() { |
399 if ( this._frame ) |
672 if ( this._frame ) { |
400 return this._frame; |
673 return this._frame; |
|
674 } |
401 |
675 |
402 this._frame = wp.media({ |
676 this._frame = wp.media({ |
403 state: 'featured-image', |
677 state: 'featured-image', |
404 states: [ new wp.media.controller.FeaturedImage() ] |
678 states: [ new wp.media.controller.FeaturedImage() , new wp.media.controller.EditImage() ] |
405 }); |
679 }); |
406 |
680 |
407 this._frame.on( 'toolbar:create:featured-image', function( toolbar ) { |
681 this._frame.on( 'toolbar:create:featured-image', function( toolbar ) { |
|
682 /** |
|
683 * @this wp.media.view.MediaFrame.Select |
|
684 */ |
408 this.createSelectToolbar( toolbar, { |
685 this.createSelectToolbar( toolbar, { |
409 text: wp.media.view.l10n.setFeaturedImage |
686 text: wp.media.view.l10n.setFeaturedImage |
410 }); |
687 }); |
411 }, this._frame ); |
688 }, this._frame ); |
412 |
689 |
|
690 this._frame.on( 'content:render:edit-image', function() { |
|
691 var selection = this.state('featured-image').get('selection'), |
|
692 view = new wp.media.view.EditImage( { model: selection.single(), controller: this } ).render(); |
|
693 |
|
694 this.content.set( view ); |
|
695 |
|
696 // after bringing in the frame, load the actual editor via an ajax call |
|
697 view.loadEditor(); |
|
698 |
|
699 }, this._frame ); |
|
700 |
413 this._frame.state('featured-image').on( 'select', this.select ); |
701 this._frame.state('featured-image').on( 'select', this.select ); |
414 return this._frame; |
702 return this._frame; |
415 }, |
703 }, |
416 |
704 /** |
|
705 * 'select' callback for Featured Image workflow, triggered when |
|
706 * the 'Set Featured Image' button is clicked in the media modal. |
|
707 * |
|
708 * @global wp.media.view.settings |
|
709 * |
|
710 * @this wp.media.controller.FeaturedImage |
|
711 */ |
417 select: function() { |
712 select: function() { |
418 var settings = wp.media.view.settings, |
713 var selection = this.get('selection').single(); |
419 selection = this.get('selection').single(); |
714 |
420 |
715 if ( ! wp.media.view.settings.post.featuredImageId ) { |
421 if ( ! settings.post.featuredImageId ) |
|
422 return; |
716 return; |
|
717 } |
423 |
718 |
424 wp.media.featuredImage.set( selection ? selection.id : -1 ); |
719 wp.media.featuredImage.set( selection ? selection.id : -1 ); |
425 }, |
720 }, |
426 |
721 /** |
|
722 * Open the content media manager to the 'featured image' tab when |
|
723 * the post thumbnail is clicked. |
|
724 * |
|
725 * Update the featured image id when the 'remove' link is clicked. |
|
726 * |
|
727 * @global wp.media.view.settings |
|
728 */ |
427 init: function() { |
729 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 ) { |
730 $('#postimagediv').on( 'click', '#set-post-thumbnail', function( event ) { |
431 event.preventDefault(); |
731 event.preventDefault(); |
432 // Stop propagation to prevent thickbox from activating. |
732 // Stop propagation to prevent thickbox from activating. |
433 event.stopPropagation(); |
733 event.stopPropagation(); |
434 |
734 |
435 wp.media.featuredImage.frame().open(); |
735 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() { |
736 }).on( 'click', '#remove-post-thumbnail', function() { |
439 wp.media.view.settings.post.featuredImageId = -1; |
737 wp.media.view.settings.post.featuredImageId = -1; |
440 }); |
738 }); |
441 } |
739 } |
442 }; |
740 }; |
443 |
741 |
444 $( wp.media.featuredImage.init ); |
742 $( wp.media.featuredImage.init ); |
445 |
743 |
|
744 /** |
|
745 * wp.media.editor |
|
746 * @namespace |
|
747 */ |
446 wp.media.editor = { |
748 wp.media.editor = { |
447 insert: function( h ) { |
749 /** |
448 var mce = typeof(tinymce) != 'undefined', |
750 * Send content to the editor |
449 qt = typeof(QTags) != 'undefined', |
751 * |
450 wpActiveEditor = window.wpActiveEditor, |
752 * @global tinymce |
451 ed; |
753 * @global QTags |
|
754 * @global wpActiveEditor |
|
755 * @global tb_remove() - Possibly overloaded by legacy plugins |
|
756 * |
|
757 * @param {string} html Content to send to the editor |
|
758 */ |
|
759 insert: function( html ) { |
|
760 var editor, wpActiveEditor, |
|
761 hasTinymce = ! _.isUndefined( window.tinymce ), |
|
762 hasQuicktags = ! _.isUndefined( window.QTags ); |
|
763 |
|
764 if ( this.activeEditor ) { |
|
765 wpActiveEditor = window.wpActiveEditor = this.activeEditor; |
|
766 } else { |
|
767 wpActiveEditor = window.wpActiveEditor; |
|
768 } |
452 |
769 |
453 // Delegate to the global `send_to_editor` if it exists. |
770 // Delegate to the global `send_to_editor` if it exists. |
454 // This attempts to play nice with any themes/plugins that have |
771 // This attempts to play nice with any themes/plugins that have |
455 // overridden the insert functionality. |
772 // overridden the insert functionality. |
456 if ( window.send_to_editor ) |
773 if ( window.send_to_editor ) { |
457 return window.send_to_editor.apply( this, arguments ); |
774 return window.send_to_editor.apply( this, arguments ); |
|
775 } |
458 |
776 |
459 if ( ! wpActiveEditor ) { |
777 if ( ! wpActiveEditor ) { |
460 if ( mce && tinymce.activeEditor ) { |
778 if ( hasTinymce && tinymce.activeEditor ) { |
461 ed = tinymce.activeEditor; |
779 editor = tinymce.activeEditor; |
462 wpActiveEditor = window.wpActiveEditor = ed.id; |
780 wpActiveEditor = window.wpActiveEditor = editor.id; |
463 } else if ( !qt ) { |
781 } else if ( ! hasQuicktags ) { |
464 return false; |
782 return false; |
465 } |
783 } |
466 } else if ( mce ) { |
784 } else if ( hasTinymce ) { |
467 if ( tinymce.activeEditor && (tinymce.activeEditor.id == 'mce_fullscreen' || tinymce.activeEditor.id == 'wp_mce_fullscreen') ) |
785 editor = tinymce.get( wpActiveEditor ); |
468 ed = tinymce.activeEditor; |
786 } |
469 else |
787 |
470 ed = tinymce.get(wpActiveEditor); |
788 if ( editor && ! editor.isHidden() ) { |
471 } |
789 editor.execCommand( 'mceInsertContent', false, html ); |
472 |
790 } else if ( hasQuicktags ) { |
473 if ( ed && !ed.isHidden() ) { |
791 QTags.insertContent( html ); |
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 { |
792 } else { |
493 document.getElementById(wpActiveEditor).value += h; |
793 document.getElementById( wpActiveEditor ).value += html; |
494 } |
794 } |
495 |
795 |
496 // If the old thickbox remove function exists, call it in case |
796 // If the old thickbox remove function exists, call it in case |
497 // a theme/plugin overloaded it. |
797 // a theme/plugin overloaded it. |
498 if ( window.tb_remove ) |
798 if ( window.tb_remove ) { |
499 try { window.tb_remove(); } catch( e ) {} |
799 try { window.tb_remove(); } catch( e ) {} |
500 }, |
800 } |
501 |
801 }, |
|
802 |
|
803 /** |
|
804 * Setup 'workflow' and add to the 'workflows' cache. 'open' can |
|
805 * subsequently be called upon it. |
|
806 * |
|
807 * @global wp.media.view.l10n |
|
808 * |
|
809 * @param {string} id A slug used to identify the workflow. |
|
810 * @param {Object} [options={}] |
|
811 * |
|
812 * @this wp.media.editor |
|
813 * |
|
814 * @returns {wp.media.view.MediaFrame.Select} A media workflow. |
|
815 */ |
502 add: function( id, options ) { |
816 add: function( id, options ) { |
503 var workflow = this.get( id ); |
817 var workflow = this.get( id ); |
504 |
818 |
505 if ( workflow ) // only add once: if exists return existing |
819 // only add once: if exists return existing |
|
820 if ( workflow ) { |
506 return workflow; |
821 return workflow; |
|
822 } |
507 |
823 |
508 workflow = workflows[ id ] = wp.media( _.defaults( options || {}, { |
824 workflow = workflows[ id ] = wp.media( _.defaults( options || {}, { |
509 frame: 'post', |
825 frame: 'post', |
510 state: 'insert', |
826 state: 'insert', |
511 title: wp.media.view.l10n.addMedia, |
827 title: wp.media.view.l10n.addMedia, |
555 linkUrl: '', |
894 linkUrl: '', |
556 align: 'none', |
895 align: 'none', |
557 link: 'none' |
896 link: 'none' |
558 }); |
897 }); |
559 |
898 |
560 if ( 'none' === embed.link ) |
899 if ( 'none' === embed.link ) { |
561 embed.linkUrl = ''; |
900 embed.linkUrl = ''; |
562 else if ( 'file' === embed.link ) |
901 } else if ( 'file' === embed.link ) { |
563 embed.linkUrl = embed.url; |
902 embed.linkUrl = embed.url; |
|
903 } |
564 |
904 |
565 this.insert( wp.media.string.image( embed ) ); |
905 this.insert( wp.media.string.image( embed ) ); |
566 } |
906 } |
567 }, this ); |
907 }, this ); |
568 |
908 |
569 workflow.state('featured-image').on( 'select', wp.media.featuredImage.select ); |
909 workflow.state('featured-image').on( 'select', wp.media.featuredImage.select ); |
570 workflow.setState( workflow.options.state ); |
910 workflow.setState( workflow.options.state ); |
571 return workflow; |
911 return workflow; |
572 }, |
912 }, |
573 |
913 /** |
|
914 * Determines the proper current workflow id |
|
915 * |
|
916 * @global wpActiveEditor |
|
917 * @global tinymce |
|
918 * |
|
919 * @param {string} [id=''] A slug used to identify the workflow. |
|
920 * |
|
921 * @returns {wpActiveEditor|string|tinymce.activeEditor.id} |
|
922 */ |
574 id: function( id ) { |
923 id: function( id ) { |
575 if ( id ) |
924 if ( id ) { |
576 return id; |
925 return id; |
|
926 } |
577 |
927 |
578 // If an empty `id` is provided, default to `wpActiveEditor`. |
928 // If an empty `id` is provided, default to `wpActiveEditor`. |
579 id = wpActiveEditor; |
929 id = window.wpActiveEditor; |
580 |
930 |
581 // If that doesn't work, fall back to `tinymce.activeEditor.id`. |
931 // If that doesn't work, fall back to `tinymce.activeEditor.id`. |
582 if ( ! id && typeof tinymce !== 'undefined' && tinymce.activeEditor ) |
932 if ( ! id && ! _.isUndefined( window.tinymce ) && tinymce.activeEditor ) { |
583 id = tinymce.activeEditor.id; |
933 id = tinymce.activeEditor.id; |
|
934 } |
584 |
935 |
585 // Last but not least, fall back to the empty string. |
936 // Last but not least, fall back to the empty string. |
586 id = id || ''; |
937 id = id || ''; |
587 return id; |
938 return id; |
588 }, |
939 }, |
589 |
940 /** |
|
941 * Return the workflow specified by id |
|
942 * |
|
943 * @param {string} id A slug used to identify the workflow. |
|
944 * |
|
945 * @this wp.media.editor |
|
946 * |
|
947 * @returns {wp.media.view.MediaFrame} A media workflow. |
|
948 */ |
590 get: function( id ) { |
949 get: function( id ) { |
591 id = this.id( id ); |
950 id = this.id( id ); |
592 return workflows[ id ]; |
951 return workflows[ id ]; |
593 }, |
952 }, |
594 |
953 /** |
|
954 * Remove the workflow represented by id from the workflow cache |
|
955 * |
|
956 * @param {string} id A slug used to identify the workflow. |
|
957 * |
|
958 * @this wp.media.editor |
|
959 */ |
595 remove: function( id ) { |
960 remove: function( id ) { |
596 id = this.id( id ); |
961 id = this.id( id ); |
597 delete workflows[ id ]; |
962 delete workflows[ id ]; |
598 }, |
963 }, |
599 |
964 /** |
|
965 * @namespace |
|
966 */ |
600 send: { |
967 send: { |
|
968 /** |
|
969 * Called when sending an attachment to the editor |
|
970 * from the medial modal. |
|
971 * |
|
972 * @global wp.media.view.settings |
|
973 * @global wp.media.post |
|
974 * |
|
975 * @param {Object} props Attachment details (align, link, size, etc). |
|
976 * @param {Object} attachment The attachment object, media version of Post. |
|
977 * @returns {Promise} |
|
978 */ |
601 attachment: function( props, attachment ) { |
979 attachment: function( props, attachment ) { |
602 var caption = attachment.caption, |
980 var caption = attachment.caption, |
603 options, html; |
981 options, html; |
604 |
982 |
605 // If captions are disabled, clear the caption. |
983 // If captions are disabled, clear the caption. |
606 if ( ! wp.media.view.settings.captions ) |
984 if ( ! wp.media.view.settings.captions ) { |
607 delete attachment.caption; |
985 delete attachment.caption; |
|
986 } |
608 |
987 |
609 props = wp.media.string.props( props, attachment ); |
988 props = wp.media.string.props( props, attachment ); |
610 |
989 |
611 options = { |
990 options = { |
612 id: attachment.id, |
991 id: attachment.id, |
613 post_content: attachment.description, |
992 post_content: attachment.description, |
614 post_excerpt: caption |
993 post_excerpt: caption |
615 }; |
994 }; |
616 |
995 |
617 if ( props.linkUrl ) |
996 if ( props.linkUrl ) { |
618 options.url = props.linkUrl; |
997 options.url = props.linkUrl; |
|
998 } |
619 |
999 |
620 if ( 'image' === attachment.type ) { |
1000 if ( 'image' === attachment.type ) { |
621 html = wp.media.string.image( props ); |
1001 html = wp.media.string.image( props ); |
622 |
1002 |
623 _.each({ |
1003 _.each({ |
642 attachment: options, |
1022 attachment: options, |
643 html: html, |
1023 html: html, |
644 post_id: wp.media.view.settings.post.id |
1024 post_id: wp.media.view.settings.post.id |
645 }); |
1025 }); |
646 }, |
1026 }, |
647 |
1027 /** |
|
1028 * Called when 'Insert From URL' source is not an image. Example: YouTube url. |
|
1029 * |
|
1030 * @global wp.media.view.settings |
|
1031 * |
|
1032 * @param {Object} embed |
|
1033 * @returns {Promise} |
|
1034 */ |
648 link: function( embed ) { |
1035 link: function( embed ) { |
649 return wp.media.post( 'send-link-to-editor', { |
1036 return wp.media.post( 'send-link-to-editor', { |
650 nonce: wp.media.view.settings.nonce.sendToEditor, |
1037 nonce: wp.media.view.settings.nonce.sendToEditor, |
651 src: embed.linkUrl, |
1038 src: embed.linkUrl, |
652 title: embed.title, |
1039 link_text: embed.linkText, |
653 html: wp.media.string.link( embed ), |
1040 html: wp.media.string.link( embed ), |
654 post_id: wp.media.view.settings.post.id |
1041 post_id: wp.media.view.settings.post.id |
655 }); |
1042 }); |
656 } |
1043 } |
657 }, |
1044 }, |
658 |
1045 /** |
|
1046 * Open a workflow |
|
1047 * |
|
1048 * @param {string} [id=undefined] Optional. A slug used to identify the workflow. |
|
1049 * @param {Object} [options={}] |
|
1050 * |
|
1051 * @this wp.media.editor |
|
1052 * |
|
1053 * @returns {wp.media.view.MediaFrame} |
|
1054 */ |
659 open: function( id, options ) { |
1055 open: function( id, options ) { |
660 var workflow, editor; |
1056 var workflow; |
661 |
1057 |
662 options = options || {}; |
1058 options = options || {}; |
663 |
1059 |
664 id = this.id( id ); |
1060 id = this.id( id ); |
665 |
1061 this.activeEditor = id; |
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 |
1062 |
676 workflow = this.get( id ); |
1063 workflow = this.get( id ); |
677 |
1064 |
678 // Redo workflow if state has changed |
1065 // Redo workflow if state has changed |
679 if ( ! workflow || ( workflow.options && options.state !== workflow.options.state ) ) |
1066 if ( ! workflow || ( workflow.options && options.state !== workflow.options.state ) ) { |
680 workflow = this.add( id, options ); |
1067 workflow = this.add( id, options ); |
|
1068 } |
681 |
1069 |
682 return workflow.open(); |
1070 return workflow.open(); |
683 }, |
1071 }, |
684 |
1072 |
|
1073 /** |
|
1074 * Bind click event for .insert-media using event delegation |
|
1075 * |
|
1076 * @global wp.media.view.l10n |
|
1077 */ |
685 init: function() { |
1078 init: function() { |
686 $(document.body).on( 'click', '.insert-media', function( event ) { |
1079 $(document.body) |
687 var $this = $(this), |
1080 .on( 'click.add-media-button', '.insert-media', function( event ) { |
688 editor = $this.data('editor'), |
1081 var elem = $( event.currentTarget ), |
689 options = { |
1082 editor = elem.data('editor'), |
690 frame: 'post', |
1083 options = { |
691 state: 'insert', |
1084 frame: 'post', |
692 title: wp.media.view.l10n.addMedia, |
1085 state: 'insert', |
693 multiple: true |
1086 title: wp.media.view.l10n.addMedia, |
694 }; |
1087 multiple: true |
695 |
1088 }; |
696 event.preventDefault(); |
1089 |
697 |
1090 event.preventDefault(); |
698 // Remove focus from the `.insert-media` button. |
1091 |
699 // Prevents Opera from showing the outline of the button |
1092 // Remove focus from the `.insert-media` button. |
700 // above the modal. |
1093 // Prevents Opera from showing the outline of the button |
701 // |
1094 // above the modal. |
702 // See: http://core.trac.wordpress.org/ticket/22445 |
1095 // |
703 $this.blur(); |
1096 // See: https://core.trac.wordpress.org/ticket/22445 |
704 |
1097 elem.blur(); |
705 if ( $this.hasClass( 'gallery' ) ) { |
1098 |
706 options.state = 'gallery'; |
1099 if ( elem.hasClass( 'gallery' ) ) { |
707 options.title = wp.media.view.l10n.createGalleryTitle; |
1100 options.state = 'gallery'; |
708 } |
1101 options.title = wp.media.view.l10n.createGalleryTitle; |
709 |
1102 } |
710 wp.media.editor.open( editor, options ); |
1103 |
711 }); |
1104 wp.media.editor.open( editor, options ); |
|
1105 }); |
|
1106 |
|
1107 // Initialize and render the Editor drag-and-drop uploader. |
|
1108 new wp.media.view.EditorUploader().render(); |
712 } |
1109 } |
713 }; |
1110 }; |
714 |
1111 |
715 _.bindAll( wp.media.editor, 'open' ); |
1112 _.bindAll( wp.media.editor, 'open' ); |
716 $( wp.media.editor.init ); |
1113 $( wp.media.editor.init ); |
717 }(jQuery)); |
1114 }(jQuery, _)); |