| 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', |
| 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: 'Remove 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 | function toolbarConfig() { |
| 64 | var toolbarItems = [], |
| 65 | buttonGroup; |
| 66 | |
| 67 | each( [ 'wp_img_alignleft', 'wp_img_aligncenter', 'wp_img_alignright', 'wp_img_alignnone', 'wp_img_edit', 'wp_img_remove' ], function( item ) { |
| 68 | var itemName; |
| 69 | |
| 70 | function bindSelectorChanged() { |
| 71 | var selection = editor.selection; |
| 72 | |
| 73 | if ( item.settings.stateSelector ) { |
| 74 | selection.selectorChanged( item.settings.stateSelector, function( state ) { |
| 75 | item.active( state ); |
| 76 | }, true ); |
| 77 | } |
| 78 | |
| 79 | if ( item.settings.disabledStateSelector ) { |
| 80 | selection.selectorChanged( item.settings.disabledStateSelector, function( state ) { |
| 81 | item.disabled( state ); |
| 82 | } ); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | if ( item === '|' ) { |
| 87 | buttonGroup = null; |
| 88 | } else { |
| 89 | if ( Factory.has( item ) ) { |
| 90 | item = { |
| 91 | type: item |
| 92 | }; |
| 93 | |
| 94 | if ( settings.toolbar_items_size ) { |
| 95 | item.size = settings.toolbar_items_size; |
| 96 | } |
| 97 | |
| 98 | toolbarItems.push( item ); |
| 99 | |
| 100 | buttonGroup = null; |
| 101 | } else { |
| 102 | if ( ! buttonGroup ) { |
| 103 | buttonGroup = { |
| 104 | type: 'buttongroup', |
| 105 | items: [] |
| 106 | }; |
| 107 | |
| 108 | toolbarItems.push( buttonGroup ); |
| 109 | } |
| 110 | |
| 111 | if ( editor.buttons[ item ] ) { |
| 112 | itemName = item; |
| 113 | item = editor.buttons[ itemName ]; |
| 114 | |
| 115 | if ( typeof item === 'function' ) { |
| 116 | item = item(); |
| 117 | } |
| 118 | |
| 119 | item.type = item.type || 'button'; |
| 120 | |
| 121 | if ( settings.toolbar_items_size ) { |
| 122 | item.size = settings.toolbar_items_size; |
| 123 | } |
| 124 | |
| 125 | item = Factory.create( item ); |
| 126 | buttonGroup.items.push( item ); |
| 127 | |
| 128 | if ( editor.initialized ) { |
| 129 | bindSelectorChanged(); |
| 130 | } else { |
| 131 | editor.on( 'init', bindSelectorChanged ); |
| 132 | } |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | } ); |
| 137 | |
| 138 | return { |
| 139 | type: 'panel', |
| 140 | layout: 'stack', |
| 141 | classes: 'toolbar-grp inline-toolbar-grp wp-image-toolbar', |
| 142 | ariaRoot: true, |
| 143 | ariaRemember: true, |
| 144 | items: [ |
| 145 | { |
| 146 | type: 'toolbar', |
| 147 | layout: 'flow', |
| 148 | items: toolbarItems |
| 149 | } |
| 150 | ] |
| 151 | }; |
| 152 | } |
| 153 | |
| 154 | tb = Factory.create( toolbarConfig() ).renderTo( document.body ).hide(); |
| 155 | |
| 156 | tb.reposition = function() { |
| 157 | var top, left, minTop, className, |
| 158 | toolbarNode = this.getEl(), |
| 159 | buffer = 5, |
| 160 | margin = 8, |
| 161 | windowPos = window.pageYOffset || document.documentElement.scrollTop, |
| 162 | adminbar = tinymce.$( '#wpadminbar' )[0], |
| 163 | mceToolbar = tinymce.$( '.mce-tinymce .mce-toolbar-grp' )[0], |
| 164 | adminbarHeight = 0, |
| 165 | boundary = editor.selection.getRng().getBoundingClientRect(), |
| 166 | boundaryMiddle = ( boundary.left + boundary.right ) / 2, |
| 167 | boundaryVerticalMiddle = ( boundary.top + boundary.bottom ) / 2, |
| 168 | spaceTop = boundary.top, |
| 169 | spaceBottom = iframeHeigth - boundary.bottom, |
| 170 | windowWidth = window.innerWidth, |
| 171 | toolbarWidth = toolbarNode.offsetWidth, |
| 172 | toolbarHalf = toolbarWidth / 2, |
| 173 | iframe = editor.getContentAreaContainer().firstChild, |
| 174 | iframePos = DOM.getPos( iframe ), |
| 175 | iframeWidth = iframe.offsetWidth, |
| 176 | iframeHeigth = iframe.offsetHeight, |
| 177 | toolbarNodeHeight = toolbarNode.offsetHeight, |
| 178 | verticalSpaceNeeded = toolbarNodeHeight + margin + buffer; |
| 179 | |
| 180 | if ( iOS ) { |
| 181 | top = boundary.top + iframePos.y + margin; |
| 182 | } else { |
| 183 | if ( spaceTop >= verticalSpaceNeeded ) { |
| 184 | className = ' mce-arrow-down'; |
| 185 | top = boundary.top + iframePos.y - toolbarNodeHeight - margin; |
| 186 | } else if ( spaceBottom >= verticalSpaceNeeded ) { |
| 187 | className = ' mce-arrow-up'; |
| 188 | top = boundary.bottom + iframePos.y; |
| 189 | } else { |
| 190 | top = buffer; |
| 191 | |
| 192 | if ( boundaryVerticalMiddle >= verticalSpaceNeeded ) { |
| 193 | className = ' mce-arrow-down'; |
| 194 | } else { |
| 195 | className = ' mce-arrow-up'; |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | // Make sure the image toolbar is below the main toolbar. |
| 201 | if ( mceToolbar ) { |
| 202 | minTop = DOM.getPos( mceToolbar ).y + mceToolbar.clientHeight; |
| 203 | } else { |
| 204 | minTop = iframePos.y; |
| 205 | } |
| 206 | |
| 207 | // Make sure the image toolbar is below the adminbar (if visible) or below the top of the window. |
| 208 | if ( windowPos ) { |
| 209 | if ( adminbar && adminbar.getBoundingClientRect().top === 0 ) { |
| 210 | adminbarHeight = adminbar.clientHeight; |
| 211 | } |
| 212 | |
| 213 | if ( windowPos + adminbarHeight > minTop ) { |
| 214 | minTop = windowPos + adminbarHeight; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | if ( top && minTop && ( minTop + buffer > top ) ) { |
| 219 | top = minTop + buffer; |
| 220 | className = ''; |
| 221 | } |
| 222 | |
| 223 | left = boundaryMiddle - toolbarHalf; |
| 224 | left += iframePos.x; |
| 225 | |
| 226 | if ( toolbarWidth >= windowWidth ) { |
| 227 | className += ' mce-arrow-full'; |
| 228 | left = 0; |
| 229 | } else if ( ( left < 0 && boundary.left + toolbarWidth > windowWidth ) || |
| 230 | ( left + toolbarWidth > windowWidth && boundary.right - toolbarWidth < 0 ) ) { |
| 231 | |
| 232 | left = ( windowWidth - toolbarWidth ) / 2; |
| 233 | } else if ( left < iframePos.x ) { |
| 234 | className += ' mce-arrow-left'; |
| 235 | left = boundary.left + iframePos.x; |
| 236 | } else if ( left + toolbarWidth > iframeWidth + iframePos.x ) { |
| 237 | className += ' mce-arrow-right'; |
| 238 | left = boundary.right - toolbarWidth + iframePos.x; |
| 239 | } |
| 240 | |
| 241 | if ( ! iOS ) { |
| 242 | toolbarNode.className = toolbarNode.className.replace( / ?mce-arrow-[\w]+/g, '' ); |
| 243 | toolbarNode.className += className; |
| 244 | } |
| 245 | |
| 246 | DOM.setStyles( toolbarNode, { 'left': left, 'top': top } ); |
| 247 | |
| 248 | return this; |
| 249 | }; |
| 250 | |
| 251 | if ( iOS ) { |
| 252 | // Safari on iOS fails to select image nodes in contentEditoble mode on touch/click. |
| 253 | // Select them again. |
| 254 | editor.on( 'click', function( event ) { |
| 255 | if ( event.target.nodeName === 'IMG' ) { |
| 256 | var node = event.target; |
| 257 | |
| 258 | window.setTimeout( function() { |
| 259 | editor.selection.select( node ); |
| 260 | }, 200 ); |
| 261 | } else { |
| 262 | tb.hide(); |
| 263 | } |
| 264 | }); |
| 265 | } |
| 266 | |
| 267 | editor.on( 'nodechange', function( event ) { |
| 268 | var delay = iOS ? 350 : 100; |
| 269 | |
| 270 | if ( event.element.nodeName !== 'IMG' ) { |
| 271 | tb.hide(); |
| 272 | return; |
| 273 | } |
| 274 | |
| 275 | setTimeout( function() { |
| 276 | var element = editor.selection.getNode(); |
| 277 | |
| 278 | if ( element.nodeName === 'IMG' ) { |
| 279 | if ( tb._visible ) { |
| 280 | tb.reposition(); |
| 281 | } else { |
| 282 | tb.show(); |
| 283 | } |
| 284 | } else { |
| 285 | tb.hide(); |
| 286 | } |
| 287 | }, delay ); |
| 288 | } ); |
| 289 | |
| 290 | tb.on( 'show', function() { |
| 291 | var self = this; |
| 292 | |
| 293 | toolbarIsHidden = false; |
| 294 | |
| 295 | setTimeout( function() { |
| 296 | if ( self._visible ) { |
| 297 | DOM.addClass( self.getEl(), 'mce-inline-toolbar-grp-active' ); |
| 298 | self.reposition(); |
| 299 | } |
| 300 | }, 100 ); |
| 301 | } ); |
| 302 | |
| 303 | tb.on( 'hide', function() { |
| 304 | toolbarIsHidden = true; |
| 305 | DOM.removeClass( this.getEl(), 'mce-inline-toolbar-grp-active' ); |
| 306 | } ); |
| 307 | |
| 308 | function hide() { |
| 309 | if ( ! toolbarIsHidden ) { |
| 310 | tb.hide(); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | DOM.bind( window, 'resize scroll', function() { |
| 315 | if ( ! toolbarIsHidden && editorWrapParent.hasClass( 'wp-editor-expand' ) ) { |
| 316 | hide(); |
| 317 | } |
| 318 | }); |
| 319 | |
| 320 | editor.on( 'init', function() { |
| 321 | DOM.bind( editor.getWin(), 'resize scroll', hide ); |
| 322 | } ); |
| 323 | |
| 324 | editor.on( 'blur hide', hide ); |
| 325 | |
| 326 | // 119 = F8 |
| 327 | editor.shortcuts.add( 'Alt+119', '', function() { |
| 328 | var node = tb.find( 'toolbar' )[0]; |
| 329 | |
| 330 | if ( node ) { |
| 331 | node.focus( true ); |
| 332 | } |
| 333 | } ); |
| 334 | |
452 | | function addToolbar( node ) { |
453 | | var rectangle, toolbarHtml, toolbar, left, |
454 | | dom = editor.dom; |
455 | | |
456 | | removeToolbar(); |
457 | | |
458 | | // Don't add to placeholders |
459 | | if ( ! node || node.nodeName !== 'IMG' || isPlaceholder( node ) ) { |
460 | | return; |
461 | | } |
462 | | |
463 | | dom.setAttrib( node, 'data-wp-imgselect', 1 ); |
464 | | rectangle = dom.getRect( node ); |
465 | | |
466 | | toolbarHtml = '<i class="dashicons dashicons-edit edit" data-mce-bogus="all"></i>' + |
467 | | '<i class="dashicons dashicons-no-alt remove" data-mce-bogus="all"></i>'; |
468 | | |
469 | | toolbar = dom.create( 'p', { |
470 | | 'id': 'wp-image-toolbar', |
471 | | 'data-mce-bogus': 'all', |
472 | | 'contenteditable': false |
473 | | }, toolbarHtml ); |
474 | | |
475 | | if ( editor.rtl ) { |
476 | | left = rectangle.x + rectangle.w - 82; |
477 | | } else { |
478 | | left = rectangle.x; |
479 | | } |
480 | | |
481 | | editor.getBody().appendChild( toolbar ); |
482 | | dom.setStyles( toolbar, { |
483 | | top: rectangle.y, |
484 | | left: left |
485 | | }); |
486 | | |
487 | | toolbarActive = true; |
488 | | } |
489 | | |
490 | | function removeToolbar() { |
491 | | var toolbar = editor.dom.get( 'wp-image-toolbar' ); |
492 | | |
493 | | if ( toolbar ) { |
494 | | editor.dom.remove( toolbar ); |
495 | | } |
496 | | |
497 | | editor.dom.setAttrib( editor.dom.select( 'img[data-wp-imgselect]' ), 'data-wp-imgselect', null ); |
498 | | |
499 | | editingImage = false; |
500 | | toolbarActive = false; |
501 | | } |
502 | | |
503 | | function isPlaceholder( node ) { |
504 | | var dom = editor.dom; |
505 | | |
506 | | if ( dom.hasClass( node, 'mceItem' ) || dom.getAttrib( node, 'data-mce-placeholder' ) || |
507 | | dom.getAttrib( node, 'data-mce-object' ) ) { |
508 | | |
509 | | return true; |
510 | | } |
511 | | |
512 | | return false; |
513 | | } |
514 | | |
515 | | function isToolbarButton( node ) { |
516 | | return ( node && node.nodeName === 'I' && node.parentNode.id === 'wp-image-toolbar' ); |
517 | | } |
518 | | |
519 | | function edit( event ) { |
520 | | var image, |
521 | | node = event.target, |
522 | | dom = editor.dom; |
523 | | |
524 | | // Don't trigger on right-click |
525 | | if ( event.button && event.button > 1 ) { |
526 | | return; |
527 | | } |
528 | | |
529 | | if ( isToolbarButton( node ) ) { |
530 | | image = dom.select( 'img[data-wp-imgselect]' )[0]; |
531 | | |
532 | | if ( image ) { |
533 | | editor.selection.select( image ); |
534 | | |
535 | | if ( dom.hasClass( node, 'remove' ) ) { |
536 | | removeImage( image ); |
537 | | } else if ( dom.hasClass( node, 'edit' ) ) { |
538 | | if ( ! editingImage ) { |
539 | | editImage( image ); |
540 | | editingImage = true; |
541 | | } |
542 | | } |
543 | | } |
544 | | |
545 | | event.preventDefault(); |
546 | | } else if ( node.nodeName === 'IMG' && ! editor.dom.getAttrib( node, 'data-wp-imgselect' ) && ! isPlaceholder( node ) ) { |
547 | | addToolbar( node ); |
548 | | } else if ( node.nodeName !== 'IMG' ) { |
549 | | removeToolbar(); |
550 | | } |
551 | | } |
552 | | |
553 | | if ( 'ontouchend' in document ) { |
554 | | editor.on( 'click', function( event ) { |
555 | | var target = event.target; |
556 | | |
557 | | if ( editingImage && target.nodeName === 'IMG' ) { |
558 | | event.preventDefault(); |
559 | | } |
560 | | |
561 | | if ( isToolbarButton( target ) ) { |
562 | | event.preventDefault(); |
563 | | event.stopPropagation(); |
564 | | } |
565 | | }); |
566 | | } |
567 | | |
568 | | editor.on( 'mouseup touchend', edit ); |
569 | | |