Diff: STRATO-apps/wordpress_03/app/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
/* global tinymce */
2
+
tinymce.PluginManager.add( 'wpeditimage', function( editor ) {
3
+
var toolbar, serializer, touchOnImage, pasteInCaption,
4
+
each = tinymce.each,
5
+
trim = tinymce.trim,
6
+
iOS = tinymce.Env.iOS;
7
+
8
+
function isPlaceholder( node ) {
9
+
return !! ( editor.dom.getAttrib( node, 'data-mce-placeholder' ) || editor.dom.getAttrib( node, 'data-mce-object' ) );
10
+
}
11
+
12
+
editor.addButton( 'wp_img_remove', {
13
+
tooltip: 'Remove',
14
+
icon: 'dashicon dashicons-no',
15
+
onclick: function() {
16
+
removeImage( editor.selection.getNode() );
17
+
}
18
+
} );
19
+
20
+
editor.addButton( 'wp_img_edit', {
21
+
tooltip: 'Edit|button', // '|button' is not displayed, only used for context.
22
+
icon: 'dashicon dashicons-edit',
23
+
onclick: function() {
24
+
editImage( editor.selection.getNode() );
25
+
}
26
+
} );
27
+
28
+
each( {
29
+
alignleft: 'Align left',
30
+
aligncenter: 'Align center',
31
+
alignright: 'Align right',
32
+
alignnone: 'No alignment'
33
+
}, function( tooltip, name ) {
34
+
var direction = name.slice( 5 );
35
+
36
+
editor.addButton( 'wp_img_' + name, {
37
+
tooltip: tooltip,
38
+
icon: 'dashicon dashicons-align-' + direction,
39
+
cmd: 'alignnone' === name ? 'wpAlignNone' : 'Justify' + direction.slice( 0, 1 ).toUpperCase() + direction.slice( 1 ),
40
+
onPostRender: function() {
41
+
var self = this;
42
+
43
+
editor.on( 'NodeChange', function( event ) {
44
+
var node;
45
+
46
+
// Don't bother.
47
+
if ( event.element.nodeName !== 'IMG' ) {
48
+
return;
49
+
}
50
+
51
+
node = editor.dom.getParent( event.element, '.wp-caption' ) || event.element;
52
+
53
+
if ( 'alignnone' === name ) {
54
+
self.active( ! /\balign(left|center|right)\b/.test( node.className ) );
55
+
} else {
56
+
self.active( editor.dom.hasClass( node, name ) );
57
+
}
58
+
} );
59
+
}
60
+
} );
61
+
} );
62
+
63
+
editor.once( 'preinit', function() {
64
+
if ( editor.wp && editor.wp._createToolbar ) {
65
+
toolbar = editor.wp._createToolbar( [
66
+
'wp_img_alignleft',
67
+
'wp_img_aligncenter',
68
+
'wp_img_alignright',
69
+
'wp_img_alignnone',
70
+
'wp_img_edit',
71
+
'wp_img_remove'
72
+
] );
73
+
}
74
+
} );
75
+
76
+
editor.on( 'wptoolbar', function( event ) {
77
+
if ( event.element.nodeName === 'IMG' && ! isPlaceholder( event.element ) ) {
78
+
event.toolbar = toolbar;
79
+
}
80
+
} );
81
+
82
+
function isNonEditable( node ) {
83
+
var parent = editor.$( node ).parents( '[contenteditable]' );
84
+
return parent && parent.attr( 'contenteditable' ) === 'false';
85
+
}
86
+
87
+
// Safari on iOS fails to select images in contentEditoble mode on touch.
88
+
// Select them again.
89
+
if ( iOS ) {
90
+
editor.on( 'init', function() {
91
+
editor.on( 'touchstart', function( event ) {
92
+
if ( event.target.nodeName === 'IMG' && ! isNonEditable( event.target ) ) {
93
+
touchOnImage = true;
94
+
}
95
+
});
96
+
97
+
editor.dom.bind( editor.getDoc(), 'touchmove', function() {
98
+
touchOnImage = false;
99
+
});
100
+
101
+
editor.on( 'touchend', function( event ) {
102
+
if ( touchOnImage && event.target.nodeName === 'IMG' && ! isNonEditable( event.target ) ) {
103
+
var node = event.target;
104
+
105
+
touchOnImage = false;
106
+
107
+
window.setTimeout( function() {
108
+
editor.selection.select( node );
109
+
editor.nodeChanged();
110
+
}, 100 );
111
+
} else if ( toolbar ) {
112
+
toolbar.hide();
113
+
}
114
+
});
115
+
});
116
+
}
117
+
118
+
function parseShortcode( content ) {
119
+
return content.replace( /(?:<p>)?\[(?:wp_)?caption([^\]]+)\]([\s\S]+?)\[\/(?:wp_)?caption\](?:<\/p>)?/g, function( a, b, c ) {
120
+
var id, align, classes, caption, img, width;
121
+
122
+
id = b.match( /id=['"]([^'"]*)['"] ?/ );
123
+
if ( id ) {
124
+
b = b.replace( id[0], '' );
125
+
}
126
+
127
+
align = b.match( /align=['"]([^'"]*)['"] ?/ );
128
+
if ( align ) {
129
+
b = b.replace( align[0], '' );
130
+
}
131
+
132
+
classes = b.match( /class=['"]([^'"]*)['"] ?/ );
133
+
if ( classes ) {
134
+
b = b.replace( classes[0], '' );
135
+
}
136
+
137
+
width = b.match( /width=['"]([0-9]*)['"] ?/ );
138
+
if ( width ) {
139
+
b = b.replace( width[0], '' );
140
+
}
141
+
142
+
c = trim( c );
143
+
img = c.match( /((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)([\s\S]*)/i );
144
+
145
+
if ( img && img[2] ) {
146
+
caption = trim( img[2] );
147
+
img = trim( img[1] );
148
+
} else {
149
+
// Old captions shortcode style.
150
+
caption = trim( b ).replace( /caption=['"]/, '' ).replace( /['"]$/, '' );
151
+
img = c;
152
+
}
153
+
154
+
id = ( id && id[1] ) ? id[1].replace( /[<>&]+/g, '' ) : '';
155
+
align = ( align && align[1] ) ? align[1] : 'alignnone';
156
+
classes = ( classes && classes[1] ) ? ' ' + classes[1].replace( /[<>&]+/g, '' ) : '';
157
+
158
+
if ( ! width && img ) {
159
+
width = img.match( /width=['"]([0-9]*)['"]/ );
160
+
}
161
+
162
+
if ( width && width[1] ) {
163
+
width = width[1];
164
+
}
165
+
166
+
if ( ! width || ! caption ) {
167
+
return c;
168
+
}
169
+
170
+
width = parseInt( width, 10 );
171
+
if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
172
+
width += 10;
173
+
}
174
+
175
+
return '<div class="mceTemp"><dl id="' + id + '" class="wp-caption ' + align + classes + '" style="width: ' + width + 'px">' +
176
+
'<dt class="wp-caption-dt">'+ img +'</dt><dd class="wp-caption-dd">'+ caption +'</dd></dl></div>';
177
+
});
178
+
}
179
+
180
+
function getShortcode( content ) {
181
+
return content.replace( /(?:<div [^>]+mceTemp[^>]+>)?\s*(<dl [^>]+wp-caption[^>]+>[\s\S]+?<\/dl>)\s*(?:<\/div>)?/g, function( all, dl ) {
182
+
var out = '';
183
+
184
+
if ( dl.indexOf('<img ') === -1 || dl.indexOf('</p>') !== -1 ) {
185
+
// Broken caption. The user managed to drag the image out or type in the wrapper div?
186
+
// Remove the <dl>, <dd> and <dt> and return the remaining text.
187
+
return dl.replace( /<d[ldt]( [^>]+)?>/g, '' ).replace( /<\/d[ldt]>/g, '' );
188
+
}
189
+
190
+
out = dl.replace( /\s*<dl ([^>]+)>\s*<dt [^>]+>([\s\S]+?)<\/dt>\s*<dd [^>]+>([\s\S]*?)<\/dd>\s*<\/dl>\s*/gi, function( a, b, c, caption ) {
191
+
var id, classes, align, width;
192
+
193
+
width = c.match( /width="([0-9]*)"/ );
194
+
width = ( width && width[1] ) ? width[1] : '';
195
+
196
+
classes = b.match( /class="([^"]*)"/ );
197
+
classes = ( classes && classes[1] ) ? classes[1] : '';
198
+
align = classes.match( /align[a-z]+/i ) || 'alignnone';
199
+
200
+
if ( ! width || ! caption ) {
201
+
if ( 'alignnone' !== align[0] ) {
202
+
c = c.replace( /><img/, ' class="' + align[0] + '"><img' );
203
+
}
204
+
return c;
205
+
}
206
+
207
+
id = b.match( /id="([^"]*)"/ );
208
+
id = ( id && id[1] ) ? id[1] : '';
209
+
210
+
classes = classes.replace( /wp-caption ?|align[a-z]+ ?/gi, '' );
211
+
212
+
if ( classes ) {
213
+
classes = ' class="' + classes + '"';
214
+
}
215
+
216
+
caption = caption.replace( /\r\n|\r/g, '\n' ).replace( /<[a-zA-Z0-9]+( [^<>]+)?>/g, function( a ) {
217
+
// No line breaks inside HTML tags.
218
+
return a.replace( /[\r\n\t]+/, ' ' );
219
+
});
220
+
221
+
// Convert remaining line breaks to <br>.
222
+
caption = caption.replace( /\s*\n\s*/g, '<br />' );
223
+
224
+
return '[caption id="' + id + '" align="' + align + '" width="' + width + '"' + classes + ']' + c + ' ' + caption + '[/caption]';
225
+
});
226
+
227
+
if ( out.indexOf('[caption') === -1 ) {
228
+
// The caption html seems broken, try to find the image that may be wrapped in a link
229
+
// and may be followed by <p> with the caption text.
230
+
out = dl.replace( /[\s\S]*?((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)(<p>[\s\S]*<\/p>)?[\s\S]*/gi, '<p>$1</p>$2' );
231
+
}
232
+
233
+
return out;
234
+
});
235
+
}
236
+
237
+
function extractImageData( imageNode ) {
238
+
var classes, extraClasses, metadata, captionBlock, caption, link, width, height,
239
+
captionClassName = [],
240
+
dom = editor.dom,
241
+
isIntRegExp = /^\d+$/;
242
+
243
+
// Default attributes.
244
+
metadata = {
245
+
attachment_id: false,
246
+
size: 'custom',
247
+
caption: '',
248
+
align: 'none',
249
+
extraClasses: '',
250
+
link: false,
251
+
linkUrl: '',
252
+
linkClassName: '',
253
+
linkTargetBlank: false,
254
+
linkRel: '',
255
+
title: ''
256
+
};
257
+
258
+
metadata.url = dom.getAttrib( imageNode, 'src' );
259
+
metadata.alt = dom.getAttrib( imageNode, 'alt' );
260
+
metadata.title = dom.getAttrib( imageNode, 'title' );
261
+
262
+
width = dom.getAttrib( imageNode, 'width' );
263
+
height = dom.getAttrib( imageNode, 'height' );
264
+
265
+
if ( ! isIntRegExp.test( width ) || parseInt( width, 10 ) < 1 ) {
266
+
width = imageNode.naturalWidth || imageNode.width;
267
+
}
268
+
269
+
if ( ! isIntRegExp.test( height ) || parseInt( height, 10 ) < 1 ) {
270
+
height = imageNode.naturalHeight || imageNode.height;
271
+
}
272
+
273
+
metadata.customWidth = metadata.width = width;
274
+
metadata.customHeight = metadata.height = height;
275
+
276
+
classes = tinymce.explode( imageNode.className, ' ' );
277
+
extraClasses = [];
278
+
279
+
tinymce.each( classes, function( name ) {
280
+
281
+
if ( /^wp-image/.test( name ) ) {
282
+
metadata.attachment_id = parseInt( name.replace( 'wp-image-', '' ), 10 );
283
+
} else if ( /^align/.test( name ) ) {
284
+
metadata.align = name.replace( 'align', '' );
285
+
} else if ( /^size/.test( name ) ) {
286
+
metadata.size = name.replace( 'size-', '' );
287
+
} else {
288
+
extraClasses.push( name );
289
+
}
290
+
291
+
} );
292
+
293
+
metadata.extraClasses = extraClasses.join( ' ' );
294
+
295
+
// Extract caption.
296
+
captionBlock = dom.getParents( imageNode, '.wp-caption' );
297
+
298
+
if ( captionBlock.length ) {
299
+
captionBlock = captionBlock[0];
300
+
301
+
classes = captionBlock.className.split( ' ' );
302
+
tinymce.each( classes, function( name ) {
303
+
if ( /^align/.test( name ) ) {
304
+
metadata.align = name.replace( 'align', '' );
305
+
} else if ( name && name !== 'wp-caption' ) {
306
+
captionClassName.push( name );
307
+
}
308
+
} );
309
+
310
+
metadata.captionClassName = captionClassName.join( ' ' );
311
+
312
+
caption = dom.select( 'dd.wp-caption-dd', captionBlock );
313
+
if ( caption.length ) {
314
+
caption = caption[0];
315
+
316
+
metadata.caption = editor.serializer.serialize( caption )
317
+
.replace( /<br[^>]*>/g, '$&\n' ).replace( /^<p>/, '' ).replace( /<\/p>$/, '' );
318
+
}
319
+
}
320
+
321
+
// Extract linkTo.
322
+
if ( imageNode.parentNode && imageNode.parentNode.nodeName === 'A' ) {
323
+
link = imageNode.parentNode;
324
+
metadata.linkUrl = dom.getAttrib( link, 'href' );
325
+
metadata.linkTargetBlank = dom.getAttrib( link, 'target' ) === '_blank' ? true : false;
326
+
metadata.linkRel = dom.getAttrib( link, 'rel' );
327
+
metadata.linkClassName = link.className;
328
+
}
329
+
330
+
return metadata;
331
+
}
332
+
333
+
function hasTextContent( node ) {
334
+
return node && !! ( node.textContent || node.innerText ).replace( /\ufeff/g, '' );
335
+
}
336
+
337
+
// Verify HTML in captions.
338
+
function verifyHTML( caption ) {
339
+
if ( ! caption || ( caption.indexOf( '<' ) === -1 && caption.indexOf( '>' ) === -1 ) ) {
340
+
return caption;
341
+
}
342
+
343
+
if ( ! serializer ) {
344
+
serializer = new tinymce.html.Serializer( {}, editor.schema );
345
+
}
346
+
347
+
return serializer.serialize( editor.parser.parse( caption, { forced_root_block: false } ) );
348
+
}
349
+
350
+
function updateImage( $imageNode, imageData ) {
351
+
var classes, className, node, html, parent, wrap, linkNode, imageNode,
352
+
captionNode, dd, dl, id, attrs, linkAttrs, width, height, align,
353
+
$imageNode, srcset, src,
354
+
dom = editor.dom;
355
+
356
+
if ( ! $imageNode || ! $imageNode.length ) {
357
+
return;
358
+
}
359
+
360
+
imageNode = $imageNode[0];
361
+
classes = tinymce.explode( imageData.extraClasses, ' ' );
362
+
363
+
if ( ! classes ) {
364
+
classes = [];
365
+
}
366
+
367
+
if ( ! imageData.caption ) {
368
+
classes.push( 'align' + imageData.align );
369
+
}
370
+
371
+
if ( imageData.attachment_id ) {
372
+
classes.push( 'wp-image-' + imageData.attachment_id );
373
+
if ( imageData.size && imageData.size !== 'custom' ) {
374
+
classes.push( 'size-' + imageData.size );
375
+
}
376
+
}
377
+
378
+
width = imageData.width;
379
+
height = imageData.height;
380
+
381
+
if ( imageData.size === 'custom' ) {
382
+
width = imageData.customWidth;
383
+
height = imageData.customHeight;
384
+
}
385
+
386
+
attrs = {
387
+
src: imageData.url,
388
+
width: width || null,
389
+
height: height || null,
390
+
title: imageData.title || null,
391
+
'class': classes.join( ' ' ) || null
392
+
};
393
+
394
+
dom.setAttribs( imageNode, attrs );
395
+
396
+
// Preserve empty alt attributes.
397
+
$imageNode.attr( 'alt', imageData.alt || '' );
398
+
399
+
linkAttrs = {
400
+
href: imageData.linkUrl,
401
+
rel: imageData.linkRel || null,
402
+
target: imageData.linkTargetBlank ? '_blank': null,
403
+
'class': imageData.linkClassName || null
404
+
};
405
+
406
+
if ( imageNode.parentNode && imageNode.parentNode.nodeName === 'A' && ! hasTextContent( imageNode.parentNode ) ) {
407
+
// Update or remove an existing link wrapped around the image.
408
+
if ( imageData.linkUrl ) {
409
+
dom.setAttribs( imageNode.parentNode, linkAttrs );
410
+
} else {
411
+
dom.remove( imageNode.parentNode, true );
412
+
}
413
+
} else if ( imageData.linkUrl ) {
414
+
if ( linkNode = dom.getParent( imageNode, 'a' ) ) {
415
+
// The image is inside a link together with other nodes,
416
+
// or is nested in another node, move it out.
417
+
dom.insertAfter( imageNode, linkNode );
418
+
}
419
+
420
+
// Add link wrapped around the image.
421
+
linkNode = dom.create( 'a', linkAttrs );
422
+
imageNode.parentNode.insertBefore( linkNode, imageNode );
423
+
linkNode.appendChild( imageNode );
424
+
}
425
+
426
+
captionNode = editor.dom.getParent( imageNode, '.mceTemp' );
427
+
428
+
if ( imageNode.parentNode && imageNode.parentNode.nodeName === 'A' && ! hasTextContent( imageNode.parentNode ) ) {
429
+
node = imageNode.parentNode;
430
+
} else {
431
+
node = imageNode;
432
+
}
433
+
434
+
if ( imageData.caption ) {
435
+
imageData.caption = verifyHTML( imageData.caption );
436
+
437
+
id = imageData.attachment_id ? 'attachment_' + imageData.attachment_id : null;
438
+
align = 'align' + ( imageData.align || 'none' );
439
+
className = 'wp-caption ' + align;
440
+
441
+
if ( imageData.captionClassName ) {
442
+
className += ' ' + imageData.captionClassName.replace( /[<>&]+/g, '' );
443
+
}
444
+
445
+
if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
446
+
width = parseInt( width, 10 );
447
+
width += 10;
448
+
}
449
+
450
+
if ( captionNode ) {
451
+
dl = dom.select( 'dl.wp-caption', captionNode );
452
+
453
+
if ( dl.length ) {
454
+
dom.setAttribs( dl, {
455
+
id: id,
456
+
'class': className,
457
+
style: 'width: ' + width + 'px'
458
+
} );
459
+
}
460
+
461
+
dd = dom.select( '.wp-caption-dd', captionNode );
462
+
463
+
if ( dd.length ) {
464
+
dom.setHTML( dd[0], imageData.caption );
465
+
}
466
+
467
+
} else {
468
+
id = id ? 'id="'+ id +'" ' : '';
469
+
470
+
// Should create a new function for generating the caption markup.
471
+
html = '<dl ' + id + 'class="' + className +'" style="width: '+ width +'px">' +
472
+
'<dt class="wp-caption-dt"></dt><dd class="wp-caption-dd">'+ imageData.caption +'</dd></dl>';
473
+
474
+
wrap = dom.create( 'div', { 'class': 'mceTemp' }, html );
475
+
476
+
if ( parent = dom.getParent( node, 'p' ) ) {
477
+
parent.parentNode.insertBefore( wrap, parent );
478
+
} else {
479
+
node.parentNode.insertBefore( wrap, node );
480
+
}
481
+
482
+
editor.$( wrap ).find( 'dt.wp-caption-dt' ).append( node );
483
+
484
+
if ( parent && dom.isEmpty( parent ) ) {
485
+
dom.remove( parent );
486
+
}
487
+
}
488
+
} else if ( captionNode ) {
489
+
// Remove the caption wrapper and place the image in new paragraph.
490
+
parent = dom.create( 'p' );
491
+
captionNode.parentNode.insertBefore( parent, captionNode );
492
+
parent.appendChild( node );
493
+
dom.remove( captionNode );
494
+
}
495
+
496
+
$imageNode = editor.$( imageNode );
497
+
srcset = $imageNode.attr( 'srcset' );
498
+
src = $imageNode.attr( 'src' );
499
+
500
+
// Remove srcset and sizes if the image file was edited or the image was replaced.
501
+
if ( srcset && src ) {
502
+
src = src.replace( /[?#].*/, '' );
503
+
504
+
if ( srcset.indexOf( src ) === -1 ) {
505
+
$imageNode.attr( 'srcset', null ).attr( 'sizes', null );
506
+
}
507
+
}
508
+
509
+
if ( wp.media.events ) {
510
+
wp.media.events.trigger( 'editor:image-update', {
511
+
editor: editor,
512
+
metadata: imageData,
513
+
image: imageNode
514
+
} );
515
+
}
516
+
517
+
editor.nodeChanged();
518
+
}
519
+
520
+
function editImage( img ) {
521
+
var frame, callback, metadata, imageNode;
522
+
523
+
if ( typeof wp === 'undefined' || ! wp.media ) {
524
+
editor.execCommand( 'mceImage' );
525
+
return;
526
+
}
527
+
528
+
metadata = extractImageData( img );
529
+
530
+
// Mark the image node so we can select it later.
531
+
editor.$( img ).attr( 'data-wp-editing', 1 );
532
+
533
+
// Manipulate the metadata by reference that is fed into the PostImage model used in the media modal.
534
+
wp.media.events.trigger( 'editor:image-edit', {
535
+
editor: editor,
536
+
metadata: metadata,
537
+
image: img
538
+
} );
539
+
540
+
frame = wp.media({
541
+
frame: 'image',
542
+
state: 'image-details',
543
+
metadata: metadata
544
+
} );
545
+
546
+
wp.media.events.trigger( 'editor:frame-create', { frame: frame } );
547
+
548
+
callback = function( imageData ) {
549
+
editor.undoManager.transact( function() {
550
+
updateImage( imageNode, imageData );
551
+
} );
552
+
frame.detach();
553
+
};
554
+
555
+
frame.state('image-details').on( 'update', callback );
556
+
frame.state('replace-image').on( 'replace', callback );
557
+
frame.on( 'close', function() {
558
+
editor.focus();
559
+
frame.detach();
560
+
561
+
/*
562
+
* `close` fires first...
563
+
* To be able to update the image node, we need to find it here,
564
+
* and use it in the callback.
565
+
*/
566
+
imageNode = editor.$( 'img[data-wp-editing]' )
567
+
imageNode.removeAttr( 'data-wp-editing' );
568
+
});
569
+
570
+
frame.open();
571
+
}
572
+
573
+
function removeImage( node ) {
574
+
var wrap = editor.dom.getParent( node, 'div.mceTemp' );
575
+
576
+
if ( ! wrap && node.nodeName === 'IMG' ) {
577
+
wrap = editor.dom.getParent( node, 'a' );
578
+
}
579
+
580
+
if ( wrap ) {
581
+
if ( wrap.nextSibling ) {
582
+
editor.selection.select( wrap.nextSibling );
583
+
} else if ( wrap.previousSibling ) {
584
+
editor.selection.select( wrap.previousSibling );
585
+
} else {
586
+
editor.selection.select( wrap.parentNode );
587
+
}
588
+
589
+
editor.selection.collapse( true );
590
+
editor.dom.remove( wrap );
591
+
} else {
592
+
editor.dom.remove( node );
593
+
}
594
+
595
+
editor.nodeChanged();
596
+
editor.undoManager.add();
597
+
}
598
+
599
+
editor.on( 'init', function() {
600
+
var dom = editor.dom,
601
+
captionClass = editor.getParam( 'wpeditimage_html5_captions' ) ? 'html5-captions' : 'html4-captions';
602
+
603
+
dom.addClass( editor.getBody(), captionClass );
604
+
605
+
// Prevent IE11 from making dl.wp-caption resizable.
606
+
if ( tinymce.Env.ie && tinymce.Env.ie > 10 ) {
607
+
// The 'mscontrolselect' event is supported only in IE11+.
608
+
dom.bind( editor.getBody(), 'mscontrolselect', function( event ) {
609
+
if ( event.target.nodeName === 'IMG' && dom.getParent( event.target, '.wp-caption' ) ) {
610
+
// Hide the thick border with resize handles around dl.wp-caption.
611
+
editor.getBody().focus(); // :(
612
+
} else if ( event.target.nodeName === 'DL' && dom.hasClass( event.target, 'wp-caption' ) ) {
613
+
// Trigger the thick border with resize handles...
614
+
// This will make the caption text editable.
615
+
event.target.focus();
616
+
}
617
+
});
618
+
}
619
+
});
620
+
621
+
editor.on( 'ObjectResized', function( event ) {
622
+
var node = event.target;
623
+
624
+
if ( node.nodeName === 'IMG' ) {
625
+
editor.undoManager.transact( function() {
626
+
var parent, width,
627
+
dom = editor.dom;
628
+
629
+
node.className = node.className.replace( /\bsize-[^ ]+/, '' );
630
+
631
+
if ( parent = dom.getParent( node, '.wp-caption' ) ) {
632
+
width = event.width || dom.getAttrib( node, 'width' );
633
+
634
+
if ( width ) {
635
+
width = parseInt( width, 10 );
636
+
637
+
if ( ! editor.getParam( 'wpeditimage_html5_captions' ) ) {
638
+
width += 10;
639
+
}
640
+
641
+
dom.setStyle( parent, 'width', width + 'px' );
642
+
}
643
+
}
644
+
});
645
+
}
646
+
});
647
+
648
+
editor.on( 'pastePostProcess', function( event ) {
649
+
// Pasting in a caption node.
650
+
if ( editor.dom.getParent( editor.selection.getNode(), 'dd.wp-caption-dd' ) ) {
651
+
// Remove "non-block" elements that should not be in captions.
652
+
editor.$( 'img, audio, video, object, embed, iframe, script, style', event.node ).remove();
653
+
654
+
editor.$( '*', event.node ).each( function( i, node ) {
655
+
if ( editor.dom.isBlock( node ) ) {
656
+
// Insert <br> where the blocks used to be. Makes it look better after pasting in the caption.
657
+
if ( tinymce.trim( node.textContent || node.innerText ) ) {
658
+
editor.dom.insertAfter( editor.dom.create( 'br' ), node );
659
+
editor.dom.remove( node, true );
660
+
} else {
661
+
editor.dom.remove( node );
662
+
}
663
+
}
664
+
});
665
+
666
+
// Trim <br> tags.
667
+
editor.$( 'br', event.node ).each( function( i, node ) {
668
+
if ( ! node.nextSibling || node.nextSibling.nodeName === 'BR' ||
669
+
! node.previousSibling || node.previousSibling.nodeName === 'BR' ) {
670
+
671
+
editor.dom.remove( node );
672
+
}
673
+
} );
674
+
675
+
// Pasted HTML is cleaned up for inserting in the caption.
676
+
pasteInCaption = true;
677
+
}
678
+
});
679
+
680
+
editor.on( 'BeforeExecCommand', function( event ) {
681
+
var node, p, DL, align, replacement, captionParent,
682
+
cmd = event.command,
683
+
dom = editor.dom;
684
+
685
+
if ( cmd === 'mceInsertContent' || cmd === 'Indent' || cmd === 'Outdent' ) {
686
+
node = editor.selection.getNode();
687
+
captionParent = dom.getParent( node, 'div.mceTemp' );
688
+
689
+
if ( captionParent ) {
690
+
if ( cmd === 'mceInsertContent' ) {
691
+
if ( pasteInCaption ) {
692
+
pasteInCaption = false;
693
+
/*
694
+
* We are in the caption element, and in 'paste' context,
695
+
* and the pasted HTML was cleaned up on 'pastePostProcess' above.
696
+
* Let it be pasted in the caption.
697
+
*/
698
+
return;
699
+
}
700
+
701
+
/*
702
+
* The paste is somewhere else in the caption DL element.
703
+
* Prevent pasting in there as it will break the caption.
704
+
* Make new paragraph under the caption DL and move the caret there.
705
+
*/
706
+
p = dom.create( 'p' );
707
+
dom.insertAfter( p, captionParent );
708
+
editor.selection.setCursorLocation( p, 0 );
709
+
710
+
/*
711
+
* If the image is selected and the user pastes "over" it,
712
+
* replace both the image and the caption elements with the pasted content.
713
+
* This matches the behavior when pasting over non-caption images.
714
+
*/
715
+
if ( node.nodeName === 'IMG' ) {
716
+
editor.$( captionParent ).remove();
717
+
}
718
+
719
+
editor.nodeChanged();
720
+
} else {
721
+
// Clicking Indent or Outdent while an image with a caption is selected breaks the caption.
722
+
// See #38313.
723
+
event.preventDefault();
724
+
event.stopImmediatePropagation();
725
+
return false;
726
+
}
727
+
}
728
+
} else if ( cmd === 'JustifyLeft' || cmd === 'JustifyRight' || cmd === 'JustifyCenter' || cmd === 'wpAlignNone' ) {
729
+
node = editor.selection.getNode();
730
+
align = 'align' + cmd.slice( 7 ).toLowerCase();
731
+
DL = editor.dom.getParent( node, '.wp-caption' );
732
+
733
+
if ( node.nodeName !== 'IMG' && ! DL ) {
734
+
return;
735
+
}
736
+
737
+
node = DL || node;
738
+
739
+
if ( editor.dom.hasClass( node, align ) ) {
740
+
replacement = ' alignnone';
741
+
} else {
742
+
replacement = ' ' + align;
743
+
}
744
+
745
+
node.className = trim( node.className.replace( / ?align(left|center|right|none)/g, '' ) + replacement );
746
+
747
+
editor.nodeChanged();
748
+
event.preventDefault();
749
+
750
+
if ( toolbar ) {
751
+
toolbar.reposition();
752
+
}
753
+
754
+
editor.fire( 'ExecCommand', {
755
+
command: cmd,
756
+
ui: event.ui,
757
+
value: event.value
758
+
} );
759
+
}
760
+
});
761
+
762
+
editor.on( 'keydown', function( event ) {
763
+
var node, wrap, P, spacer,
764
+
selection = editor.selection,
765
+
keyCode = event.keyCode,
766
+
dom = editor.dom,
767
+
VK = tinymce.util.VK;
768
+
769
+
if ( keyCode === VK.ENTER ) {
770
+
// When pressing Enter inside a caption move the caret to a new parapraph under it.
771
+
node = selection.getNode();
772
+
wrap = dom.getParent( node, 'div.mceTemp' );
773
+
774
+
if ( wrap ) {
775
+
dom.events.cancel( event ); // Doesn't cancel all :(
776
+
777
+
// Remove any extra dt and dd cleated on pressing Enter...
778
+
tinymce.each( dom.select( 'dt, dd', wrap ), function( element ) {
779
+
if ( dom.isEmpty( element ) ) {
780
+
dom.remove( element );
781
+
}
782
+
});
783
+
784
+
spacer = tinymce.Env.ie && tinymce.Env.ie < 11 ? '' : '<br data-mce-bogus="1" />';
785
+
P = dom.create( 'p', null, spacer );
786
+
787
+
if ( node.nodeName === 'DD' ) {
788
+
dom.insertAfter( P, wrap );
789
+
} else {
790
+
wrap.parentNode.insertBefore( P, wrap );
791
+
}
792
+
793
+
editor.nodeChanged();
794
+
selection.setCursorLocation( P, 0 );
795
+
}
796
+
} else if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
797
+
node = selection.getNode();
798
+
799
+
if ( node.nodeName === 'DIV' && dom.hasClass( node, 'mceTemp' ) ) {
800
+
wrap = node;
801
+
} else if ( node.nodeName === 'IMG' || node.nodeName === 'DT' || node.nodeName === 'A' ) {
802
+
wrap = dom.getParent( node, 'div.mceTemp' );
803
+
}
804
+
805
+
if ( wrap ) {
806
+
dom.events.cancel( event );
807
+
removeImage( node );
808
+
return false;
809
+
}
810
+
}
811
+
});
812
+
813
+
/*
814
+
* After undo/redo FF seems to set the image height very slowly when it is set to 'auto' in the CSS.
815
+
* This causes image.getBoundingClientRect() to return wrong values and the resize handles are shown in wrong places.
816
+
* Collapse the selection to remove the resize handles.
817
+
*/
818
+
if ( tinymce.Env.gecko ) {
819
+
editor.on( 'undo redo', function() {
820
+
if ( editor.selection.getNode().nodeName === 'IMG' ) {
821
+
editor.selection.collapse();
822
+
}
823
+
});
824
+
}
825
+
826
+
editor.wpSetImgCaption = function( content ) {
827
+
return parseShortcode( content );
828
+
};
829
+
830
+
editor.wpGetImgCaption = function( content ) {
831
+
return getShortcode( content );
832
+
};
833
+
834
+
editor.on( 'beforeGetContent', function( event ) {
835
+
if ( event.format !== 'raw' ) {
836
+
editor.$( 'img[id="__wp-temp-img-id"]' ).removeAttr( 'id' );
837
+
}
838
+
});
839
+
840
+
editor.on( 'BeforeSetContent', function( event ) {
841
+
if ( event.format !== 'raw' ) {
842
+
event.content = editor.wpSetImgCaption( event.content );
843
+
}
844
+
});
845
+
846
+
editor.on( 'PostProcess', function( event ) {
847
+
if ( event.get ) {
848
+
event.content = editor.wpGetImgCaption( event.content );
849
+
}
850
+
});
851
+
852
+
( function() {
853
+
var wrap;
854
+
855
+
editor.on( 'dragstart', function() {
856
+
var node = editor.selection.getNode();
857
+
858
+
if ( node.nodeName === 'IMG' ) {
859
+
wrap = editor.dom.getParent( node, '.mceTemp' );
860
+
861
+
if ( ! wrap && node.parentNode.nodeName === 'A' && ! hasTextContent( node.parentNode ) ) {
862
+
wrap = node.parentNode;
863
+
}
864
+
}
865
+
} );
866
+
867
+
editor.on( 'drop', function( event ) {
868
+
var dom = editor.dom,
869
+
rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint( event.clientX, event.clientY, editor.getDoc() );
870
+
871
+
// Don't allow anything to be dropped in a captioned image.
872
+
if ( rng && dom.getParent( rng.startContainer, '.mceTemp' ) ) {
873
+
event.preventDefault();
874
+
} else if ( wrap ) {
875
+
event.preventDefault();
876
+
877
+
editor.undoManager.transact( function() {
878
+
if ( rng ) {
879
+
editor.selection.setRng( rng );
880
+
}
881
+
882
+
editor.selection.setNode( wrap );
883
+
dom.remove( wrap );
884
+
} );
885
+
}
886
+
887
+
wrap = null;
888
+
} );
889
+
} )();
890
+
891
+
// Add to editor.wp.
892
+
editor.wp = editor.wp || {};
893
+
editor.wp.isPlaceholder = isPlaceholder;
894
+
895
+
// Back-compat.
896
+
return {
897
+
_do_shcode: parseShortcode,
898
+
_get_shcode: getShortcode
899
+
};
900
+
});
901
+