| | 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 | | |