wp/wp-includes/js/tinymce/plugins/wordpress/plugin.js
changeset 5 5e2f62d02dcd
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
       
     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( 'meta+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 });