]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/js/tinymce/plugins/wordpress/plugin.js
WordPress 4.2.1-scripts
[autoinstalls/wordpress.git] / wp-includes / js / tinymce / plugins / wordpress / plugin.js
1 /* global tinymce, getUserSetting, setUserSetting */
2
3 // Set the minimum value for the modals z-index higher than #wpadminbar (100000)
4 tinymce.ui.FloatPanel.zIndex = 100100;
5
6 tinymce.PluginManager.add( 'wordpress', function( editor ) {
7         var DOM = tinymce.DOM,
8                 each = tinymce.each,
9                 __ = editor.editorManager.i18n.translate,
10                 wpAdvButton, style,
11                 last = 0;
12
13         if ( typeof window.jQuery !== 'undefined' ) {
14                 window.jQuery( document ).triggerHandler( 'tinymce-editor-setup', [ editor ] );
15         }
16
17         function toggleToolbars( state ) {
18                 var iframe, initial, toolbars,
19                         pixels = 0;
20
21                 initial = ( state === 'hide' );
22
23                 if ( editor.theme.panel ) {
24                         toolbars = editor.theme.panel.find('.toolbar:not(.menubar)');
25                 }
26
27                 if ( ! toolbars || toolbars.length < 2 || ( state === 'hide' && ! toolbars[1].visible() ) ) {
28                         return;
29                 }
30
31                 if ( ! state && toolbars[1].visible() ) {
32                         state = 'hide';
33                 }
34
35                 each( toolbars, function( toolbar, i ) {
36                         if ( i > 0 ) {
37                                 if ( state === 'hide' ) {
38                                         toolbar.hide();
39                                         pixels += 30;
40                                 } else {
41                                         toolbar.show();
42                                         pixels -= 30;
43                                 }
44                         }
45                 });
46
47                 if ( pixels && ! initial ) {
48                         // Resize iframe, not needed in iOS
49                         if ( ! tinymce.Env.iOS ) {
50                                 iframe = editor.getContentAreaContainer().firstChild;
51                                 DOM.setStyle( iframe, 'height', iframe.clientHeight + pixels );
52                         }
53
54                         if ( state === 'hide' ) {
55                                 setUserSetting('hidetb', '0');
56                                 wpAdvButton && wpAdvButton.active( false );
57                         } else {
58                                 setUserSetting('hidetb', '1');
59                                 wpAdvButton && wpAdvButton.active( true );
60                         }
61                 }
62
63                 editor.fire( 'wp-toolbar-toggle' );
64         }
65
66         // Add the kitchen sink button :)
67         editor.addButton( 'wp_adv', {
68                 tooltip: 'Toolbar Toggle',
69                 cmd: 'WP_Adv',
70                 onPostRender: function() {
71                         wpAdvButton = this;
72                         wpAdvButton.active( getUserSetting( 'hidetb' ) === '1' ? true : false );
73                 }
74         });
75
76         // Hide the toolbars after loading
77         editor.on( 'PostRender', function() {
78                 if ( editor.getParam( 'wordpress_adv_hidden', true ) && getUserSetting( 'hidetb', '0' ) === '0' ) {
79                         toggleToolbars( 'hide' );
80                 }
81         });
82
83         editor.addCommand( 'WP_Adv', function() {
84                 toggleToolbars();
85         });
86
87         editor.on( 'focus', function() {
88         window.wpActiveEditor = editor.id;
89     });
90
91         // Replace Read More/Next Page tags with images
92         editor.on( 'BeforeSetContent', function( e ) {
93                 var title;
94
95                 if ( e.content ) {
96                         if ( e.content.indexOf( '<!--more' ) !== -1 ) {
97                                 title = __( 'Read more...' );
98
99                                 e.content = e.content.replace( /<!--more(.*?)-->/g, function( match, moretext ) {
100                                         return '<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="more" data-wp-more-text="' + moretext + '" ' +
101                                                 'class="wp-more-tag mce-wp-more" title="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />';
102                                 });
103                         }
104
105                         if ( e.content.indexOf( '<!--nextpage-->' ) !== -1 ) {
106                                 title = __( 'Page break' );
107
108                                 e.content = e.content.replace( /<!--nextpage-->/g,
109                                         '<img src="' + tinymce.Env.transparentSrc + '" data-wp-more="nextpage" class="wp-more-tag mce-wp-nextpage" ' +
110                                                 'title="' + title + '" data-mce-resize="false" data-mce-placeholder="1" />' );
111                         }
112                 }
113         });
114
115         // Replace images with tags
116         editor.on( 'PostProcess', function( e ) {
117                 if ( e.get ) {
118                         e.content = e.content.replace(/<img[^>]+>/g, function( image ) {
119                                 var match, moretext = '';
120
121                                 if ( image.indexOf( 'data-wp-more="more"' ) !== -1 ) {
122                                         if ( match = image.match( /data-wp-more-text="([^"]+)"/ ) ) {
123                                                 moretext = match[1];
124                                         }
125
126                                         image = '<!--more' + moretext + '-->';
127                                 } else if ( image.indexOf( 'data-wp-more="nextpage"' ) !== -1 ) {
128                                         image = '<!--nextpage-->';
129                                 }
130
131                                 return image;
132                         });
133                 }
134         });
135
136         // Display the tag name instead of img in element path
137         editor.on( 'ResolveName', function( event ) {
138                 var attr;
139
140                 if ( event.target.nodeName === 'IMG' && ( attr = editor.dom.getAttrib( event.target, 'data-wp-more' ) ) ) {
141                         event.name = attr;
142                 }
143         });
144
145         // Register commands
146         editor.addCommand( 'WP_More', function( tag ) {
147                 var parent, html, title,
148                         classname = 'wp-more-tag',
149                         dom = editor.dom,
150                         node = editor.selection.getNode();
151
152                 tag = tag || 'more';
153                 classname += ' mce-wp-' + tag;
154                 title = tag === 'more' ? 'Read more...' : 'Next page';
155                 title = __( title );
156                 html = '<img src="' + tinymce.Env.transparentSrc + '" title="' + title + '" class="' + classname + '" ' +
157                         'data-wp-more="' + tag + '" data-mce-resize="false" data-mce-placeholder="1" />';
158
159                 // Most common case
160                 if ( node.nodeName === 'BODY' || ( node.nodeName === 'P' && node.parentNode.nodeName === 'BODY' ) ) {
161                         editor.insertContent( html );
162                         return;
163                 }
164
165                 // Get the top level parent node
166                 parent = dom.getParent( node, function( found ) {
167                         if ( found.parentNode && found.parentNode.nodeName === 'BODY' ) {
168                                 return true;
169                         }
170
171                         return false;
172                 }, editor.getBody() );
173
174                 if ( parent ) {
175                         if ( parent.nodeName === 'P' ) {
176                                 parent.appendChild( dom.create( 'p', null, html ).firstChild );
177                         } else {
178                                 dom.insertAfter( dom.create( 'p', null, html ), parent );
179                         }
180
181                         editor.nodeChanged();
182                 }
183         });
184
185         editor.addCommand( 'WP_Code', function() {
186                 editor.formatter.toggle('code');
187         });
188
189         editor.addCommand( 'WP_Page', function() {
190                 editor.execCommand( 'WP_More', 'nextpage' );
191         });
192
193         editor.addCommand( 'WP_Help', function() {
194                 editor.windowManager.open({
195                         url: tinymce.baseURL + '/wp-mce-help.php',
196                         title: 'Keyboard Shortcuts',
197                         width: 450,
198                         height: 420,
199                         classes: 'wp-help',
200                         buttons: { text: 'Close', onclick: 'close' }
201                 });
202         });
203
204         editor.addCommand( 'WP_Medialib', function() {
205                 if ( typeof wp !== 'undefined' && wp.media && wp.media.editor ) {
206                         wp.media.editor.open( editor.id );
207                 }
208         });
209
210         // Register buttons
211         editor.addButton( 'wp_more', {
212                 tooltip: 'Insert Read More tag',
213                 onclick: function() {
214                         editor.execCommand( 'WP_More', 'more' );
215                 }
216         });
217
218         editor.addButton( 'wp_page', {
219                 tooltip: 'Page break',
220                 onclick: function() {
221                         editor.execCommand( 'WP_More', 'nextpage' );
222                 }
223         });
224
225         editor.addButton( 'wp_help', {
226                 tooltip: 'Keyboard Shortcuts',
227                 cmd: 'WP_Help'
228         });
229
230         editor.addButton( 'wp_code', {
231                 tooltip: 'Code',
232                 cmd: 'WP_Code',
233                 stateSelector: 'code'
234         });
235
236         // Menubar
237         // Insert->Add Media
238         if ( typeof wp !== 'undefined' && wp.media && wp.media.editor ) {
239                 editor.addMenuItem( 'add_media', {
240                         text: 'Add Media',
241                         icon: 'wp-media-library',
242                         context: 'insert',
243                         cmd: 'WP_Medialib'
244                 });
245         }
246
247         // Insert "Read More..."
248         editor.addMenuItem( 'wp_more', {
249                 text: 'Insert Read More tag',
250                 icon: 'wp_more',
251                 context: 'insert',
252                 onclick: function() {
253                         editor.execCommand( 'WP_More', 'more' );
254                 }
255         });
256
257         // Insert "Next Page"
258         editor.addMenuItem( 'wp_page', {
259                 text: 'Page break',
260                 icon: 'wp_page',
261                 context: 'insert',
262                 onclick: function() {
263                         editor.execCommand( 'WP_More', 'nextpage' );
264                 }
265         });
266
267         editor.on( 'BeforeExecCommand', function(e) {
268                 if ( tinymce.Env.webkit && ( e.command === 'InsertUnorderedList' || e.command === 'InsertOrderedList' ) ) {
269                         if ( ! style ) {
270                                 style = editor.dom.create( 'style', {'type': 'text/css'},
271                                         '#tinymce,#tinymce span,#tinymce li,#tinymce li>span,#tinymce p,#tinymce p>span{font:medium sans-serif;color:#000;line-height:normal;}');
272                         }
273
274                         editor.getDoc().head.appendChild( style );
275                 }
276         });
277
278         editor.on( 'ExecCommand', function( e ) {
279                 if ( tinymce.Env.webkit && style &&
280                         ( 'InsertUnorderedList' === e.command || 'InsertOrderedList' === e.command ) ) {
281
282                         editor.dom.remove( style );
283                 }
284         });
285
286         editor.on( 'init', function() {
287                 var env = tinymce.Env,
288                         bodyClass = ['mceContentBody'], // back-compat for themes that use this in editor-style.css...
289                         doc = editor.getDoc(),
290                         dom = editor.dom;
291
292                 if ( tinymce.Env.iOS ) {
293                         dom.addClass( doc.documentElement, 'ios' );
294                 }
295
296                 if ( editor.getParam( 'directionality' ) === 'rtl' ) {
297                         bodyClass.push('rtl');
298                         dom.setAttrib( doc.documentElement, 'dir', 'rtl' );
299                 }
300
301                 if ( env.ie ) {
302                         if ( parseInt( env.ie, 10 ) === 9 ) {
303                                 bodyClass.push('ie9');
304                         } else if ( parseInt( env.ie, 10 ) === 8 ) {
305                                 bodyClass.push('ie8');
306                         } else if ( env.ie < 8 ) {
307                                 bodyClass.push('ie7');
308                         }
309                 } else if ( env.webkit ) {
310                         bodyClass.push('webkit');
311                 }
312
313                 bodyClass.push('wp-editor');
314
315                 each( bodyClass, function( cls ) {
316                         if ( cls ) {
317                                 dom.addClass( doc.body, cls );
318                         }
319                 });
320
321                 // Remove invalid parent paragraphs when inserting HTML
322                 // TODO: still needed?
323                 editor.on( 'BeforeSetContent', function( e ) {
324                         if ( e.content ) {
325                                 e.content = e.content.replace(/<p>\s*<(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre|address)( [^>]*)?>/gi, '<$1$2>');
326                                 e.content = e.content.replace(/<\/(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre|address)>\s*<\/p>/gi, '</$1>');
327                         }
328                 });
329
330                 if ( typeof window.jQuery !== 'undefined' ) {
331                         window.jQuery( document ).triggerHandler( 'tinymce-editor-init', [editor] );
332                 }
333
334                 if ( window.tinyMCEPreInit && window.tinyMCEPreInit.dragDropUpload ) {
335                         dom.bind( doc, 'dragstart dragend dragover drop', function( event ) {
336                                 if ( typeof window.jQuery !== 'undefined' ) {
337                                         // Trigger the jQuery handlers.
338                                         window.jQuery( document ).trigger( new window.jQuery.Event( event ) );
339                                 }
340                         });
341                 }
342
343                 if ( editor.getParam( 'wp_paste_filters', true ) ) {
344                         if ( ! tinymce.Env.webkit ) {
345                                 // In WebKit handled by removeWebKitStyles()
346                                 editor.on( 'PastePreProcess', function( event ) {
347                                         // Remove all inline styles
348                                         event.content = event.content.replace( /(<[^>]+) style="[^"]*"([^>]*>)/gi, '$1$2' );
349
350                                         // Put back the internal styles
351                                         event.content = event.content.replace(/(<[^>]+) data-mce-style=([^>]+>)/gi, '$1 style=$2' );
352                                 });
353                         }
354
355                         editor.on( 'PastePostProcess', function( event ) {
356                                 // Remove empty paragraphs
357                                 each( dom.select( 'p', event.node ), function( node ) {
358                                         if ( dom.isEmpty( node ) ) {
359                                                 dom.remove( node );
360                                         }
361                                 });
362                         });
363                 }
364         });
365
366         // Word count
367         if ( typeof window.jQuery !== 'undefined' ) {
368                 editor.on( 'keyup', function( e ) {
369                         var key = e.keyCode || e.charCode;
370
371                         if ( key === last ) {
372                                 return;
373                         }
374
375                         if ( 13 === key || 8 === last || 46 === last ) {
376                                 window.jQuery( document ).triggerHandler( 'wpcountwords', [ editor.getContent({ format : 'raw' }) ] );
377                         }
378
379                         last = key;
380                 });
381         }
382
383         editor.on( 'SaveContent', function( e ) {
384                 // If editor is hidden, we just want the textarea's value to be saved
385                 if ( ! editor.inline && editor.isHidden() ) {
386                         e.content = e.element.value;
387                         return;
388                 }
389
390                 // Keep empty paragraphs :(
391                 e.content = e.content.replace( /<p>(?:<br ?\/?>|\u00a0|\uFEFF| )*<\/p>/g, '<p>&nbsp;</p>' );
392
393                 if ( editor.getParam( 'wpautop', true ) && typeof window.switchEditors !== 'undefined' ) {
394                         e.content = window.switchEditors.pre_wpautop( e.content );
395                 }
396         });
397
398         // Remove spaces from empty paragraphs.
399         editor.on( 'BeforeSetContent', function( event ) {
400                 var paragraph = tinymce.Env.webkit ? '<p><br /></p>' : '<p></p>';
401
402                 if ( event.content ) {
403                         event.content = event.content.replace( /<p>(?:&nbsp;|\u00a0|\uFEFF|\s)+<\/p>/gi, paragraph );
404                 }
405         });
406
407         editor.on( 'preInit', function() {
408                 // Don't replace <i> with <em> and <b> with <strong> and don't remove them when empty
409                 editor.schema.addValidElements( '@[id|accesskey|class|dir|lang|style|tabindex|title|contenteditable|draggable|dropzone|hidden|spellcheck|translate],i,b' );
410
411                 if ( tinymce.Env.iOS ) {
412                         editor.settings.height = 300;
413                 }
414
415                 each( {
416                         c: 'JustifyCenter',
417                         r: 'JustifyRight',
418                         l: 'JustifyLeft',
419                         j: 'JustifyFull',
420                         q: 'mceBlockQuote',
421                         u: 'InsertUnorderedList',
422                         o: 'InsertOrderedList',
423                         s: 'unlink',
424                         m: 'WP_Medialib',
425                         z: 'WP_Adv',
426                         t: 'WP_More',
427                         d: 'Strikethrough',
428                         h: 'WP_Help',
429                         p: 'WP_Page',
430                         x: 'WP_Code'
431                 }, function( command, key ) {
432                         editor.shortcuts.add( 'access+' + key, '', command );
433                 } );
434
435                 editor.addShortcut( 'ctrl+s', '', function() {
436                         if ( typeof wp !== 'undefined' && wp.autosave ) {
437                                 wp.autosave.server.triggerSave();
438                         }
439                 } );
440         } );
441
442         /**
443          * Experimental: create a floating toolbar.
444          * This functionality will change in the next releases. Not recommended for use by plugins.
445          */
446         ( function() {
447                 var Factory = tinymce.ui.Factory,
448                         settings = editor.settings,
449                         currentToolbar,
450                         currentSelection;
451
452                 function create( buttons ) {
453                         var toolbar,
454                                 toolbarItems = [],
455                                 buttonGroup;
456
457                         each( buttons, function( item ) {
458                                 var itemName;
459
460                                 function bindSelectorChanged() {
461                                         var selection = editor.selection;
462
463                                         if ( itemName === 'bullist' ) {
464                                                 selection.selectorChanged( 'ul > li', function( state, args ) {
465                                                         var i = args.parents.length,
466                                                                 nodeName;
467
468                                                         while ( i-- ) {
469                                                                 nodeName = args.parents[ i ].nodeName;
470
471                                                                 if ( nodeName === 'OL' || nodeName == 'UL' ) {
472                                                                         break;
473                                                                 }
474                                                         }
475
476                                                         item.active( state && nodeName === 'UL' );
477                                                 } );
478                                         }
479
480                                         if ( itemName === 'numlist' ) {
481                                                 selection.selectorChanged( 'ol > li', function( state, args ) {
482                                                         var i = args.parents.length,
483                                                                 nodeName;
484
485                                                         while ( i-- ) {
486                                                                 nodeName = args.parents[ i ].nodeName;
487
488                                                                 if ( nodeName === 'OL' || nodeName === 'UL' ) {
489                                                                         break;
490                                                                 }
491                                                         }
492
493                                                         item.active( state && nodeName === 'OL' );
494                                                 } );
495                                         }
496
497                                         if ( item.settings.stateSelector ) {
498                                                 selection.selectorChanged( item.settings.stateSelector, function( state ) {
499                                                         item.active( state );
500                                                 }, true );
501                                         }
502
503                                         if ( item.settings.disabledStateSelector ) {
504                                                 selection.selectorChanged( item.settings.disabledStateSelector, function( state ) {
505                                                         item.disabled( state );
506                                                 } );
507                                         }
508                                 }
509
510                                 if ( item === '|' ) {
511                                         buttonGroup = null;
512                                 } else {
513                                         if ( Factory.has( item ) ) {
514                                                 item = {
515                                                         type: item
516                                                 };
517
518                                                 if ( settings.toolbar_items_size ) {
519                                                         item.size = settings.toolbar_items_size;
520                                                 }
521
522                                                 toolbarItems.push( item );
523
524                                                 buttonGroup = null;
525                                         } else {
526                                                 if ( ! buttonGroup ) {
527                                                         buttonGroup = {
528                                                                 type: 'buttongroup',
529                                                                 items: []
530                                                         };
531
532                                                         toolbarItems.push( buttonGroup );
533                                                 }
534
535                                                 if ( editor.buttons[ item ] ) {
536                                                         itemName = item;
537                                                         item = editor.buttons[ itemName ];
538
539                                                         if ( typeof item === 'function' ) {
540                                                                 item = item();
541                                                         }
542
543                                                         item.type = item.type || 'button';
544
545                                                         if ( settings.toolbar_items_size ) {
546                                                                 item.size = settings.toolbar_items_size;
547                                                         }
548
549                                                         item = Factory.create( item );
550
551                                                         buttonGroup.items.push( item );
552
553                                                         if ( editor.initialized ) {
554                                                                 bindSelectorChanged();
555                                                         } else {
556                                                                 editor.on( 'init', bindSelectorChanged );
557                                                         }
558                                                 }
559                                         }
560                                 }
561                         } );
562
563                         toolbar = Factory.create( {
564                                 type: 'panel',
565                                 layout: 'stack',
566                                 classes: 'toolbar-grp inline-toolbar-grp',
567                                 ariaRoot: true,
568                                 ariaRemember: true,
569                                 items: [ {
570                                         type: 'toolbar',
571                                         layout: 'flow',
572                                         items: toolbarItems
573                                 } ]
574                         } );
575
576                         function hide() {
577                                 toolbar.hide();
578                         }
579
580                         function reposition() {
581                                 var top, left, minTop, className,
582                                         windowPos, adminbar, mceToolbar, boundary,
583                                         boundaryMiddle, boundaryVerticalMiddle, spaceTop,
584                                         spaceBottom, windowWidth, toolbarWidth, toolbarHalf,
585                                         iframe, iframePos, iframeWidth, iframeHeigth,
586                                         toolbarNodeHeight, verticalSpaceNeeded,
587                                         toolbarNode = this.getEl(),
588                                         buffer = 5,
589                                         margin = 8,
590                                         adminbarHeight = 0;
591
592                                 if ( ! currentSelection ) {
593                                         return;
594                                 }
595
596                                 windowPos = window.pageYOffset || document.documentElement.scrollTop;
597                                 adminbar = tinymce.$( '#wpadminbar' )[0];
598                                 mceToolbar = tinymce.$( '.mce-toolbar-grp', editor.getContainer() )[0];
599                                 boundary = currentSelection.getBoundingClientRect();
600                                 boundaryMiddle = ( boundary.left + boundary.right ) / 2;
601                                 boundaryVerticalMiddle = ( boundary.top + boundary.bottom ) / 2;
602                                 spaceTop = boundary.top;
603                                 spaceBottom = iframeHeigth - boundary.bottom;
604                                 windowWidth = window.innerWidth;
605                                 toolbarWidth = toolbarNode.offsetWidth;
606                                 toolbarHalf = toolbarWidth / 2;
607                                 iframe = document.getElementById( editor.id + '_ifr' );
608                                 iframePos = DOM.getPos( iframe );
609                                 iframeWidth = iframe.offsetWidth;
610                                 iframeHeigth = iframe.offsetHeight;
611                                 toolbarNodeHeight = toolbarNode.offsetHeight;
612                                 verticalSpaceNeeded = toolbarNodeHeight + margin + buffer;
613
614                                 if ( spaceTop >= verticalSpaceNeeded ) {
615                                         className = ' mce-arrow-down';
616                                         top = boundary.top + iframePos.y - toolbarNodeHeight - margin;
617                                 } else if ( spaceBottom >= verticalSpaceNeeded ) {
618                                         className = ' mce-arrow-up';
619                                         top = boundary.bottom + iframePos.y;
620                                 } else {
621                                         top = buffer;
622
623                                         if ( boundaryVerticalMiddle >= verticalSpaceNeeded ) {
624                                                 className = ' mce-arrow-down';
625                                         } else {
626                                                 className = ' mce-arrow-up';
627                                         }
628                                 }
629
630                                 // Make sure the image toolbar is below the main toolbar.
631                                 if ( mceToolbar ) {
632                                         minTop = DOM.getPos( mceToolbar ).y + mceToolbar.clientHeight;
633                                 } else {
634                                         minTop = iframePos.y;
635                                 }
636
637                                 // Make sure the image toolbar is below the adminbar (if visible) or below the top of the window.
638                                 if ( windowPos ) {
639                                         if ( adminbar && adminbar.getBoundingClientRect().top === 0 ) {
640                                                 adminbarHeight = adminbar.clientHeight;
641                                         }
642
643                                         if ( windowPos + adminbarHeight > minTop ) {
644                                                 minTop = windowPos + adminbarHeight;
645                                         }
646                                 }
647
648                                 if ( top && minTop && ( minTop + buffer > top ) ) {
649                                         top = minTop + buffer;
650                                         className = '';
651                                 }
652
653                                 left = boundaryMiddle - toolbarHalf;
654                                 left += iframePos.x;
655
656                                 if ( boundary.left < 0 || boundary.right > iframeWidth ) {
657                                         left = iframePos.x + ( iframeWidth - toolbarWidth ) / 2;
658                                 } else if ( toolbarWidth >= windowWidth ) {
659                                         className += ' mce-arrow-full';
660                                         left = 0;
661                                 } else if ( ( left < 0 && boundary.left + toolbarWidth > windowWidth ) ||
662                                         ( left + toolbarWidth > windowWidth && boundary.right - toolbarWidth < 0 ) ) {
663
664                                         left = ( windowWidth - toolbarWidth ) / 2;
665                                 } else if ( left < iframePos.x ) {
666                                         className += ' mce-arrow-left';
667                                         left = boundary.left + iframePos.x;
668                                 } else if ( left + toolbarWidth > iframeWidth + iframePos.x ) {
669                                         className += ' mce-arrow-right';
670                                         left = boundary.right - toolbarWidth + iframePos.x;
671                                 }
672
673                                 toolbarNode.className = toolbarNode.className.replace( / ?mce-arrow-[\w]+/g, '' );
674                                 toolbarNode.className += className;
675
676                                 DOM.setStyles( toolbarNode, { 'left': left, 'top': top } );
677
678                                 return this;
679                         }
680
681                         toolbar.on( 'show', function() {
682                                 currentToolbar = this;
683                                 this.reposition();
684                         } );
685
686                         toolbar.on( 'hide', function() {
687                                 currentToolbar = false;
688                         } );
689
690                         toolbar.on( 'keydown', function( event ) {
691                                 if ( event.keyCode === 27 ) {
692                                         this.hide();
693                                         editor.focus();
694                                 }
695                         } );
696
697                         toolbar.on( 'remove', function() {
698                                 DOM.unbind( window, 'resize scroll', hide );
699                                 editor.dom.unbind( editor.getWin(), 'resize scroll', hide );
700                                 editor.off( 'blur hide', hide );
701                         } );
702
703                         editor.once( 'init', function() {
704                                 DOM.bind( window, 'resize scroll', hide );
705                                 editor.dom.bind( editor.getWin(), 'resize scroll', hide );
706                                 editor.on( 'blur hide', hide );
707                         } );
708
709                         toolbar.reposition = reposition;
710                         toolbar.hide().renderTo( document.body );
711
712                         return toolbar;
713                 }
714
715                 editor.shortcuts.add( 'alt+119', '', function() {
716                         var node;
717
718                         if ( currentToolbar ) {
719                                 node = currentToolbar.find( 'toolbar' )[0];
720                                 node && node.focus( true );
721                         }
722                 } );
723
724                 editor.on( 'nodechange', function( event ) {
725                         var collapsed = editor.selection.isCollapsed();
726
727                         var args = {
728                                 element: event.element,
729                                 parents: event.parents,
730                                 collapsed: collapsed
731                         };
732
733                         editor.fire( 'wptoolbar', args );
734
735                         currentSelection = args.selection || args.element;
736
737                         currentToolbar && currentToolbar.hide();
738                         args.toolbar && args.toolbar.show();
739                 } );
740
741                 editor.wp = editor.wp || {};
742                 editor.wp._createToolbar = create;
743         }());
744
745         function noop() {}
746
747         // Expose some functions (back-compat)
748         return {
749                 _showButtons: noop,
750                 _hideButtons: noop,
751                 _setEmbed: noop,
752                 _getEmbed: noop
753         };
754 });