wp/wp-includes/class-wp-editor.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
    23 	private static $has_tinymce = false;
    23 	private static $has_tinymce = false;
    24 	private static $has_quicktags = false;
    24 	private static $has_quicktags = false;
    25 	private static $has_medialib = false;
    25 	private static $has_medialib = false;
    26 	private static $editor_buttons_css = true;
    26 	private static $editor_buttons_css = true;
    27 	private static $drag_drop_upload = false;
    27 	private static $drag_drop_upload = false;
       
    28 	private static $old_dfw_compat = false;
       
    29 	private static $translation;
       
    30 	private static $tinymce_scripts_printed = false;
       
    31 	private static $link_dialog_printed = false;
    28 
    32 
    29 	private function __construct() {}
    33 	private function __construct() {}
    30 
    34 
    31 	/**
    35 	/**
    32 	 * Parse default arguments for the editor instance.
    36 	 * Parse default arguments for the editor instance.
    33 	 *
    37 	 *
       
    38 	 * @static
    34 	 * @param string $editor_id ID for the current editor instance.
    39 	 * @param string $editor_id ID for the current editor instance.
    35 	 * @param array  $settings {
    40 	 * @param array  $settings {
    36 	 *     Array of editor arguments.
    41 	 *     Array of editor arguments.
    37 	 *
    42 	 *
    38 	 *     @type bool       $wpautop           Whether to use wpautop(). Default true.
    43 	 *     @type bool       $wpautop           Whether to use wpautop(). Default true.
    44 	 *     @type string     $textarea_name     Give the textarea a unique name here. Square brackets
    49 	 *     @type string     $textarea_name     Give the textarea a unique name here. Square brackets
    45 	 *                                         can be used here. Default $editor_id.
    50 	 *                                         can be used here. Default $editor_id.
    46 	 *     @type int        $textarea_rows     Number rows in the editor textarea. Default 20.
    51 	 *     @type int        $textarea_rows     Number rows in the editor textarea. Default 20.
    47 	 *     @type string|int $tabindex          Tabindex value to use. Default empty.
    52 	 *     @type string|int $tabindex          Tabindex value to use. Default empty.
    48 	 *     @type string     $tabfocus_elements The previous and next element ID to move the focus to
    53 	 *     @type string     $tabfocus_elements The previous and next element ID to move the focus to
    49 	 *                                         when pressing the Tab key in TinyMCE. Defualt ':prev,:next'.
    54 	 *                                         when pressing the Tab key in TinyMCE. Default ':prev,:next'.
    50 	 *     @type string     $editor_css        Intended for extra styles for both Visual and Text editors.
    55 	 *     @type string     $editor_css        Intended for extra styles for both Visual and Text editors.
    51 	 *                                         Should include `<style>` tags, and can use "scoped". Default empty.
    56 	 *                                         Should include `<style>` tags, and can use "scoped". Default empty.
    52 	 *     @type string     $editor_class      Extra classes to add to the editor textarea elemen. Default empty.
    57 	 *     @type string     $editor_class      Extra classes to add to the editor textarea element. Default empty.
    53 	 *     @type bool       $teeny             Whether to output the minimal editor config. Examples include
    58 	 *     @type bool       $teeny             Whether to output the minimal editor config. Examples include
    54 	 *                                         Press This and the Comment editor. Default false.
    59 	 *                                         Press This and the Comment editor. Default false.
    55 	 *     @type bool       $dfw               Whether to replace the default fullscreen with "Distraction Free
    60 	 *     @type bool       $dfw               Deprecated in 4.1. Since 4.3 used only to enqueue wp-fullscreen-stub.js
    56 	 *                                         Writing". DFW requires specific DOM elements and css). Default false.
    61 	 *                                         for backward compatibility.
    57 	 *     @type bool|array $tinymce           Whether to load TinyMCE. Can be used to pass settings directly to
    62 	 *     @type bool|array $tinymce           Whether to load TinyMCE. Can be used to pass settings directly to
    58 	 *                                         TinyMCE using an array. Default true.
    63 	 *                                         TinyMCE using an array. Default true.
    59 	 *     @type bool|array $quicktags         Whether to load Quicktags. Can be used to pass settings directly to
    64 	 *     @type bool|array $quicktags         Whether to load Quicktags. Can be used to pass settings directly to
    60 	 *                                         Quicktags using an array. Default true.
    65 	 *                                         Quicktags using an array. Default true.
    61 	 * }
    66 	 * }
    62 	 * @return array Parsed arguments array.
    67 	 * @return array Parsed arguments array.
    63 	 */
    68 	 */
    64 	public static function parse_settings( $editor_id, $settings ) {
    69 	public static function parse_settings( $editor_id, $settings ) {
    65 
    70 
    66 		/**
    71 		/**
    67 		 * Filter the wp_editor() settings.
    72 		 * Filters the wp_editor() settings.
    68 		 *
    73 		 *
    69 		 * @since 4.0.0
    74 		 * @since 4.0.0
    70 		 *
    75 		 *
    71 		 * @see _WP_Editors()::parse_settings()
    76 		 * @see _WP_Editors()::parse_settings()
    72 		 *
    77 		 *
    96 		self::$this_tinymce = ( $set['tinymce'] && user_can_richedit() );
   101 		self::$this_tinymce = ( $set['tinymce'] && user_can_richedit() );
    97 
   102 
    98 		if ( self::$this_tinymce ) {
   103 		if ( self::$this_tinymce ) {
    99 			if ( false !== strpos( $editor_id, '[' ) ) {
   104 			if ( false !== strpos( $editor_id, '[' ) ) {
   100 				self::$this_tinymce = false;
   105 				self::$this_tinymce = false;
   101 				_deprecated_argument( 'wp_editor()', '3.9', 'TinyMCE editor IDs cannot have brackets.' );
   106 				_deprecated_argument( 'wp_editor()', '3.9.0', 'TinyMCE editor IDs cannot have brackets.' );
   102 			}
   107 			}
   103 		}
   108 		}
   104 
   109 
   105 		self::$this_quicktags = (bool) $set['quicktags'];
   110 		self::$this_quicktags = (bool) $set['quicktags'];
   106 
   111 
   107 		if ( self::$this_tinymce )
   112 		if ( self::$this_tinymce )
   108 			self::$has_tinymce = true;
   113 			self::$has_tinymce = true;
   109 
   114 
   110 		if ( self::$this_quicktags )
   115 		if ( self::$this_quicktags )
   111 			self::$has_quicktags = true;
   116 			self::$has_quicktags = true;
       
   117 
       
   118 		if ( $set['dfw'] ) {
       
   119 			self::$old_dfw_compat = true;
       
   120 		}
   112 
   121 
   113 		if ( empty( $set['editor_height'] ) )
   122 		if ( empty( $set['editor_height'] ) )
   114 			return $set;
   123 			return $set;
   115 
   124 
   116 		if ( 'content' === $editor_id && empty( $set['tinymce']['wp_autoresize_on'] ) ) {
   125 		if ( 'content' === $editor_id && empty( $set['tinymce']['wp_autoresize_on'] ) ) {
   130 	}
   139 	}
   131 
   140 
   132 	/**
   141 	/**
   133 	 * Outputs the HTML for a single instance of the editor.
   142 	 * Outputs the HTML for a single instance of the editor.
   134 	 *
   143 	 *
       
   144 	 * @static
   135 	 * @param string $content The initial content of the editor.
   145 	 * @param string $content The initial content of the editor.
   136 	 * @param string $editor_id ID for the textarea and TinyMCE and Quicktags instances (can contain only ASCII letters and numbers).
   146 	 * @param string $editor_id ID for the textarea and TinyMCE and Quicktags instances (can contain only ASCII letters and numbers).
   137 	 * @param array $settings See the _parse_settings() method for description.
   147 	 * @param array $settings See _WP_Editors()::parse_settings() for description.
   138 	 */
   148 	 */
   139 	public static function editor( $content, $editor_id, $settings = array() ) {
   149 	public static function editor( $content, $editor_id, $settings = array() ) {
   140 
       
   141 		$set = self::parse_settings( $editor_id, $settings );
   150 		$set = self::parse_settings( $editor_id, $settings );
   142 		$editor_class = ' class="' . trim( $set['editor_class'] . ' wp-editor-area' ) . '"';
   151 		$editor_class = ' class="' . trim( esc_attr( $set['editor_class'] ) . ' wp-editor-area' ) . '"';
   143 		$tabindex = $set['tabindex'] ? ' tabindex="' . (int) $set['tabindex'] . '"' : '';
   152 		$tabindex = $set['tabindex'] ? ' tabindex="' . (int) $set['tabindex'] . '"' : '';
   144 		$switch_class = 'html-active';
   153 		$default_editor = 'html';
   145 		$toolbar = $buttons = $autocomplete = '';
   154 		$buttons = $autocomplete = '';
       
   155 		$editor_id_attr = esc_attr( $editor_id );
   146 
   156 
   147 		if ( $set['drag_drop_upload'] ) {
   157 		if ( $set['drag_drop_upload'] ) {
   148 			self::$drag_drop_upload = true;
   158 			self::$drag_drop_upload = true;
   149 		}
   159 		}
   150 
   160 
   151 		if ( ! empty( $set['editor_height'] ) )
   161 		if ( ! empty( $set['editor_height'] ) ) {
   152 			$height = ' style="height: ' . $set['editor_height'] . 'px"';
   162 			$height = ' style="height: ' . (int) $set['editor_height'] . 'px"';
   153 		else
   163 		} else {
   154 			$height = ' rows="' . $set['textarea_rows'] . '"';
   164 			$height = ' rows="' . (int) $set['textarea_rows'] . '"';
   155 
   165 		}
   156 		if ( !current_user_can( 'upload_files' ) )
   166 
       
   167 		if ( ! current_user_can( 'upload_files' ) ) {
   157 			$set['media_buttons'] = false;
   168 			$set['media_buttons'] = false;
   158 
   169 		}
   159 		if ( ! self::$this_quicktags && self::$this_tinymce ) {
   170 
   160 			$switch_class = 'tmce-active';
   171 		if ( self::$this_tinymce ) {
   161 			$autocomplete = ' autocomplete="off"';
   172 			$autocomplete = ' autocomplete="off"';
   162 		} elseif ( self::$this_quicktags && self::$this_tinymce ) {
   173 
   163 			$default_editor = $set['default_editor'] ? $set['default_editor'] : wp_default_editor();
   174 			if ( self::$this_quicktags ) {
   164 			$autocomplete = ' autocomplete="off"';
   175 				$default_editor = $set['default_editor'] ? $set['default_editor'] : wp_default_editor();
   165 
   176 				// 'html' is used for the "Text" editor tab.
   166 			// 'html' is used for the "Text" editor tab.
   177 				if ( 'html' !== $default_editor ) {
   167 			if ( 'html' === $default_editor ) {
   178 					$default_editor = 'tinymce';
   168 				add_filter('the_editor_content', 'wp_htmledit_pre');
   179 				}
   169 				$switch_class = 'html-active';
   180 
       
   181 				$buttons .= '<button type="button" id="' . $editor_id_attr . '-tmce" class="wp-switch-editor switch-tmce"' .
       
   182 					' data-wp-editor-id="' . $editor_id_attr . '">' . _x( 'Visual', 'Name for the Visual editor tab' ) . "</button>\n";
       
   183 				$buttons .= '<button type="button" id="' . $editor_id_attr . '-html" class="wp-switch-editor switch-html"' .
       
   184 					' data-wp-editor-id="' . $editor_id_attr . '">' . _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ) . "</button>\n";
   170 			} else {
   185 			} else {
   171 				add_filter('the_editor_content', 'wp_richedit_pre');
   186 				$default_editor = 'tinymce';
   172 				$switch_class = 'tmce-active';
   187 			}
   173 			}
   188 		}
   174 
   189 
   175 			$buttons .= '<button type="button" id="' . $editor_id . '-tmce" class="wp-switch-editor switch-tmce" onclick="switchEditors.switchto(this);">' . __('Visual') . "</button>\n";
   190 		$switch_class = 'html' === $default_editor ? 'html-active' : 'tmce-active';
   176 			$buttons .= '<button type="button" id="' . $editor_id . '-html" class="wp-switch-editor switch-html" onclick="switchEditors.switchto(this);">' . _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ) . "</button>\n";
       
   177 		}
       
   178 
       
   179 		$wrap_class = 'wp-core-ui wp-editor-wrap ' . $switch_class;
   191 		$wrap_class = 'wp-core-ui wp-editor-wrap ' . $switch_class;
   180 
   192 
   181 		if ( $set['_content_editor_dfw'] ) {
   193 		if ( $set['_content_editor_dfw'] ) {
   182 			$wrap_class .= ' has-dfw';
   194 			$wrap_class .= ' has-dfw';
   183 		}
   195 		}
   184 
   196 
   185 		echo '<div id="wp-' . $editor_id . '-wrap" class="' . $wrap_class . '">';
   197 		echo '<div id="wp-' . $editor_id_attr . '-wrap" class="' . $wrap_class . '">';
   186 
   198 
   187 		if ( self::$editor_buttons_css ) {
   199 		if ( self::$editor_buttons_css ) {
   188 			wp_print_styles('editor-buttons');
   200 			wp_print_styles( 'editor-buttons' );
   189 			self::$editor_buttons_css = false;
   201 			self::$editor_buttons_css = false;
   190 		}
   202 		}
   191 
   203 
   192 		if ( !empty($set['editor_css']) )
   204 		if ( ! empty( $set['editor_css'] ) ) {
   193 			echo $set['editor_css'] . "\n";
   205 			echo $set['editor_css'] . "\n";
   194 
   206 		}
   195 		if ( !empty($buttons) || $set['media_buttons'] ) {
   207 
   196 			echo '<div id="wp-' . $editor_id . '-editor-tools" class="wp-editor-tools hide-if-no-js">';
   208 		if ( ! empty( $buttons ) || $set['media_buttons'] ) {
       
   209 			echo '<div id="wp-' . $editor_id_attr . '-editor-tools" class="wp-editor-tools hide-if-no-js">';
   197 
   210 
   198 			if ( $set['media_buttons'] ) {
   211 			if ( $set['media_buttons'] ) {
   199 				self::$has_medialib = true;
   212 				self::$has_medialib = true;
   200 
   213 
   201 				if ( !function_exists('media_buttons') )
   214 				if ( ! function_exists( 'media_buttons' ) )
   202 					include(ABSPATH . 'wp-admin/includes/media.php');
   215 					include( ABSPATH . 'wp-admin/includes/media.php' );
   203 
   216 
   204 				echo '<div id="wp-' . $editor_id . '-media-buttons" class="wp-media-buttons">';
   217 				echo '<div id="wp-' . $editor_id_attr . '-media-buttons" class="wp-media-buttons">';
   205 
   218 
   206 				/**
   219 				/**
   207 				 * Fires after the default media button(s) are displayed.
   220 				 * Fires after the default media button(s) are displayed.
   208 				 *
   221 				 *
   209 				 * @since 2.5.0
   222 				 * @since 2.5.0
   216 
   229 
   217 			echo '<div class="wp-editor-tabs">' . $buttons . "</div>\n";
   230 			echo '<div class="wp-editor-tabs">' . $buttons . "</div>\n";
   218 			echo "</div>\n";
   231 			echo "</div>\n";
   219 		}
   232 		}
   220 
   233 
       
   234 		$quicktags_toolbar = '';
       
   235 
       
   236 		if ( self::$this_quicktags ) {
       
   237 			if ( 'content' === $editor_id && ! empty( $GLOBALS['current_screen'] ) && $GLOBALS['current_screen']->base === 'post' ) {
       
   238 				$toolbar_id = 'ed_toolbar';
       
   239 			} else {
       
   240 				$toolbar_id = 'qt_' . $editor_id_attr . '_toolbar';
       
   241 			}
       
   242 
       
   243 			$quicktags_toolbar = '<div id="' . $toolbar_id . '" class="quicktags-toolbar"></div>';
       
   244 		}
       
   245 
   221 		/**
   246 		/**
   222 		 * Filter the HTML markup output that displays the editor.
   247 		 * Filters the HTML markup output that displays the editor.
   223 		 *
   248 		 *
   224 		 * @since 2.1.0
   249 		 * @since 2.1.0
   225 		 *
   250 		 *
   226 		 * @param string $output Editor's HTML markup.
   251 		 * @param string $output Editor's HTML markup.
   227 		 */
   252 		 */
   228 		$the_editor = apply_filters( 'the_editor', '<div id="wp-' . $editor_id . '-editor-container" class="wp-editor-container">' .
   253 		$the_editor = apply_filters( 'the_editor', '<div id="wp-' . $editor_id_attr . '-editor-container" class="wp-editor-container">' .
   229 			'<textarea' . $editor_class . $height . $tabindex . $autocomplete . ' cols="40" name="' . $set['textarea_name'] . '" ' .
   254 			$quicktags_toolbar .
   230 			'id="' . $editor_id . '">%s</textarea></div>' );
   255 			'<textarea' . $editor_class . $height . $tabindex . $autocomplete . ' cols="40" name="' . esc_attr( $set['textarea_name'] ) . '" ' .
       
   256 			'id="' . $editor_id_attr . '">%s</textarea></div>' );
       
   257 
       
   258 		// Prepare the content for the Visual or Text editor, only when TinyMCE is used (back-compat).
       
   259 		if ( self::$this_tinymce ) {
       
   260 			add_filter( 'the_editor_content', 'format_for_editor', 10, 2 );
       
   261 		}
   231 
   262 
   232 		/**
   263 		/**
   233 		 * Filter the default editor content.
   264 		 * Filters the default editor content.
   234 		 *
   265 		 *
   235 		 * @since 2.1.0
   266 		 * @since 2.1.0
   236 		 *
   267 		 *
   237 		 * @param string $content Default editor content.
   268 		 * @param string $content        Default editor content.
       
   269 		 * @param string $default_editor The default editor for the current user.
       
   270 		 *                               Either 'html' or 'tinymce'.
   238 		 */
   271 		 */
   239 		$content = apply_filters( 'the_editor_content', $content );
   272 		$content = apply_filters( 'the_editor_content', $content, $default_editor );
       
   273 
       
   274 		// Remove the filter as the next editor on the same page may not need it.
       
   275 		if ( self::$this_tinymce ) {
       
   276 			remove_filter( 'the_editor_content', 'format_for_editor' );
       
   277 		}
       
   278 
       
   279 		// Back-compat for the `htmledit_pre` and `richedit_pre` filters
       
   280 		if ( 'html' === $default_editor && has_filter( 'htmledit_pre' ) ) {
       
   281 			/** This filter is documented in wp-includes/deprecated.php */
       
   282 			$content = apply_filters_deprecated( 'htmledit_pre', array( $content ), '4.3.0', 'format_for_editor' );
       
   283 		} elseif ( 'tinymce' === $default_editor && has_filter( 'richedit_pre' ) ) {
       
   284 			/** This filter is documented in wp-includes/deprecated.php */
       
   285 			$content = apply_filters_deprecated( 'richedit_pre', array( $content ), '4.3.0', 'format_for_editor' );
       
   286 		}
       
   287 
       
   288 		if ( false !== stripos( $content, 'textarea' ) ) {
       
   289 			$content = preg_replace( '%</textarea%i', '&lt;/textarea', $content );
       
   290 		}
   240 
   291 
   241 		printf( $the_editor, $content );
   292 		printf( $the_editor, $content );
   242 		echo "\n</div>\n\n";
   293 		echo "\n</div>\n\n";
   243 
   294 
   244 		self::editor_settings($editor_id, $set);
   295 		self::editor_settings( $editor_id, $set );
   245 	}
   296 	}
   246 
   297 
   247 	/**
   298 	/**
       
   299 	 * @static
       
   300 	 *
       
   301 	 * @global string $tinymce_version
       
   302 	 *
   248 	 * @param string $editor_id
   303 	 * @param string $editor_id
   249 	 * @param array  $set
   304 	 * @param array  $set
   250 	 */
   305 	 */
   251 	public static function editor_settings($editor_id, $set) {
   306 	public static function editor_settings($editor_id, $set) {
   252 		$first_run = false;
   307 		global $tinymce_version;
   253 
   308 
   254 		if ( empty(self::$first_init) ) {
   309 		if ( empty(self::$first_init) ) {
   255 			if ( is_admin() ) {
   310 			if ( is_admin() ) {
   256 				add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_js' ), 50 );
   311 				add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_js' ), 50 );
   257 				add_action( 'admin_print_footer_scripts', array( __CLASS__, 'enqueue_scripts' ), 1 );
   312 				add_action( 'admin_print_footer_scripts', array( __CLASS__, 'enqueue_scripts' ), 1 );
   272 				$qtInit = array_merge($qtInit, $set['quicktags']);
   327 				$qtInit = array_merge($qtInit, $set['quicktags']);
   273 
   328 
   274 			if ( empty($qtInit['buttons']) )
   329 			if ( empty($qtInit['buttons']) )
   275 				$qtInit['buttons'] = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close';
   330 				$qtInit['buttons'] = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close';
   276 
   331 
   277 			if ( $set['dfw'] )
       
   278 				$qtInit['buttons'] .= ',fullscreen';
       
   279 
       
   280 			if ( $set['_content_editor_dfw'] ) {
   332 			if ( $set['_content_editor_dfw'] ) {
   281 				$qtInit['buttons'] .= ',dfw';
   333 				$qtInit['buttons'] .= ',dfw';
   282 			}
   334 			}
   283 
   335 
   284 			/**
   336 			/**
   285 			 * Filter the Quicktags settings.
   337 			 * Filters the Quicktags settings.
   286 			 *
   338 			 *
   287 			 * @since 3.3.0
   339 			 * @since 3.3.0
   288 			 *
   340 			 *
   289 			 * @param array  $qtInit    Quicktags settings.
   341 			 * @param array  $qtInit    Quicktags settings.
   290 			 * @param string $editor_id The unique editor ID, e.g. 'content'.
   342 			 * @param string $editor_id The unique editor ID, e.g. 'content'.
   297 		}
   349 		}
   298 
   350 
   299 		if ( self::$this_tinymce ) {
   351 		if ( self::$this_tinymce ) {
   300 
   352 
   301 			if ( empty( self::$first_init ) ) {
   353 			if ( empty( self::$first_init ) ) {
   302 				self::$baseurl = includes_url( 'js/tinymce' );
   354 				$baseurl = self::get_baseurl();
   303 
   355 				$mce_locale = self::get_mce_locale();
   304 				$mce_locale = get_locale();
       
   305 				self::$mce_locale = $mce_locale = empty( $mce_locale ) ? 'en' : strtolower( substr( $mce_locale, 0, 2 ) ); // ISO 639-1
       
   306 
       
   307 				/** This filter is documented in wp-admin/includes/media.php */
       
   308 				$no_captions = (bool) apply_filters( 'disable_captions', '' );
       
   309 				$first_run = true;
       
   310 				$ext_plugins = '';
   356 				$ext_plugins = '';
   311 
   357 
   312 				if ( $set['teeny'] ) {
   358 				if ( $set['teeny'] ) {
   313 
   359 
   314 					/**
   360 					/**
   315 					 * Filter the list of teenyMCE plugins.
   361 					 * Filters the list of teenyMCE plugins.
   316 					 *
   362 					 *
   317 					 * @since 2.7.0
   363 					 * @since 2.7.0
   318 					 *
   364 					 *
   319 					 * @param array  $plugins   An array of teenyMCE plugins.
   365 					 * @param array  $plugins   An array of teenyMCE plugins.
   320 					 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   366 					 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   321 					 */
   367 					 */
   322 					self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array( 'colorpicker', 'lists', 'fullscreen', 'image', 'wordpress', 'wpeditimage', 'wplink' ), $editor_id );
   368 					$plugins = apply_filters( 'teeny_mce_plugins', array( 'colorpicker', 'lists', 'fullscreen', 'image', 'wordpress', 'wpeditimage', 'wplink' ), $editor_id );
   323 				} else {
   369 				} else {
   324 
   370 
   325 					/**
   371 					/**
   326 					 * Filter the list of TinyMCE external plugins.
   372 					 * Filters the list of TinyMCE external plugins.
   327 					 *
   373 					 *
   328 					 * The filter takes an associative array of external plugins for
   374 					 * The filter takes an associative array of external plugins for
   329 					 * TinyMCE in the form 'plugin_name' => 'url'.
   375 					 * TinyMCE in the form 'plugin_name' => 'url'.
   330 					 *
   376 					 *
   331 					 * The url should be absolute, and should include the js filename
   377 					 * The url should be absolute, and should include the js filename
   356 						'wpeditimage',
   402 						'wpeditimage',
   357 						'wpemoji',
   403 						'wpemoji',
   358 						'wpgallery',
   404 						'wpgallery',
   359 						'wplink',
   405 						'wplink',
   360 						'wpdialogs',
   406 						'wpdialogs',
       
   407 						'wptextpattern',
   361 						'wpview',
   408 						'wpview',
   362 					);
   409 					);
   363 
   410 
   364 					if ( ! self::$has_medialib ) {
   411 					if ( ! self::$has_medialib ) {
   365 						$plugins[] = 'image';
   412 						$plugins[] = 'image';
   366 					}
   413 					}
   367 
   414 
   368 					/**
   415 					/**
   369 					 * Filter the list of default TinyMCE plugins.
   416 					 * Filters the list of default TinyMCE plugins.
   370 					 *
   417 					 *
   371 					 * The filter specifies which of the default plugins included
   418 					 * The filter specifies which of the default plugins included
   372 					 * in WordPress should be added to the TinyMCE instance.
   419 					 * in WordPress should be added to the TinyMCE instance.
   373 					 *
   420 					 *
   374 					 * @since 3.3.0
   421 					 * @since 3.3.0
   384 					}
   431 					}
   385 
   432 
   386 					if ( ! empty( $mce_external_plugins ) ) {
   433 					if ( ! empty( $mce_external_plugins ) ) {
   387 
   434 
   388 						/**
   435 						/**
   389 						 * Filter the translations loaded for external TinyMCE 3.x plugins.
   436 						 * Filters the translations loaded for external TinyMCE 3.x plugins.
   390 						 *
   437 						 *
   391 						 * The filter takes an associative array ('plugin_name' => 'path')
   438 						 * The filter takes an associative array ('plugin_name' => 'path')
   392 						 * where 'path' is the include path to the file.
   439 						 * where 'path' is the include path to the file.
   393 						 *
   440 						 *
   394 						 * The language file should follow the same format as wp_mce_translation(),
   441 						 * The language file should follow the same format as wp_mce_translation(),
   453 								if ( ! empty( $strings ) )
   500 								if ( ! empty( $strings ) )
   454 									$ext_plugins .= "\n" . $strings . "\n";
   501 									$ext_plugins .= "\n" . $strings . "\n";
   455 							}
   502 							}
   456 
   503 
   457 							$ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
   504 							$ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
   458 							$ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
       
   459 						}
   505 						}
   460 					}
   506 					}
   461 				}
   507 				}
   462 
   508 
   463 				if ( $set['dfw'] )
       
   464 					$plugins[] = 'wpfullscreen';
       
   465 
       
   466 				self::$plugins = $plugins;
   509 				self::$plugins = $plugins;
   467 				self::$ext_plugins = $ext_plugins;
   510 				self::$ext_plugins = $ext_plugins;
   468 
   511 
   469 				self::$first_init = array(
   512 				$settings = self::default_settings();
   470 					'theme' => 'modern',
   513 				$settings['plugins'] = implode( ',', $plugins );
   471 					'skin' => 'lightgray',
       
   472 					'language' => self::$mce_locale,
       
   473 					'formats' => "{
       
   474 						alignleft: [
       
   475 							{selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles: {textAlign:'left'}},
       
   476 							{selector: 'img,table,dl.wp-caption', classes: 'alignleft'}
       
   477 						],
       
   478 						aligncenter: [
       
   479 							{selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles: {textAlign:'center'}},
       
   480 							{selector: 'img,table,dl.wp-caption', classes: 'aligncenter'}
       
   481 						],
       
   482 						alignright: [
       
   483 							{selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles: {textAlign:'right'}},
       
   484 							{selector: 'img,table,dl.wp-caption', classes: 'alignright'}
       
   485 						],
       
   486 						strikethrough: {inline: 'del'}
       
   487 					}",
       
   488 					'relative_urls' => false,
       
   489 					'remove_script_host' => false,
       
   490 					'convert_urls' => false,
       
   491 					'browser_spellcheck' => true,
       
   492 					'fix_list_elements' => true,
       
   493 					'entities' => '38,amp,60,lt,62,gt',
       
   494 					'entity_encoding' => 'raw',
       
   495 					'keep_styles' => false,
       
   496 					'cache_suffix' => 'wp-mce-' . $GLOBALS['tinymce_version'],
       
   497 
       
   498 					// Limit the preview styles in the menu/toolbar
       
   499 					'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
       
   500 
       
   501 					'end_container_on_empty_block' => true,
       
   502 					'wpeditimage_disable_captions' => $no_captions,
       
   503 					'wpeditimage_html5_captions' => current_theme_supports( 'html5', 'caption' ),
       
   504 					'plugins' => implode( ',', $plugins ),
       
   505 				);
       
   506 
   514 
   507 				if ( ! empty( $mce_external_plugins ) ) {
   515 				if ( ! empty( $mce_external_plugins ) ) {
   508 					self::$first_init['external_plugins'] = wp_json_encode( $mce_external_plugins );
   516 					$settings['external_plugins'] = wp_json_encode( $mce_external_plugins );
   509 				}
   517 				}
   510 
   518 
   511 				$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
   519 				/** This filter is documented in wp-admin/includes/media.php */
   512 				$version = 'ver=' . $GLOBALS['wp_version'];
   520 				if ( apply_filters( 'disable_captions', '' ) ) {
   513 				$dashicons = includes_url( "css/dashicons$suffix.css?$version" );
   521 					$settings['wpeditimage_disable_captions'] = true;
   514 
   522 				}
   515 				// WordPress default stylesheet and dashicons
   523 
   516 				$mce_css = array(
   524 				$mce_css = $settings['content_css'];
   517 					$dashicons,
       
   518 					self::$baseurl . '/skins/wordpress/wp-content.css?' . $version
       
   519 				);
       
   520 
       
   521 				$editor_styles = get_editor_stylesheets();
   525 				$editor_styles = get_editor_stylesheets();
       
   526 
   522 				if ( ! empty( $editor_styles ) ) {
   527 				if ( ! empty( $editor_styles ) ) {
   523 					foreach ( $editor_styles as $style ) {
   528 					// Force urlencoding of commas.
   524 						$mce_css[] = $style;
   529 					foreach ( $editor_styles as $key => $url ) {
       
   530 						if ( strpos( $url, ',' ) !== false ) {
       
   531 							$editor_styles[ $key ] = str_replace( ',', '%2C', $url );
       
   532 						}
   525 					}
   533 					}
       
   534 
       
   535 					$mce_css .= ',' . implode( ',', $editor_styles );
   526 				}
   536 				}
   527 
   537 
   528 				/**
   538 				/**
   529 				 * Filter the comma-delimited list of stylesheets to load in TinyMCE.
   539 				 * Filters the comma-delimited list of stylesheets to load in TinyMCE.
   530 				 *
   540 				 *
   531 				 * @since 2.1.0
   541 				 * @since 2.1.0
   532 				 *
   542 				 *
   533 				 * @param array $stylesheets Comma-delimited list of stylesheets.
   543 				 * @param string $stylesheets Comma-delimited list of stylesheets.
   534 				 */
   544 				 */
   535 				$mce_css = trim( apply_filters( 'mce_css', implode( ',', $mce_css ) ), ' ,' );
   545 				$mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
   536 
   546 
   537 				if ( ! empty($mce_css) )
   547 				if ( ! empty( $mce_css ) ) {
   538 					self::$first_init['content_css'] = $mce_css;
   548 					$settings['content_css'] = $mce_css;
       
   549 				} else {
       
   550 					unset( $settings['content_css'] );
       
   551 				}
       
   552 
       
   553 				self::$first_init = $settings;
   539 			}
   554 			}
   540 
   555 
   541 			if ( $set['teeny'] ) {
   556 			if ( $set['teeny'] ) {
   542 
   557 
   543 				/**
   558 				/**
   544 				 * Filter the list of teenyMCE buttons (Text tab).
   559 				 * Filters the list of teenyMCE buttons (Text tab).
   545 				 *
   560 				 *
   546 				 * @since 2.7.0
   561 				 * @since 2.7.0
   547 				 *
   562 				 *
   548 				 * @param array  $buttons   An array of teenyMCE buttons.
   563 				 * @param array  $buttons   An array of teenyMCE buttons.
   549 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   564 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   550 				 */
   565 				 */
   551 				$mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'alignleft', 'aligncenter', 'alignright', 'undo', 'redo', 'link', 'unlink', 'fullscreen'), $editor_id );
   566 				$mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'alignleft', 'aligncenter', 'alignright', 'undo', 'redo', 'link', 'fullscreen'), $editor_id );
   552 				$mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array();
   567 				$mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array();
   553 			} else {
   568 			} else {
   554 				$mce_buttons = array( 'bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'hr', 'alignleft', 'aligncenter', 'alignright', 'link', 'unlink', 'wp_more', 'spellchecker' );
   569 				$mce_buttons = array( 'formatselect', 'bold', 'italic', 'bullist', 'numlist', 'blockquote', 'alignleft', 'aligncenter', 'alignright', 'link', 'wp_more', 'spellchecker' );
   555 
   570 
   556 				if ( $set['_content_editor_dfw'] ) {
   571 				if ( ! wp_is_mobile() ) {
   557 					$mce_buttons[] = 'dfw';
   572 					if ( $set['_content_editor_dfw'] ) {
   558 				} else {
   573 						$mce_buttons[] = 'dfw';
   559 					$mce_buttons[] = 'fullscreen';
   574 					} else {
       
   575 						$mce_buttons[] = 'fullscreen';
       
   576 					}
   560 				}
   577 				}
   561 
   578 
   562 				$mce_buttons[] = 'wp_adv';
   579 				$mce_buttons[] = 'wp_adv';
   563 
   580 
   564 				/**
   581 				/**
   565 				 * Filter the first-row list of TinyMCE buttons (Visual tab).
   582 				 * Filters the first-row list of TinyMCE buttons (Visual tab).
   566 				 *
   583 				 *
   567 				 * @since 2.0.0
   584 				 * @since 2.0.0
   568 				 *
   585 				 *
   569 				 * @param array  $buttons   First-row list of buttons.
   586 				 * @param array  $buttons   First-row list of buttons.
   570 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   587 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   571 				 */
   588 				 */
   572 				$mce_buttons = apply_filters( 'mce_buttons', $mce_buttons, $editor_id );
   589 				$mce_buttons = apply_filters( 'mce_buttons', $mce_buttons, $editor_id );
   573 
   590 
   574 				$mce_buttons_2 = array( 'formatselect', 'underline', 'alignjustify', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo' );
   591 				$mce_buttons_2 = array( 'strikethrough', 'hr', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo' );
   575 
   592 
   576 				if ( ! wp_is_mobile() ) {
   593 				if ( ! wp_is_mobile() ) {
   577 					$mce_buttons_2[] = 'wp_help';
   594 					$mce_buttons_2[] = 'wp_help';
   578 				}
   595 				}
   579 
   596 
   580 				/**
   597 				/**
   581 				 * Filter the second-row list of TinyMCE buttons (Visual tab).
   598 				 * Filters the second-row list of TinyMCE buttons (Visual tab).
   582 				 *
   599 				 *
   583 				 * @since 2.0.0
   600 				 * @since 2.0.0
   584 				 *
   601 				 *
   585 				 * @param array  $buttons   Second-row list of buttons.
   602 				 * @param array  $buttons   Second-row list of buttons.
   586 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   603 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   587 				 */
   604 				 */
   588 				$mce_buttons_2 = apply_filters( 'mce_buttons_2', $mce_buttons_2, $editor_id );
   605 				$mce_buttons_2 = apply_filters( 'mce_buttons_2', $mce_buttons_2, $editor_id );
   589 
   606 
   590 				/**
   607 				/**
   591 				 * Filter the third-row list of TinyMCE buttons (Visual tab).
   608 				 * Filters the third-row list of TinyMCE buttons (Visual tab).
   592 				 *
   609 				 *
   593 				 * @since 2.0.0
   610 				 * @since 2.0.0
   594 				 *
   611 				 *
   595 				 * @param array  $buttons   Third-row list of buttons.
   612 				 * @param array  $buttons   Third-row list of buttons.
   596 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   613 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   597 				 */
   614 				 */
   598 				$mce_buttons_3 = apply_filters( 'mce_buttons_3', array(), $editor_id );
   615 				$mce_buttons_3 = apply_filters( 'mce_buttons_3', array(), $editor_id );
   599 
   616 
   600 				/**
   617 				/**
   601 				 * Filter the fourth-row list of TinyMCE buttons (Visual tab).
   618 				 * Filters the fourth-row list of TinyMCE buttons (Visual tab).
   602 				 *
   619 				 *
   603 				 * @since 2.5.0
   620 				 * @since 2.5.0
   604 				 *
   621 				 *
   605 				 * @param array  $buttons   Fourth-row list of buttons.
   622 				 * @param array  $buttons   Fourth-row list of buttons.
   606 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   623 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   610 
   627 
   611 			$body_class = $editor_id;
   628 			$body_class = $editor_id;
   612 
   629 
   613 			if ( $post = get_post() ) {
   630 			if ( $post = get_post() ) {
   614 				$body_class .= ' post-type-' . sanitize_html_class( $post->post_type ) . ' post-status-' . sanitize_html_class( $post->post_status );
   631 				$body_class .= ' post-type-' . sanitize_html_class( $post->post_type ) . ' post-status-' . sanitize_html_class( $post->post_status );
       
   632 
   615 				if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
   633 				if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
   616 					$post_format = get_post_format( $post );
   634 					$post_format = get_post_format( $post );
   617 					if ( $post_format && ! is_wp_error( $post_format ) )
   635 					if ( $post_format && ! is_wp_error( $post_format ) )
   618 						$body_class .= ' post-format-' . sanitize_html_class( $post_format );
   636 						$body_class .= ' post-format-' . sanitize_html_class( $post_format );
   619 					else
   637 					else
   620 						$body_class .= ' post-format-standard';
   638 						$body_class .= ' post-format-standard';
   621 				}
   639 				}
   622 			}
   640 
   623 
   641 				$page_template = get_page_template_slug( $post );
   624 			$body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
   642 
   625 
   643 				if ( $page_template !== false ) {
   626 			if ( !empty($set['tinymce']['body_class']) ) {
   644 					$page_template = empty( $page_template ) ? 'default' : str_replace( '.', '-', basename( $page_template, '.php' ) );
       
   645 					$body_class .= ' page-template-' . sanitize_html_class( $page_template );
       
   646 				}
       
   647 			}
       
   648 
       
   649 			$body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) );
       
   650 
       
   651 			if ( ! empty( $set['tinymce']['body_class'] ) ) {
   627 				$body_class .= ' ' . $set['tinymce']['body_class'];
   652 				$body_class .= ' ' . $set['tinymce']['body_class'];
   628 				unset($set['tinymce']['body_class']);
   653 				unset( $set['tinymce']['body_class'] );
   629 			}
       
   630 
       
   631 			if ( $set['dfw'] ) {
       
   632 				// replace the first 'fullscreen' with 'wp_fullscreen'
       
   633 				if ( ($key = array_search('fullscreen', $mce_buttons)) !== false )
       
   634 					$mce_buttons[$key] = 'wp_fullscreen';
       
   635 				elseif ( ($key = array_search('fullscreen', $mce_buttons_2)) !== false )
       
   636 					$mce_buttons_2[$key] = 'wp_fullscreen';
       
   637 				elseif ( ($key = array_search('fullscreen', $mce_buttons_3)) !== false )
       
   638 					$mce_buttons_3[$key] = 'wp_fullscreen';
       
   639 				elseif ( ($key = array_search('fullscreen', $mce_buttons_4)) !== false )
       
   640 					$mce_buttons_4[$key] = 'wp_fullscreen';
       
   641 			}
   654 			}
   642 
   655 
   643 			$mceInit = array (
   656 			$mceInit = array (
   644 				'selector' => "#$editor_id",
   657 				'selector' => "#$editor_id",
   645 				'resize' => 'vertical',
       
   646 				'menubar' => false,
       
   647 				'wpautop' => (bool) $set['wpautop'],
   658 				'wpautop' => (bool) $set['wpautop'],
   648 				'indent' => ! $set['wpautop'],
   659 				'indent' => ! $set['wpautop'],
   649 				'toolbar1' => implode($mce_buttons, ','),
   660 				'toolbar1' => implode( ',', $mce_buttons ),
   650 				'toolbar2' => implode($mce_buttons_2, ','),
   661 				'toolbar2' => implode( ',', $mce_buttons_2 ),
   651 				'toolbar3' => implode($mce_buttons_3, ','),
   662 				'toolbar3' => implode( ',', $mce_buttons_3 ),
   652 				'toolbar4' => implode($mce_buttons_4, ','),
   663 				'toolbar4' => implode( ',', $mce_buttons_4 ),
   653 				'tabfocus_elements' => $set['tabfocus_elements'],
   664 				'tabfocus_elements' => $set['tabfocus_elements'],
   654 				'body_class' => $body_class
   665 				'body_class' => $body_class
   655 			);
   666 			);
   656 
   667 
   657 			if ( $first_run )
   668 			// Merge with the first part of the init array
   658 				$mceInit = array_merge( self::$first_init, $mceInit );
   669 			$mceInit = array_merge( self::$first_init, $mceInit );
   659 
   670 
   660 			if ( is_array( $set['tinymce'] ) )
   671 			if ( is_array( $set['tinymce'] ) )
   661 				$mceInit = array_merge( $mceInit, $set['tinymce'] );
   672 				$mceInit = array_merge( $mceInit, $set['tinymce'] );
   662 
   673 
   663 			/*
   674 			/*
   664 			 * For people who really REALLY know what they're doing with TinyMCE
   675 			 * For people who really REALLY know what they're doing with TinyMCE
   665 			 * You can modify $mceInit to add, remove, change elements of the config
   676 			 * You can modify $mceInit to add, remove, change elements of the config
   666 			 * before tinyMCE.init. Setting "valid_elements", "invalid_elements"
   677 			 * before tinyMCE.init. Setting "valid_elements", "invalid_elements"
   667 			 * and "extended_valid_elements" can be done through this filter. Best
   678 			 * and "extended_valid_elements" can be done through this filter. Best
   668 			 * is to use the default cleanup by not specifying valid_elements,
   679 			 * is to use the default cleanup by not specifying valid_elements,
   669 			 * as TinyMCE contains full set of XHTML 1.0.
   680 			 * as TinyMCE checks against the full set of HTML 5.0 elements and attributes.
   670 			 */
   681 			 */
   671 			if ( $set['teeny'] ) {
   682 			if ( $set['teeny'] ) {
   672 
   683 
   673 				/**
   684 				/**
   674 				 * Filter the teenyMCE config before init.
   685 				 * Filters the teenyMCE config before init.
   675 				 *
   686 				 *
   676 				 * @since 2.7.0
   687 				 * @since 2.7.0
   677 				 *
   688 				 *
   678 				 * @param array  $mceInit   An array with teenyMCE config.
   689 				 * @param array  $mceInit   An array with teenyMCE config.
   679 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   690 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   680 				 */
   691 				 */
   681 				$mceInit = apply_filters( 'teeny_mce_before_init', $mceInit, $editor_id );
   692 				$mceInit = apply_filters( 'teeny_mce_before_init', $mceInit, $editor_id );
   682 			} else {
   693 			} else {
   683 
   694 
   684 				/**
   695 				/**
   685 				 * Filter the TinyMCE config before init.
   696 				 * Filters the TinyMCE config before init.
   686 				 *
   697 				 *
   687 				 * @since 2.5.0
   698 				 * @since 2.5.0
   688 				 *
   699 				 *
   689 				 * @param array  $mceInit   An array with TinyMCE config.
   700 				 * @param array  $mceInit   An array with TinyMCE config.
   690 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   701 				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
   699 
   710 
   700 			self::$mce_settings[$editor_id] = $mceInit;
   711 			self::$mce_settings[$editor_id] = $mceInit;
   701 		} // end if self::$this_tinymce
   712 		} // end if self::$this_tinymce
   702 	}
   713 	}
   703 
   714 
   704 	private static function _parse_init($init) {
   715 	/**
       
   716 	 *
       
   717 	 * @static
       
   718 	 * @param array $init
       
   719 	 * @return string
       
   720 	 */
       
   721 	private static function _parse_init( $init ) {
   705 		$options = '';
   722 		$options = '';
   706 
   723 
   707 		foreach ( $init as $k => $v ) {
   724 		foreach ( $init as $key => $value ) {
   708 			if ( is_bool($v) ) {
   725 			if ( is_bool( $value ) ) {
   709 				$val = $v ? 'true' : 'false';
   726 				$val = $value ? 'true' : 'false';
   710 				$options .= $k . ':' . $val . ',';
   727 				$options .= $key . ':' . $val . ',';
   711 				continue;
   728 				continue;
   712 			} elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
   729 			} elseif ( ! empty( $value ) && is_string( $value ) && (
   713 				$options .= $k . ':' . $v . ',';
   730 				( '{' == $value{0} && '}' == $value{strlen( $value ) - 1} ) ||
       
   731 				( '[' == $value{0} && ']' == $value{strlen( $value ) - 1} ) ||
       
   732 				preg_match( '/^\(?function ?\(/', $value ) ) ) {
       
   733 
       
   734 				$options .= $key . ':' . $value . ',';
   714 				continue;
   735 				continue;
   715 			}
   736 			}
   716 			$options .= $k . ':"' . $v . '",';
   737 			$options .= $key . ':"' . $value . '",';
   717 		}
   738 		}
   718 
   739 
   719 		return '{' . trim( $options, ' ,' ) . '}';
   740 		return '{' . trim( $options, ' ,' ) . '}';
   720 	}
   741 	}
   721 
   742 
   722 	public static function enqueue_scripts() {
   743 	/**
   723 		wp_enqueue_script('word-count');
   744 	 *
   724 
   745 	 * @static
   725 		if ( self::$has_tinymce )
   746 	 * 
   726 			wp_enqueue_script('editor');
   747 	 * @param bool $default_scripts Optional. Whether default scripts should be enqueued. Default false.
   727 
   748 	 */
   728 		if ( self::$has_quicktags ) {
   749 	public static function enqueue_scripts( $default_scripts = false ) {
       
   750 		if ( $default_scripts || self::$has_tinymce ) {
       
   751 			wp_enqueue_script( 'editor' );
       
   752 		}
       
   753 
       
   754 		if ( $default_scripts || self::$has_quicktags ) {
   729 			wp_enqueue_script( 'quicktags' );
   755 			wp_enqueue_script( 'quicktags' );
   730 			wp_enqueue_style( 'buttons' );
   756 			wp_enqueue_style( 'buttons' );
   731 		}
   757 		}
   732 
   758 
   733 		if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) ) {
   759 		if ( $default_scripts || in_array( 'wplink', self::$plugins, true ) || in_array( 'link', self::$qt_buttons, true ) ) {
   734 			wp_enqueue_script('wplink');
   760 			wp_enqueue_script( 'wplink' );
   735 		}
   761 			wp_enqueue_script( 'jquery-ui-autocomplete' );
   736 
   762 		}
   737 		if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
   763 
   738 			wp_enqueue_script('wp-fullscreen');
   764 		if ( self::$old_dfw_compat ) {
       
   765 			wp_enqueue_script( 'wp-fullscreen-stub' );
       
   766 		}
   739 
   767 
   740 		if ( self::$has_medialib ) {
   768 		if ( self::$has_medialib ) {
   741 			add_thickbox();
   769 			add_thickbox();
   742 			wp_enqueue_script('media-upload');
   770 			wp_enqueue_script( 'media-upload' );
       
   771 			wp_enqueue_script( 'wp-embed' );
       
   772 		} elseif ( $default_scripts ) {
       
   773 			wp_enqueue_script( 'media-upload' );
   743 		}
   774 		}
   744 
   775 
   745 		/**
   776 		/**
   746 		 * Fires when scripts and styles are enqueued for the editor.
   777 		 * Fires when scripts and styles are enqueued for the editor.
   747 		 *
   778 		 *
   749 		 *
   780 		 *
   750 		 * @param array $to_load An array containing boolean values whether TinyMCE
   781 		 * @param array $to_load An array containing boolean values whether TinyMCE
   751 		 *                       and Quicktags are being loaded.
   782 		 *                       and Quicktags are being loaded.
   752 		 */
   783 		 */
   753 		do_action( 'wp_enqueue_editor', array(
   784 		do_action( 'wp_enqueue_editor', array(
   754 			'tinymce'   => self::$has_tinymce,
   785 			'tinymce'   => ( $default_scripts || self::$has_tinymce ),
   755 			'quicktags' => self::$has_quicktags,
   786 			'quicktags' => ( $default_scripts || self::$has_quicktags ),
   756 		) );
   787 		) );
   757 	}
   788 	}
   758 
   789 
   759 	/**
   790 	/**
   760 	 * Translates the default TinyMCE strings and returns them as JSON encoded object ready to be loaded with tinymce.addI18n().
   791 	 * Enqueue all editor scripts.
   761 	 * Can be used directly (_WP_Editors::wp_mce_translation()) by passing the same locale as set in the TinyMCE init object.
   792 	 * For use when the editor is going to be initialized after page load.
   762 	 *
   793 	 *
   763 	 * @param string $mce_locale The locale used for the editor.
   794 	 * @since 4.8.0
   764 	 * @param bool $json_only optional Whether to include the JavaScript calls to tinymce.addI18n() and tinymce.ScriptLoader.markDone().
       
   765 	 * @return string Translation object, JSON encoded.
       
   766 	 */
   795 	 */
   767 	public static function wp_mce_translation( $mce_locale = '', $json_only = false ) {
   796 	public static function enqueue_default_editor() {
   768 
   797 		// We are past the point where scripts can be enqueued properly.
   769 		$mce_translation = array(
   798 		if ( did_action( 'wp_enqueue_editor' ) ) {
       
   799 			return;
       
   800 		}
       
   801 
       
   802 		self::enqueue_scripts( true );
       
   803 
       
   804 		// Also add wp-includes/css/editor.css
       
   805 		wp_enqueue_style( 'editor-buttons' );
       
   806 
       
   807 		if ( is_admin() ) {
       
   808 			add_action( 'admin_print_footer_scripts', array( __CLASS__, 'print_default_editor_scripts' ), 45 );
       
   809 		} else {
       
   810 			add_action( 'wp_print_footer_scripts', array( __CLASS__, 'print_default_editor_scripts' ), 45 );
       
   811 		}
       
   812 	}
       
   813 
       
   814 	/**
       
   815 	 * Print (output) all editor scripts and default settings.
       
   816 	 * For use when the editor is going to be initialized after page load.
       
   817 	 *
       
   818 	 * @since 4.8.0
       
   819 	 *
       
   820 	 */
       
   821 	public static function print_default_editor_scripts() {
       
   822 		$user_can_richedit = user_can_richedit();
       
   823 
       
   824 		if ( $user_can_richedit ) {
       
   825 			$settings = self::default_settings();
       
   826 
       
   827 			$settings['toolbar1'] = 'bold,italic,bullist,numlist,link';
       
   828 			$settings['wpautop'] = false;
       
   829 			$settings['indent'] = true;
       
   830 			$settings['elementpath'] = false;
       
   831 
       
   832 			if ( is_rtl() ) {
       
   833 				$settings['directionality'] = 'rtl';
       
   834 			}
       
   835 
       
   836 			// In production all plugins are loaded (they are in wp-editor.js.gz).
       
   837 			// The 'wpview', 'wpdialogs', and 'media' TinyMCE plugins are not initialized by default.
       
   838 			// Can be added from js by using the 'wp-before-tinymce-init' event.
       
   839 			$settings['plugins'] = implode( ',', array(
       
   840 				'charmap',
       
   841 				'colorpicker',
       
   842 				'hr',
       
   843 				'lists',
       
   844 				'paste',
       
   845 				'tabfocus',
       
   846 				'textcolor',
       
   847 				'fullscreen',
       
   848 				'wordpress',
       
   849 				'wpautoresize',
       
   850 				'wpeditimage',
       
   851 				'wpemoji',
       
   852 				'wpgallery',
       
   853 				'wplink',
       
   854 				'wptextpattern',
       
   855 			) );
       
   856 
       
   857 			$settings = self::_parse_init( $settings );
       
   858 		} else {
       
   859 			$settings = '{}';
       
   860 		}
       
   861 
       
   862 		?>
       
   863 		<script type="text/javascript">
       
   864 		window.wp = window.wp || {};
       
   865 		window.wp.editor = window.wp.editor || {};
       
   866 		window.wp.editor.getDefaultSettings = function() {
       
   867 			return {
       
   868 				tinymce: <?php echo $settings; ?>,
       
   869 				quicktags: {
       
   870 					buttons: 'strong,em,link,ul,ol,li,code'
       
   871 				}
       
   872 			};
       
   873 		};
       
   874 
       
   875 		<?php
       
   876 
       
   877 		if ( $user_can_richedit ) {
       
   878 			$suffix = SCRIPT_DEBUG ? '' : '.min';
       
   879 			$baseurl = self::get_baseurl();
       
   880 
       
   881 			?>
       
   882 			var tinyMCEPreInit = {
       
   883 				baseURL: "<?php echo $baseurl; ?>",
       
   884 				suffix: "<?php echo $suffix; ?>",
       
   885 				mceInit: {},
       
   886 				qtInit: {},
       
   887 				load_ext: function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
       
   888 			};
       
   889 			<?php
       
   890 		}
       
   891 		?>
       
   892 		</script>
       
   893 		<?php
       
   894 
       
   895 		if ( $user_can_richedit ) {
       
   896 			self::print_tinymce_scripts();
       
   897 		}
       
   898 
       
   899 		/**
       
   900 		 * Fires when the editor scripts are loaded for later initialization,
       
   901 		 * after all scripts and settings are printed.
       
   902 		 *
       
   903 		 * @since 4.8.0
       
   904 		 */
       
   905 		do_action( 'print_default_editor_scripts' );
       
   906 
       
   907 		self::wp_link_dialog();
       
   908 	}
       
   909 
       
   910 	public static function get_mce_locale() {
       
   911 		if ( empty( self::$mce_locale ) ) {
       
   912 			$mce_locale = get_user_locale();
       
   913 			self::$mce_locale = empty( $mce_locale ) ? 'en' : strtolower( substr( $mce_locale, 0, 2 ) ); // ISO 639-1
       
   914 		}
       
   915 
       
   916 		return self::$mce_locale;
       
   917 	}
       
   918 
       
   919 	public static function get_baseurl() {
       
   920 		if ( empty( self::$baseurl ) ) {
       
   921 			self::$baseurl = includes_url( 'js/tinymce' );
       
   922 		}
       
   923 
       
   924 		return self::$baseurl;
       
   925 	}
       
   926 
       
   927 	/**
       
   928 	 * Returns the default TinyMCE settings.
       
   929 	 * Doesn't include plugins, buttons, editor selector.
       
   930 	 *
       
   931 	 * @global string $tinymce_version
       
   932 	 *
       
   933 	 * @return array
       
   934 	 */
       
   935 	private static function default_settings() {
       
   936 		global $tinymce_version;
       
   937 
       
   938 		$shortcut_labels = array();
       
   939 
       
   940 		foreach ( self::get_translation() as $name => $value ) {
       
   941 			if ( is_array( $value ) ) {
       
   942 				$shortcut_labels[$name] = $value[1];
       
   943 			}
       
   944 		}
       
   945 
       
   946 		$settings = array(
       
   947 			'theme' => 'modern',
       
   948 			'skin' => 'lightgray',
       
   949 			'language' => self::get_mce_locale(),
       
   950 			'formats' => '{' .
       
   951 				'alignleft: [' .
       
   952 					'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"left"}},' .
       
   953 					'{selector: "img,table,dl.wp-caption", classes: "alignleft"}' .
       
   954 				'],' .
       
   955 				'aligncenter: [' .
       
   956 					'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"center"}},' .
       
   957 					'{selector: "img,table,dl.wp-caption", classes: "aligncenter"}' .
       
   958 				'],' .
       
   959 				'alignright: [' .
       
   960 					'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"right"}},' .
       
   961 					'{selector: "img,table,dl.wp-caption", classes: "alignright"}' .
       
   962 				'],' .
       
   963 				'strikethrough: {inline: "del"}' .
       
   964 			'}',
       
   965 			'relative_urls' => false,
       
   966 			'remove_script_host' => false,
       
   967 			'convert_urls' => false,
       
   968 			'browser_spellcheck' => true,
       
   969 			'fix_list_elements' => true,
       
   970 			'entities' => '38,amp,60,lt,62,gt',
       
   971 			'entity_encoding' => 'raw',
       
   972 			'keep_styles' => false,
       
   973 			'cache_suffix' => 'wp-mce-' . $tinymce_version,
       
   974 			'resize' => 'vertical',
       
   975 			'menubar' => false,
       
   976 			'branding' => false,
       
   977 
       
   978 			// Limit the preview styles in the menu/toolbar
       
   979 			'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
       
   980 
       
   981 			'end_container_on_empty_block' => true,
       
   982 			'wpeditimage_html5_captions' => true,
       
   983 			'wp_lang_attr' => get_bloginfo( 'language' ),
       
   984 			'wp_keep_scroll_position' => false,
       
   985 			'wp_shortcut_labels' => wp_json_encode( $shortcut_labels ),
       
   986 		);
       
   987 
       
   988 		$suffix = SCRIPT_DEBUG ? '' : '.min';
       
   989 		$version = 'ver=' . get_bloginfo( 'version' );
       
   990 
       
   991 		// Default stylesheets
       
   992 		$settings['content_css'] = includes_url( "css/dashicons$suffix.css?$version" ) . ',' .
       
   993 			includes_url( "js/tinymce/skins/wordpress/wp-content.css?$version" );
       
   994 
       
   995 		return $settings;
       
   996 	}
       
   997 
       
   998 	private static function get_translation() {
       
   999 		if ( empty( self::$translation ) ) {
       
  1000 			self::$translation = array(
   770 			// Default TinyMCE strings
  1001 			// Default TinyMCE strings
   771 			'New document' => __( 'New document' ),
  1002 			'New document' => __( 'New document' ),
   772 			'Formats' => _x( 'Formats', 'TinyMCE' ),
  1003 			'Formats' => _x( 'Formats', 'TinyMCE' ),
   773 
  1004 
   774 			'Headings' => _x( 'Headings', 'TinyMCE' ),
  1005 			'Headings' => _x( 'Headings', 'TinyMCE' ),
   775 			'Heading 1' => __( 'Heading 1' ),
  1006 			'Heading 1' => array( __( 'Heading 1' ), 'access1' ),
   776 			'Heading 2' => __( 'Heading 2' ),
  1007 			'Heading 2' => array( __( 'Heading 2' ), 'access2' ),
   777 			'Heading 3' => __( 'Heading 3' ),
  1008 			'Heading 3' => array( __( 'Heading 3' ), 'access3' ),
   778 			'Heading 4' => __( 'Heading 4' ),
  1009 			'Heading 4' => array( __( 'Heading 4' ), 'access4' ),
   779 			'Heading 5' => __( 'Heading 5' ),
  1010 			'Heading 5' => array( __( 'Heading 5' ), 'access5' ),
   780 			'Heading 6' => __( 'Heading 6' ),
  1011 			'Heading 6' => array( __( 'Heading 6' ), 'access6' ),
   781 
  1012 
   782 			/* translators: block tags */
  1013 			/* translators: block tags */
   783 			'Blocks' => _x( 'Blocks', 'TinyMCE' ),
  1014 			'Blocks' => _x( 'Blocks', 'TinyMCE' ),
   784 			'Paragraph' => __( 'Paragraph' ),
  1015 			'Paragraph' => array( __( 'Paragraph' ), 'access7' ),
   785 			'Blockquote' => __( 'Blockquote' ),
  1016 			'Blockquote' => array( __( 'Blockquote' ), 'accessQ' ),
   786 			'Div' => _x( 'Div', 'HTML tag' ),
  1017 			'Div' => _x( 'Div', 'HTML tag' ),
   787 			'Pre' => _x( 'Pre', 'HTML tag' ),
  1018 			'Pre' => _x( 'Pre', 'HTML tag' ),
       
  1019 			'Preformatted' => _x( 'Preformatted', 'HTML tag' ),
   788 			'Address' => _x( 'Address', 'HTML tag' ),
  1020 			'Address' => _x( 'Address', 'HTML tag' ),
   789 
  1021 
   790 			'Inline' => _x( 'Inline', 'HTML elements' ),
  1022 			'Inline' => _x( 'Inline', 'HTML elements' ),
   791 			'Underline' => __( 'Underline' ),
  1023 			'Underline' => array( __( 'Underline' ), 'metaU' ),
   792 			'Strikethrough' => __( 'Strikethrough' ),
  1024 			'Strikethrough' => array( __( 'Strikethrough' ), 'accessD' ),
   793 			'Subscript' => __( 'Subscript' ),
  1025 			'Subscript' => __( 'Subscript' ),
   794 			'Superscript' => __( 'Superscript' ),
  1026 			'Superscript' => __( 'Superscript' ),
   795 			'Clear formatting' => __( 'Clear formatting' ),
  1027 			'Clear formatting' => __( 'Clear formatting' ),
   796 			'Bold' => __( 'Bold' ),
  1028 			'Bold' => array( __( 'Bold' ), 'metaB' ),
   797 			'Italic' => __( 'Italic' ),
  1029 			'Italic' => array( __( 'Italic' ), 'metaI' ),
   798 			'Code' => _x( 'Code', 'editor button' ),
  1030 			'Code' => array( __( 'Code' ), 'accessX' ),
   799 			'Source code' => __( 'Source code' ),
  1031 			'Source code' => __( 'Source code' ),
   800 			'Font Family' => __( 'Font Family' ),
  1032 			'Font Family' => __( 'Font Family' ),
   801 			'Font Sizes' => __( 'Font Sizes' ),
  1033 			'Font Sizes' => __( 'Font Sizes' ),
   802 
  1034 
   803 			'Align center' => __( 'Align center' ),
  1035 			'Align center' => array( __( 'Align center' ), 'accessC' ),
   804 			'Align right' => __( 'Align right' ),
  1036 			'Align right' => array( __( 'Align right' ), 'accessR' ),
   805 			'Align left' => __( 'Align left' ),
  1037 			'Align left' => array( __( 'Align left' ), 'accessL' ),
   806 			'Justify' => __( 'Justify' ),
  1038 			'Justify' => array( __( 'Justify' ), 'accessJ' ),
   807 			'Increase indent' => __( 'Increase indent' ),
  1039 			'Increase indent' => __( 'Increase indent' ),
   808 			'Decrease indent' => __( 'Decrease indent' ),
  1040 			'Decrease indent' => __( 'Decrease indent' ),
   809 
  1041 
   810 			'Cut' => __( 'Cut' ),
  1042 			'Cut' => array( __( 'Cut' ), 'metaX' ),
   811 			'Copy' => __( 'Copy' ),
  1043 			'Copy' => array( __( 'Copy' ), 'metaC' ),
   812 			'Paste' => __( 'Paste' ),
  1044 			'Paste' => array( __( 'Paste' ), 'metaV' ),
   813 			'Select all' => __( 'Select all' ),
  1045 			'Select all' => array( __( 'Select all' ), 'metaA' ),
   814 			'Undo' => __( 'Undo' ),
  1046 			'Undo' => array( __( 'Undo' ), 'metaZ' ),
   815 			'Redo' => __( 'Redo' ),
  1047 			'Redo' => array( __( 'Redo' ), 'metaY' ),
   816 
  1048 
   817 			'Ok' => __( 'OK' ),
  1049 			'Ok' => __( 'OK' ),
   818 			'Cancel' => __( 'Cancel' ),
  1050 			'Cancel' => __( 'Cancel' ),
   819 			'Close' => __( 'Close' ),
  1051 			'Close' => __( 'Close' ),
   820 			'Visual aids' => __( 'Visual aids' ),
  1052 			'Visual aids' => __( 'Visual aids' ),
   821 
  1053 
   822 			'Bullet list' => __( 'Bulleted list' ),
  1054 			'Bullet list' => array( __( 'Bulleted list' ), 'accessU' ),
   823 			'Numbered list' => __( 'Numbered list' ),
  1055 			'Numbered list' => array( __( 'Numbered list' ), 'accessO' ),
   824 			'Square' => _x( 'Square', 'list style' ),
  1056 			'Square' => _x( 'Square', 'list style' ),
   825 			'Default' => _x( 'Default', 'list style' ),
  1057 			'Default' => _x( 'Default', 'list style' ),
   826 			'Circle' => _x( 'Circle', 'list style' ),
  1058 			'Circle' => _x( 'Circle', 'list style' ),
   827 			'Disc' => _x('Disc', 'list style' ),
  1059 			'Disc' => _x('Disc', 'list style' ),
   828 			'Lower Greek' => _x( 'Lower Greek', 'list style' ),
  1060 			'Lower Greek' => _x( 'Lower Greek', 'list style' ),
   833 
  1065 
   834 			// Anchor plugin
  1066 			// Anchor plugin
   835 			'Name' => _x( 'Name', 'Name of link anchor (TinyMCE)' ),
  1067 			'Name' => _x( 'Name', 'Name of link anchor (TinyMCE)' ),
   836 			'Anchor' => _x( 'Anchor', 'Link anchor (TinyMCE)' ),
  1068 			'Anchor' => _x( 'Anchor', 'Link anchor (TinyMCE)' ),
   837 			'Anchors' => _x( 'Anchors', 'Link anchors (TinyMCE)' ),
  1069 			'Anchors' => _x( 'Anchors', 'Link anchors (TinyMCE)' ),
       
  1070 			'Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.' =>
       
  1071 				__( 'Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.' ),
       
  1072 			'Id' => _x( 'Id', 'Id for link anchor (TinyMCE)' ),
   838 
  1073 
   839 			// Fullpage plugin
  1074 			// Fullpage plugin
   840 			'Document properties' => __( 'Document properties' ),
  1075 			'Document properties' => __( 'Document properties' ),
   841 			'Robots' => __( 'Robots' ),
  1076 			'Robots' => __( 'Robots' ),
   842 			'Title' => __( 'Title' ),
  1077 			'Title' => __( 'Title' ),
   844 			'Encoding' => __( 'Encoding' ),
  1079 			'Encoding' => __( 'Encoding' ),
   845 			'Description' => __( 'Description' ),
  1080 			'Description' => __( 'Description' ),
   846 			'Author' => __( 'Author' ),
  1081 			'Author' => __( 'Author' ),
   847 
  1082 
   848 			// Media, image plugins
  1083 			// Media, image plugins
   849 			'Insert/edit image' => __( 'Insert/edit image' ),
  1084 			'Image' => __( 'Image' ),
       
  1085 			'Insert/edit image' => array( __( 'Insert/edit image' ), 'accessM' ),
   850 			'General' => __( 'General' ),
  1086 			'General' => __( 'General' ),
   851 			'Advanced' => __( 'Advanced' ),
  1087 			'Advanced' => __( 'Advanced' ),
   852 			'Source' => __( 'Source' ),
  1088 			'Source' => __( 'Source' ),
   853 			'Border' => __( 'Border' ),
  1089 			'Border' => __( 'Border' ),
   854 			'Constrain proportions' => __( 'Constrain proportions' ),
  1090 			'Constrain proportions' => __( 'Constrain proportions' ),
   855 			'Vertical space' => __( 'Vertical space' ),
  1091 			'Vertical space' => __( 'Vertical space' ),
   856 			'Image description' => __( 'Image description' ),
  1092 			'Image description' => __( 'Image description' ),
   857 			'Style' => __( 'Style' ),
  1093 			'Style' => __( 'Style' ),
   858 			'Dimensions' => __( 'Dimensions' ),
  1094 			'Dimensions' => __( 'Dimensions' ),
   859 			'Insert image' => __( 'Insert image' ),
  1095 			'Insert image' => __( 'Insert image' ),
       
  1096 			'Date/time' => __( 'Date/time' ),
   860 			'Insert date/time' => __( 'Insert date/time' ),
  1097 			'Insert date/time' => __( 'Insert date/time' ),
   861 			'Insert/edit video' => __( 'Insert/edit video' ),
  1098 			'Table of Contents' => __( 'Table of Contents' ),
       
  1099 			'Insert/Edit code sample' => __( 'Insert/edit code sample' ),
       
  1100 			'Language' => __( 'Language' ),
       
  1101 			'Media' => __( 'Media' ),
       
  1102 			'Insert/edit media' => __( 'Insert/edit media' ),
   862 			'Poster' => __( 'Poster' ),
  1103 			'Poster' => __( 'Poster' ),
   863 			'Alternative source' => __( 'Alternative source' ),
  1104 			'Alternative source' => __( 'Alternative source' ),
   864 			'Paste your embed code below:' => __( 'Paste your embed code below:' ),
  1105 			'Paste your embed code below:' => __( 'Paste your embed code below:' ),
   865 			'Insert video' => __( 'Insert video' ),
  1106 			'Insert video' => __( 'Insert video' ),
   866 			'Embed' => __( 'Embed' ),
  1107 			'Embed' => __( 'Embed' ),
   878 			'Save' => __( 'Save' ),
  1119 			'Save' => __( 'Save' ),
   879 			'Fullscreen' => __( 'Fullscreen' ),
  1120 			'Fullscreen' => __( 'Fullscreen' ),
   880 			'Horizontal line' => __( 'Horizontal line' ),
  1121 			'Horizontal line' => __( 'Horizontal line' ),
   881 			'Horizontal space' => __( 'Horizontal space' ),
  1122 			'Horizontal space' => __( 'Horizontal space' ),
   882 			'Restore last draft' => __( 'Restore last draft' ),
  1123 			'Restore last draft' => __( 'Restore last draft' ),
       
  1124 			'Insert/edit link' => array( __( 'Insert/edit link' ), 'metaK' ),
       
  1125 			'Remove link' => array( __( 'Remove link' ), 'accessS' ),
       
  1126 
       
  1127 			// Link plugin
       
  1128 			'Link' => __( 'Link' ),
       
  1129 			'Insert link' => __( 'Insert link' ),
   883 			'Insert/edit link' => __( 'Insert/edit link' ),
  1130 			'Insert/edit link' => __( 'Insert/edit link' ),
   884 			'Remove link' => __( 'Remove link' ),
  1131 			'Target' => __( 'Target' ),
       
  1132 			'New window' => __( 'New window' ),
       
  1133 			'Text to display' => __( 'Text to display' ),
       
  1134 			'Url' => __( 'URL' ),
       
  1135 			'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?' =>
       
  1136 				__( 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?' ),
       
  1137 			'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?' =>
       
  1138 				__( 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?' ),
   885 
  1139 
   886 			'Color' => __( 'Color' ),
  1140 			'Color' => __( 'Color' ),
   887 			'Custom color' => __( 'Custom color' ),
  1141 			'Custom color' => __( 'Custom color' ),
   888 			'Custom...' => _x( 'Custom...', 'label for custom color' ),
  1142 			'Custom...' => _x( 'Custom...', 'label for custom color' ), // no ellipsis
   889 			'No color' => __( 'No color' ),
  1143 			'No color' => __( 'No color' ),
       
  1144 			'R' => _x( 'R', 'Short for red in RGB' ),
       
  1145 			'G' => _x( 'G', 'Short for green in RGB' ),
       
  1146 			'B' => _x( 'B', 'Short for blue in RGB' ),
   890 
  1147 
   891 			// Spelling, search/replace plugins
  1148 			// Spelling, search/replace plugins
   892 			'Could not find the specified string.' => __( 'Could not find the specified string.' ),
  1149 			'Could not find the specified string.' => __( 'Could not find the specified string.' ),
   893 			'Replace' => _x( 'Replace', 'find/replace' ),
  1150 			'Replace' => _x( 'Replace', 'find/replace' ),
   894 			'Next' => _x( 'Next', 'find/replace' ),
  1151 			'Next' => _x( 'Next', 'find/replace' ),
   967 			'Show blocks' => _x( 'Show blocks', 'editor button' ),
  1224 			'Show blocks' => _x( 'Show blocks', 'editor button' ),
   968 			'Show invisible characters' => __( 'Show invisible characters' ),
  1225 			'Show invisible characters' => __( 'Show invisible characters' ),
   969 
  1226 
   970 			/* translators: word count */
  1227 			/* translators: word count */
   971 			'Words: {0}' => sprintf( __( 'Words: %s' ), '{0}' ),
  1228 			'Words: {0}' => sprintf( __( 'Words: %s' ), '{0}' ),
   972 			'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' => __( 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' ) . "\n\n" . __( 'If you&#8217;re looking to paste rich content from Microsoft Word, try turning this option off. The editor will clean up text pasted from Word automatically.' ),
  1229 			'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' =>
   973 			'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' => __( 'Rich Text Area. Press Alt-Shift-H for help' ),
  1230 				__( 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' ) . "\n\n" .
   974 			'You have unsaved changes are you sure you want to navigate away?' => __( 'The changes you made will be lost if you navigate away from this page.' ),
  1231 				__( 'If you&#8217;re looking to paste rich content from Microsoft Word, try turning this option off. The editor will clean up text pasted from Word automatically.' ),
   975 			'Your browser doesn\'t support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.' => __( 'Your browser does not support direct access to the clipboard. Please use keyboard shortcuts or your browser&#8217;s edit menu instead.' ),
  1232 			'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' =>
       
  1233 				__( 'Rich Text Area. Press Alt-Shift-H for help.' ),
       
  1234 			'Rich Text Area. Press Control-Option-H for help.' => __( 'Rich Text Area. Press Control-Option-H for help.' ),
       
  1235 			'You have unsaved changes are you sure you want to navigate away?' =>
       
  1236 				__( 'The changes you made will be lost if you navigate away from this page.' ),
       
  1237 			'Your browser doesn\'t support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.' =>
       
  1238 				__( 'Your browser does not support direct access to the clipboard. Please use keyboard shortcuts or your browser&#8217;s edit menu instead.' ),
   976 
  1239 
   977 			// TinyMCE menus
  1240 			// TinyMCE menus
   978 			'Insert' => _x( 'Insert', 'TinyMCE menu' ),
  1241 			'Insert' => _x( 'Insert', 'TinyMCE menu' ),
   979 			'File' => _x( 'File', 'TinyMCE menu' ),
  1242 			'File' => _x( 'File', 'TinyMCE menu' ),
   980 			'Edit' => _x( 'Edit', 'TinyMCE menu' ),
  1243 			'Edit' => _x( 'Edit', 'TinyMCE menu' ),
   982 			'View' => _x( 'View', 'TinyMCE menu' ),
  1245 			'View' => _x( 'View', 'TinyMCE menu' ),
   983 			'Table' => _x( 'Table', 'TinyMCE menu' ),
  1246 			'Table' => _x( 'Table', 'TinyMCE menu' ),
   984 			'Format' => _x( 'Format', 'TinyMCE menu' ),
  1247 			'Format' => _x( 'Format', 'TinyMCE menu' ),
   985 
  1248 
   986 			// WordPress strings
  1249 			// WordPress strings
   987 			'Keyboard Shortcuts' => __( 'Keyboard Shortcuts' ),
  1250 			'Toolbar Toggle' => array( __( 'Toolbar Toggle' ), 'accessZ' ),
   988 			'Toolbar Toggle' => __( 'Toolbar Toggle' ),
  1251 			'Insert Read More tag' => array( __( 'Insert Read More tag' ), 'accessT' ),
   989 			'Insert Read More tag' => __( 'Insert Read More tag' ),
  1252 			'Insert Page Break tag' => array( __( 'Insert Page Break tag' ), 'accessP' ),
   990 			'Read more...' => __( 'Read more...' ), // Title on the placeholder inside the editor
  1253 			'Read more...' => __( 'Read more...' ), // Title on the placeholder inside the editor (no ellipsis)
   991 			'Distraction-free writing mode' => __( 'Distraction-free writing mode' ),
  1254 			'Distraction-free writing mode' => array( __( 'Distraction-free writing mode' ), 'accessW' ),
   992 			'No alignment' => __( 'No alignment' ), // Tooltip for the 'alignnone' button in the image toolbar
  1255 			'No alignment' => __( 'No alignment' ), // Tooltip for the 'alignnone' button in the image toolbar
   993 			'Remove' => __( 'Remove' ), // Tooltip for the 'remove' button in the image toolbar
  1256 			'Remove' => __( 'Remove' ), // Tooltip for the 'remove' button in the image toolbar
   994 			'Edit ' => __( 'Edit' ), // Tooltip for the 'edit' button in the image toolbar
  1257 			'Edit ' => __( 'Edit' ), // Tooltip for the 'edit' button in the image toolbar
   995 		);
  1258 			'Paste URL or type to search' => __( 'Paste URL or type to search' ), // Placeholder for the inline link dialog
       
  1259 			'Apply'  => __( 'Apply' ), // Tooltip for the 'apply' button in the inline link dialog
       
  1260 			'Link options'  => __( 'Link options' ), // Tooltip for the 'link options' button in the inline link dialog
       
  1261 			'Visual' => _x( 'Visual', 'Name for the Visual editor tab' ), // Editor switch tab label
       
  1262 			'Text' => _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ), // Editor switch tab label
       
  1263 
       
  1264 			// Shortcuts help modal
       
  1265 			'Keyboard Shortcuts' => array( __( 'Keyboard Shortcuts' ), 'accessH' ),
       
  1266 			'Default shortcuts,' => __( 'Default shortcuts,' ),
       
  1267 			'Additional shortcuts,' => __( 'Additional shortcuts,' ),
       
  1268 			'Focus shortcuts:' => __( 'Focus shortcuts:' ),
       
  1269 			'Inline toolbar (when an image, link or preview is selected)' => __( 'Inline toolbar (when an image, link or preview is selected)' ),
       
  1270 			'Editor menu (when enabled)' => __( 'Editor menu (when enabled)' ),
       
  1271 			'Editor toolbar' => __( 'Editor toolbar' ),
       
  1272 			'Elements path' => __( 'Elements path' ),
       
  1273 			'Ctrl + Alt + letter:' => __( 'Ctrl + Alt + letter:' ),
       
  1274 			'Shift + Alt + letter:' => __( 'Shift + Alt + letter:' ),
       
  1275 			'Cmd + letter:' => __( 'Cmd + letter:' ),
       
  1276 			'Ctrl + letter:' => __( 'Ctrl + letter:' ),
       
  1277 			'Letter' => __( 'Letter' ),
       
  1278 			'Action' => __( 'Action' ),
       
  1279 			'Warning: the link has been inserted but may have errors. Please test it.' => __( 'Warning: the link has been inserted but may have errors. Please test it.' ),
       
  1280 			'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' =>
       
  1281 				__( 'To move focus to other buttons use Tab or the arrow keys. To return focus to the editor press Escape or use one of the buttons.' ),
       
  1282 			'When starting a new paragraph with one of these formatting shortcuts followed by a space, the formatting will be applied automatically. Press Backspace or Escape to undo.' =>
       
  1283 				__( 'When starting a new paragraph with one of these formatting shortcuts followed by a space, the formatting will be applied automatically. Press Backspace or Escape to undo.' ),
       
  1284 			'The following formatting shortcuts are replaced when pressing Enter. Press Escape or the Undo button to undo.' =>
       
  1285 				__( 'The following formatting shortcuts are replaced when pressing Enter. Press Escape or the Undo button to undo.' ),
       
  1286 			'The next group of formatting shortcuts are applied as you type or when you insert them around plain text in the same paragraph. Press Escape or the Undo button to undo.' =>
       
  1287 				__( 'The next group of formatting shortcuts are applied as you type or when you insert them around plain text in the same paragraph. Press Escape or the Undo button to undo.' ),
       
  1288 			);
       
  1289 		}
       
  1290 
       
  1291 		/*
       
  1292 		Imagetools plugin (not included):
       
  1293 			'Edit image' => __( 'Edit image' ),
       
  1294 			'Image options' => __( 'Image options' ),
       
  1295 			'Back' => __( 'Back' ),
       
  1296 			'Invert' => __( 'Invert' ),
       
  1297 			'Flip horizontally' => __( 'Flip horizontally' ),
       
  1298 			'Flip vertically' => __( 'Flip vertically' ),
       
  1299 			'Crop' => __( 'Crop' ),
       
  1300 			'Orientation' => __( 'Orientation' ),
       
  1301 			'Resize' => __( 'Resize' ),
       
  1302 			'Rotate clockwise' => __( 'Rotate clockwise' ),
       
  1303 			'Rotate counterclockwise' => __( 'Rotate counterclockwise' ),
       
  1304 			'Sharpen' => __( 'Sharpen' ),
       
  1305 			'Brightness' => __( 'Brightness' ),
       
  1306 			'Color levels' => __( 'Color levels' ),
       
  1307 			'Contrast' => __( 'Contrast' ),
       
  1308 			'Gamma' => __( 'Gamma' ),
       
  1309 			'Zoom in' => __( 'Zoom in' ),
       
  1310 			'Zoom out' => __( 'Zoom out' ),
       
  1311 		*/
       
  1312 
       
  1313 		return self::$translation;
       
  1314 	}
       
  1315 
       
  1316 	/**
       
  1317 	 * Translates the default TinyMCE strings and returns them as JSON encoded object ready to be loaded with tinymce.addI18n(),
       
  1318 	 * or as JS snippet that should run after tinymce.js is loaded.
       
  1319 	 *
       
  1320 	 * @static
       
  1321 	 * @param string $mce_locale The locale used for the editor.
       
  1322 	 * @param bool $json_only optional Whether to include the JavaScript calls to tinymce.addI18n() and tinymce.ScriptLoader.markDone().
       
  1323 	 * @return string Translation object, JSON encoded.
       
  1324 	 */
       
  1325 	public static function wp_mce_translation( $mce_locale = '', $json_only = false ) {
       
  1326 		if ( ! $mce_locale ) {
       
  1327 			$mce_locale = self::get_mce_locale();
       
  1328 		}
       
  1329 
       
  1330 		$mce_translation = self::get_translation();
       
  1331 
       
  1332 		foreach ( $mce_translation as $name => $value ) {
       
  1333 			if ( is_array( $value ) ) {
       
  1334 				$mce_translation[$name] = $value[0];
       
  1335 			}
       
  1336 		}
   996 
  1337 
   997 		/**
  1338 		/**
   998 		 * Link plugin (not included):
  1339 		 * Filters translated strings prepared for TinyMCE.
   999 		 *	Insert link
       
  1000 		 *	Target
       
  1001 		 *	New window
       
  1002 		 *	Text to display
       
  1003 		 *	The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
       
  1004 		 *	The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?
       
  1005 		 *	Url
       
  1006 		 */
       
  1007 
       
  1008 		if ( ! $mce_locale ) {
       
  1009 			$mce_locale = self::$mce_locale;
       
  1010 		}
       
  1011 
       
  1012 		/**
       
  1013 		 * Filter translated strings prepared for TinyMCE.
       
  1014 		 *
  1340 		 *
  1015 		 * @since 3.9.0
  1341 		 * @since 3.9.0
  1016 		 *
  1342 		 *
  1017 		 * @param array  $mce_translation Key/value pairs of strings.
  1343 		 * @param array  $mce_translation Key/value pairs of strings.
  1018 		 * @param string $mce_locale      Locale.
  1344 		 * @param string $mce_locale      Locale.
  1038 
  1364 
  1039 		if ( $json_only ) {
  1365 		if ( $json_only ) {
  1040 			return wp_json_encode( $mce_translation );
  1366 			return wp_json_encode( $mce_translation );
  1041 		}
  1367 		}
  1042 
  1368 
  1043 		$baseurl = self::$baseurl ? self::$baseurl : includes_url( 'js/tinymce' );
  1369 		$baseurl = self::get_baseurl();
  1044 
  1370 
  1045 		return "tinymce.addI18n( '$mce_locale', " . wp_json_encode( $mce_translation ) . ");\n" .
  1371 		return "tinymce.addI18n( '$mce_locale', " . wp_json_encode( $mce_translation ) . ");\n" .
  1046 			"tinymce.ScriptLoader.markDone( '$baseurl/langs/$mce_locale.js' );\n";
  1372 			"tinymce.ScriptLoader.markDone( '$baseurl/langs/$mce_locale.js' );\n";
  1047 	}
  1373 	}
  1048 
  1374 
       
  1375 	/**
       
  1376 	 * Print (output) the main TinyMCE scripts.
       
  1377 	 *
       
  1378 	 * @since 4.8.0
       
  1379 	 *
       
  1380 	 * @static
       
  1381 	 * @global string $tinymce_version
       
  1382 	 * @global bool   $concatenate_scripts
       
  1383 	 * @global bool   $compress_scripts
       
  1384 	 */
       
  1385 	public static function print_tinymce_scripts() {
       
  1386 		global $tinymce_version, $concatenate_scripts, $compress_scripts;
       
  1387 
       
  1388 		if ( self::$tinymce_scripts_printed ) {
       
  1389 			return;
       
  1390 		}
       
  1391 
       
  1392 		self::$tinymce_scripts_printed = true;
       
  1393 
       
  1394 		if ( ! isset( $concatenate_scripts ) ) {
       
  1395 			script_concat_settings();
       
  1396 		}
       
  1397 
       
  1398 		$suffix = SCRIPT_DEBUG ? '' : '.min';
       
  1399 		$version = 'ver=' . $tinymce_version;
       
  1400 		$baseurl = self::get_baseurl();
       
  1401 
       
  1402 		$has_custom_theme = false;
       
  1403 		foreach ( self::$mce_settings as $init ) {
       
  1404 			if ( ! empty( $init['theme_url'] ) ) {
       
  1405 				$has_custom_theme = true;
       
  1406 				break;
       
  1407 			}
       
  1408 		}
       
  1409 
       
  1410 		$compressed = $compress_scripts && $concatenate_scripts && isset( $_SERVER['HTTP_ACCEPT_ENCODING'] )
       
  1411 			&& false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) && ! $has_custom_theme;
       
  1412 
       
  1413 		// Load tinymce.js when running from /src, else load wp-tinymce.js.gz (production) or tinymce.min.js (SCRIPT_DEBUG)
       
  1414 		$mce_suffix = false !== strpos( get_bloginfo( 'version' ), '-src' ) ? '' : '.min';
       
  1415 
       
  1416 		if ( $compressed ) {
       
  1417 			echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
       
  1418 		} else {
       
  1419 			echo "<script type='text/javascript' src='{$baseurl}/tinymce{$mce_suffix}.js?$version'></script>\n";
       
  1420 			echo "<script type='text/javascript' src='{$baseurl}/plugins/compat3x/plugin{$suffix}.js?$version'></script>\n";
       
  1421 		}
       
  1422 
       
  1423 		echo "<script type='text/javascript'>\n" . self::wp_mce_translation() . "</script>\n";
       
  1424 	}
       
  1425 
       
  1426 	/**
       
  1427 	 * Print (output) the TinyMCE configuration and initialization scripts.
       
  1428 	 *
       
  1429 	 * @static
       
  1430 	 * @global string $tinymce_version
       
  1431 	 */
  1049 	public static function editor_js() {
  1432 	public static function editor_js() {
  1050 		global $tinymce_version, $concatenate_scripts, $compress_scripts;
  1433 		global $tinymce_version;
  1051 
  1434 
  1052 		/**
  1435 		$tmce_on = ! empty( self::$mce_settings );
  1053 		 * Filter "tiny_mce_version" is deprecated
       
  1054 		 *
       
  1055 		 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
       
  1056 		 * These plugins can be refreshed by appending query string to the URL passed to "mce_external_plugins" filter.
       
  1057 		 * If the plugin has a popup dialog, a query string can be added to the button action that opens it (in the plugin's code).
       
  1058 		 */
       
  1059 		$version = 'ver=' . $tinymce_version;
       
  1060 		$tmce_on = !empty(self::$mce_settings);
       
  1061 
       
  1062 		if ( ! isset($concatenate_scripts) )
       
  1063 			script_concat_settings();
       
  1064 
       
  1065 		$compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
       
  1066 			&& false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
       
  1067 
       
  1068 		$mceInit = $qtInit = '';
  1436 		$mceInit = $qtInit = '';
       
  1437 
  1069 		if ( $tmce_on ) {
  1438 		if ( $tmce_on ) {
  1070 			foreach ( self::$mce_settings as $editor_id => $init ) {
  1439 			foreach ( self::$mce_settings as $editor_id => $init ) {
  1071 				$options = self::_parse_init( $init );
  1440 				$options = self::_parse_init( $init );
  1072 				$mceInit .= "'$editor_id':{$options},";
  1441 				$mceInit .= "'$editor_id':{$options},";
  1073 			}
  1442 			}
  1074 			$mceInit = '{' . trim($mceInit, ',') . '}';
  1443 			$mceInit = '{' . trim( $mceInit, ',' ) . '}';
  1075 		} else {
  1444 		} else {
  1076 			$mceInit = '{}';
  1445 			$mceInit = '{}';
  1077 		}
  1446 		}
  1078 
  1447 
  1079 		if ( !empty(self::$qt_settings) ) {
  1448 		if ( ! empty( self::$qt_settings ) ) {
  1080 			foreach ( self::$qt_settings as $editor_id => $init ) {
  1449 			foreach ( self::$qt_settings as $editor_id => $init ) {
  1081 				$options = self::_parse_init( $init );
  1450 				$options = self::_parse_init( $init );
  1082 				$qtInit .= "'$editor_id':{$options},";
  1451 				$qtInit .= "'$editor_id':{$options},";
  1083 			}
  1452 			}
  1084 			$qtInit = '{' . trim($qtInit, ',') . '}';
  1453 			$qtInit = '{' . trim( $qtInit, ',' ) . '}';
  1085 		} else {
  1454 		} else {
  1086 			$qtInit = '{}';
  1455 			$qtInit = '{}';
  1087 		}
  1456 		}
  1088 
  1457 
  1089 		$ref = array(
  1458 		$ref = array(
  1090 			'plugins' => implode( ',', self::$plugins ),
  1459 			'plugins' => implode( ',', self::$plugins ),
  1091 			'theme' => 'modern',
  1460 			'theme' => 'modern',
  1092 			'language' => self::$mce_locale
  1461 			'language' => self::$mce_locale
  1093 		);
  1462 		);
  1094 
  1463 
  1095 		$suffix = ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) ? '' : '.min';
  1464 		$suffix = SCRIPT_DEBUG ? '' : '.min';
       
  1465 		$baseurl = self::get_baseurl();
       
  1466 		$version = 'ver=' . $tinymce_version;
  1096 
  1467 
  1097 		/**
  1468 		/**
  1098 		 * Fires immediately before the TinyMCE settings are printed.
  1469 		 * Fires immediately before the TinyMCE settings are printed.
  1099 		 *
  1470 		 *
  1100 		 * @since 3.2.0
  1471 		 * @since 3.2.0
  1104 		do_action( 'before_wp_tiny_mce', self::$mce_settings );
  1475 		do_action( 'before_wp_tiny_mce', self::$mce_settings );
  1105 		?>
  1476 		?>
  1106 
  1477 
  1107 		<script type="text/javascript">
  1478 		<script type="text/javascript">
  1108 		tinyMCEPreInit = {
  1479 		tinyMCEPreInit = {
  1109 			baseURL: "<?php echo self::$baseurl; ?>",
  1480 			baseURL: "<?php echo $baseurl; ?>",
  1110 			suffix: "<?php echo $suffix; ?>",
  1481 			suffix: "<?php echo $suffix; ?>",
  1111 			<?php
  1482 			<?php
  1112 
  1483 
  1113 			if ( self::$drag_drop_upload ) {
  1484 			if ( self::$drag_drop_upload ) {
  1114 				echo 'dragDropUpload: true,';
  1485 				echo 'dragDropUpload: true,';
  1121 			load_ext: function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
  1492 			load_ext: function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
  1122 		};
  1493 		};
  1123 		</script>
  1494 		</script>
  1124 		<?php
  1495 		<?php
  1125 
  1496 
  1126 		$baseurl = self::$baseurl;
       
  1127 		// Load tinymce.js when running from /src, else load wp-tinymce.js.gz (production) or tinymce.min.js (SCRIPT_DEBUG)
       
  1128 		$mce_suffix = false !== strpos( $GLOBALS['wp_version'], '-src' ) ? '' : '.min';
       
  1129 
       
  1130 		if ( $tmce_on ) {
  1497 		if ( $tmce_on ) {
  1131 			if ( $compressed ) {
  1498 			self::print_tinymce_scripts();
  1132 				echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
       
  1133 			} else {
       
  1134 				echo "<script type='text/javascript' src='{$baseurl}/tinymce{$mce_suffix}.js?$version'></script>\n";
       
  1135 				echo "<script type='text/javascript' src='{$baseurl}/plugins/compat3x/plugin{$suffix}.js?$version'></script>\n";
       
  1136 			}
       
  1137 
       
  1138 			echo "<script type='text/javascript'>\n" . self::wp_mce_translation() . "</script>\n";
       
  1139 
  1499 
  1140 			if ( self::$ext_plugins ) {
  1500 			if ( self::$ext_plugins ) {
  1141 				// Load the old-format English strings to prevent unsightly labels in old style popups
  1501 				// Load the old-format English strings to prevent unsightly labels in old style popups
  1142 				echo "<script type='text/javascript' src='{$baseurl}/langs/wp-langs-en.js?$version'></script>\n";
  1502 				echo "<script type='text/javascript' src='{$baseurl}/langs/wp-langs-en.js?$version'></script>\n";
  1143 			}
  1503 			}
  1164 			echo 'var ajaxurl = "' . admin_url( 'admin-ajax.php', 'relative' ) . '";';
  1524 			echo 'var ajaxurl = "' . admin_url( 'admin-ajax.php', 'relative' ) . '";';
  1165 
  1525 
  1166 		?>
  1526 		?>
  1167 
  1527 
  1168 		( function() {
  1528 		( function() {
  1169 			var init, edId, qtId, firstInit, wrapper;
  1529 			var init, id, $wrap;
  1170 
  1530 
  1171 			if ( typeof tinymce !== 'undefined' ) {
  1531 			if ( typeof tinymce !== 'undefined' ) {
  1172 				for ( edId in tinyMCEPreInit.mceInit ) {
  1532 				if ( tinymce.Env.ie && tinymce.Env.ie < 11 ) {
  1173 					if ( firstInit ) {
  1533 					tinymce.$( '.wp-editor-wrap ' ).removeClass( 'tmce-active' ).addClass( 'html-active' );
  1174 						init = tinyMCEPreInit.mceInit[edId] = tinymce.extend( {}, firstInit, tinyMCEPreInit.mceInit[edId] );
  1534 					return;
  1175 					} else {
  1535 				}
  1176 						init = firstInit = tinyMCEPreInit.mceInit[edId];
  1536 
  1177 					}
  1537 				for ( id in tinyMCEPreInit.mceInit ) {
  1178 
  1538 					init = tinyMCEPreInit.mceInit[id];
  1179 					wrapper = tinymce.DOM.select( '#wp-' + edId + '-wrap' )[0];
  1539 					$wrap = tinymce.$( '#wp-' + id + '-wrap' );
  1180 
  1540 
  1181 					if ( ( tinymce.DOM.hasClass( wrapper, 'tmce-active' ) || ! tinyMCEPreInit.qtInit.hasOwnProperty( edId ) ) &&
  1541 					if ( ( $wrap.hasClass( 'tmce-active' ) || ! tinyMCEPreInit.qtInit.hasOwnProperty( id ) ) && ! init.wp_skip_init ) {
  1182 						! init.wp_skip_init ) {
  1542 						tinymce.init( init );
  1183 
  1543 
  1184 						try {
  1544 						if ( ! window.wpActiveEditor ) {
  1185 							tinymce.init( init );
  1545 							window.wpActiveEditor = id;
  1186 
  1546 						}
  1187 							if ( ! window.wpActiveEditor ) {
       
  1188 								window.wpActiveEditor = edId;
       
  1189 							}
       
  1190 						} catch(e){}
       
  1191 					}
  1547 					}
  1192 				}
  1548 				}
  1193 			}
  1549 			}
  1194 
  1550 
  1195 			if ( typeof quicktags !== 'undefined' ) {
  1551 			if ( typeof quicktags !== 'undefined' ) {
  1196 				for ( qtId in tinyMCEPreInit.qtInit ) {
  1552 				for ( id in tinyMCEPreInit.qtInit ) {
  1197 					try {
  1553 					quicktags( tinyMCEPreInit.qtInit[id] );
  1198 						quicktags( tinyMCEPreInit.qtInit[qtId] );
  1554 
  1199 
  1555 					if ( ! window.wpActiveEditor ) {
  1200 						if ( ! window.wpActiveEditor ) {
  1556 						window.wpActiveEditor = id;
  1201 							window.wpActiveEditor = qtId;
       
  1202 						}
       
  1203 					} catch(e){};
       
  1204 				}
       
  1205 			}
       
  1206 
       
  1207 			if ( typeof jQuery !== 'undefined' ) {
       
  1208 				jQuery('.wp-editor-wrap').on( 'click.wp-editor', function() {
       
  1209 					if ( this.id ) {
       
  1210 						window.wpActiveEditor = this.id.slice( 3, -5 );
       
  1211 					}
       
  1212 				});
       
  1213 			} else {
       
  1214 				for ( qtId in tinyMCEPreInit.qtInit ) {
       
  1215 					document.getElementById( 'wp-' + qtId + '-wrap' ).onclick = function() {
       
  1216 						window.wpActiveEditor = this.id.slice( 3, -5 );
       
  1217 					}
  1557 					}
  1218 				}
  1558 				}
  1219 			}
  1559 			}
  1220 		}());
  1560 		}());
  1221 		</script>
  1561 		</script>
  1222 		<?php
  1562 		<?php
  1223 
  1563 
  1224 		if ( in_array( 'wplink', self::$plugins, true ) || in_array( 'link', self::$qt_buttons, true ) )
  1564 		if ( in_array( 'wplink', self::$plugins, true ) || in_array( 'link', self::$qt_buttons, true ) ) {
  1225 			self::wp_link_dialog();
  1565 			self::wp_link_dialog();
  1226 
  1566 		}
  1227 		if ( in_array( 'wpfullscreen', self::$plugins, true ) || in_array( 'fullscreen', self::$qt_buttons, true ) )
       
  1228 			self::wp_fullscreen_html();
       
  1229 
  1567 
  1230 		/**
  1568 		/**
  1231 		 * Fires after any core TinyMCE editor instances are created.
  1569 		 * Fires after any core TinyMCE editor instances are created.
  1232 		 *
  1570 		 *
  1233 		 * @since 3.2.0
  1571 		 * @since 3.2.0
  1235 		 * @param array $mce_settings TinyMCE settings array.
  1573 		 * @param array $mce_settings TinyMCE settings array.
  1236 		 */
  1574 		 */
  1237 		do_action( 'after_wp_tiny_mce', self::$mce_settings );
  1575 		do_action( 'after_wp_tiny_mce', self::$mce_settings );
  1238 	}
  1576 	}
  1239 
  1577 
       
  1578 	/**
       
  1579 	 * Outputs the HTML for distraction-free writing mode.
       
  1580 	 *
       
  1581 	 * @since 3.2.0
       
  1582 	 * @deprecated 4.3.0
       
  1583 	 *
       
  1584 	 * @static
       
  1585 	 */
  1240 	public static function wp_fullscreen_html() {
  1586 	public static function wp_fullscreen_html() {
  1241 		global $content_width;
  1587 		_deprecated_function( __FUNCTION__, '4.3.0' );
  1242 		$post = get_post();
       
  1243 
       
  1244 		$width = isset( $content_width ) && 800 > $content_width ? $content_width : 800;
       
  1245 		$width = $width + 22; // compensate for the padding and border
       
  1246 		$dfw_width = get_user_setting( 'dfw_width', $width );
       
  1247 		$save = $post && $post->post_status == 'publish' ? __('Update') : __('Save');
       
  1248 
       
  1249 		?>
       
  1250 		<div id="wp-fullscreen-body" class="wp-core-ui<?php if ( is_rtl() ) echo ' rtl'; ?>" data-theme-width="<?php echo (int) $width; ?>" data-dfw-width="<?php echo (int) $dfw_width; ?>">
       
  1251 		<div id="fullscreen-topbar">
       
  1252 			<div id="wp-fullscreen-toolbar">
       
  1253 			<div id="wp-fullscreen-close"><a href="#" onclick="wp.editor.fullscreen.off();return false;"><?php _e('Exit fullscreen'); ?></a></div>
       
  1254 			<div id="wp-fullscreen-central-toolbar" style="width:<?php echo $width; ?>px;">
       
  1255 
       
  1256 			<div id="wp-fullscreen-mode-bar">
       
  1257 				<div id="wp-fullscreen-modes" class="button-group">
       
  1258 					<a class="button wp-fullscreen-mode-tinymce" href="#" onclick="wp.editor.fullscreen.switchmode( 'tinymce' ); return false;"><?php _e( 'Visual' ); ?></a>
       
  1259 					<a class="button wp-fullscreen-mode-html" href="#" onclick="wp.editor.fullscreen.switchmode( 'html' ); return false;"><?php _ex( 'Text', 'Name for the Text editor tab (formerly HTML)' ); ?></a>
       
  1260 				</div>
       
  1261 			</div>
       
  1262 
       
  1263 			<div id="wp-fullscreen-button-bar"><div id="wp-fullscreen-buttons" class="mce-toolbar">
       
  1264 		<?php
       
  1265 
       
  1266 		$buttons = array(
       
  1267 			// format: title, onclick, show in both editors
       
  1268 			'bold' => array( 'title' => __('Bold (Ctrl + B)'), 'both' => false ),
       
  1269 			'italic' => array( 'title' => __('Italic (Ctrl + I)'), 'both' => false ),
       
  1270 			'bullist' => array( 'title' => __('Unordered list (Alt + Shift + U)'), 'both' => false ),
       
  1271 			'numlist' => array( 'title' => __('Ordered list (Alt + Shift + O)'), 'both' => false ),
       
  1272 			'blockquote' => array( 'title' => __('Blockquote (Alt + Shift + Q)'), 'both' => false ),
       
  1273 			'wp-media-library' => array( 'title' => __('Media library (Alt + Shift + M)'), 'both' => true ),
       
  1274 			'link' => array( 'title' => __('Insert/edit link (Alt + Shift + A)'), 'both' => true ),
       
  1275 			'unlink' => array( 'title' => __('Unlink (Alt + Shift + S)'), 'both' => false ),
       
  1276 			'help' => array( 'title' => __('Help (Alt + Shift + H)'), 'both' => false ),
       
  1277 		);
       
  1278 
       
  1279 		/**
       
  1280 		 * Filter the list of TinyMCE buttons for the fullscreen
       
  1281 		 * 'Distraction-Free Writing' editor.
       
  1282 		 *
       
  1283 		 * @since 3.2.0
       
  1284 		 *
       
  1285 		 * @param array $buttons An array of TinyMCE buttons for the DFW editor.
       
  1286 		 */
       
  1287 		$buttons = apply_filters( 'wp_fullscreen_buttons', $buttons );
       
  1288 
       
  1289 		foreach ( $buttons as $button => $args ) {
       
  1290 			if ( 'separator' == $args ) {
       
  1291 				continue;
       
  1292 			}
       
  1293 
       
  1294 			$onclick = ! empty( $args['onclick'] ) ? ' onclick="' . $args['onclick'] . '"' : '';
       
  1295 			$title = esc_attr( $args['title'] );
       
  1296 			?>
       
  1297 
       
  1298 			<div class="mce-widget mce-btn<?php if ( $args['both'] ) { ?> wp-fullscreen-both<?php } ?>">
       
  1299 			<button type="button" aria-label="<?php echo $title; ?>" title="<?php echo $title; ?>"<?php echo $onclick; ?> id="wp_fs_<?php echo $button; ?>">
       
  1300 				<i class="mce-ico mce-i-<?php echo $button; ?>"></i>
       
  1301 			</button>
       
  1302 			</div>
       
  1303 			<?php
       
  1304 		}
       
  1305 
       
  1306 		?>
       
  1307 
       
  1308 		</div></div>
       
  1309 
       
  1310 		<div id="wp-fullscreen-save">
       
  1311 			<input type="button" class="button button-primary right" value="<?php echo $save; ?>" onclick="wp.editor.fullscreen.save();" />
       
  1312 			<span class="wp-fullscreen-saved-message"><?php if ( $post && $post->post_status == 'publish' ) _e('Updated.'); else _e('Saved.'); ?></span>
       
  1313 			<span class="wp-fullscreen-error-message"><?php _e('Save failed.'); ?></span>
       
  1314 			<span class="spinner"></span>
       
  1315 		</div>
       
  1316 
       
  1317 		</div>
       
  1318 		</div>
       
  1319 	</div>
       
  1320 	<div id="wp-fullscreen-statusbar">
       
  1321 		<div id="wp-fullscreen-status">
       
  1322 			<div id="wp-fullscreen-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></div>
       
  1323 			<div id="wp-fullscreen-tagline"><?php _e('Just write.'); ?></div>
       
  1324 		</div>
       
  1325 	</div>
       
  1326 	</div>
       
  1327 
       
  1328 	<div class="fullscreen-overlay" id="fullscreen-overlay"></div>
       
  1329 	<div class="fullscreen-overlay fullscreen-fader fade-300" id="fullscreen-fader"></div>
       
  1330 	<?php
       
  1331 	}
  1588 	}
  1332 
  1589 
  1333 	/**
  1590 	/**
  1334 	 * Performs post queries for internal linking.
  1591 	 * Performs post queries for internal linking.
  1335 	 *
  1592 	 *
  1336 	 * @since 3.1.0
  1593 	 * @since 3.1.0
  1337 	 *
  1594 	 *
       
  1595 	 * @static
  1338 	 * @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments.
  1596 	 * @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments.
  1339 	 * @return false|array Results.
  1597 	 * @return false|array Results.
  1340 	 */
  1598 	 */
  1341 	public static function wp_link_query( $args = array() ) {
  1599 	public static function wp_link_query( $args = array() ) {
  1342 		$pts = get_post_types( array( 'public' => true ), 'objects' );
  1600 		$pts = get_post_types( array( 'public' => true ), 'objects' );
  1357 			$query['s'] = $args['s'];
  1615 			$query['s'] = $args['s'];
  1358 
  1616 
  1359 		$query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0;
  1617 		$query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0;
  1360 
  1618 
  1361 		/**
  1619 		/**
  1362 		 * Filter the link query arguments.
  1620 		 * Filters the link query arguments.
  1363 		 *
  1621 		 *
  1364 		 * Allows modification of the link query arguments before querying.
  1622 		 * Allows modification of the link query arguments before querying.
  1365 		 *
  1623 		 *
  1366 		 * @see WP_Query for a full list of arguments
  1624 		 * @see WP_Query for a full list of arguments
  1367 		 *
  1625 		 *
  1372 		$query = apply_filters( 'wp_link_query_args', $query );
  1630 		$query = apply_filters( 'wp_link_query_args', $query );
  1373 
  1631 
  1374 		// Do main query.
  1632 		// Do main query.
  1375 		$get_posts = new WP_Query;
  1633 		$get_posts = new WP_Query;
  1376 		$posts = $get_posts->query( $query );
  1634 		$posts = $get_posts->query( $query );
  1377 		// Check if any posts were found.
       
  1378 		if ( ! $get_posts->post_count )
       
  1379 			return false;
       
  1380 
  1635 
  1381 		// Build results.
  1636 		// Build results.
  1382 		$results = array();
  1637 		$results = array();
  1383 		foreach ( $posts as $post ) {
  1638 		foreach ( $posts as $post ) {
  1384 			if ( 'post' == $post->post_type )
  1639 			if ( 'post' == $post->post_type )
  1393 				'info' => $info,
  1648 				'info' => $info,
  1394 			);
  1649 			);
  1395 		}
  1650 		}
  1396 
  1651 
  1397 		/**
  1652 		/**
  1398 		 * Filter the link query results.
  1653 		 * Filters the link query results.
  1399 		 *
  1654 		 *
  1400 		 * Allows modification of the returned link query results.
  1655 		 * Allows modification of the returned link query results.
  1401 		 *
  1656 		 *
  1402 		 * @since 3.7.0
  1657 		 * @since 3.7.0
  1403 		 *
  1658 		 *
  1414 		 *                                 the 'singular_name' post type label otherwise.
  1669 		 *                                 the 'singular_name' post type label otherwise.
  1415 		 *     }
  1670 		 *     }
  1416 		 * }
  1671 		 * }
  1417 		 * @param array $query  An array of WP_Query arguments.
  1672 		 * @param array $query  An array of WP_Query arguments.
  1418 		 */
  1673 		 */
  1419 		return apply_filters( 'wp_link_query', $results, $query );
  1674 		$results = apply_filters( 'wp_link_query', $results, $query );
       
  1675 
       
  1676 		return ! empty( $results ) ? $results : false;
  1420 	}
  1677 	}
  1421 
  1678 
  1422 	/**
  1679 	/**
  1423 	 * Dialog for internal linking.
  1680 	 * Dialog for internal linking.
  1424 	 *
  1681 	 *
  1425 	 * @since 3.1.0
  1682 	 * @since 3.1.0
       
  1683 	 *
       
  1684 	 * @static
  1426 	 */
  1685 	 */
  1427 	public static function wp_link_dialog() {
  1686 	public static function wp_link_dialog() {
  1428 		$search_panel_visible = '1' == get_user_setting( 'wplink', '0' ) ? ' search-panel-visible' : '';
  1687 		// Run once
       
  1688 		if ( self::$link_dialog_printed ) {
       
  1689 			return;
       
  1690 		}
       
  1691 
       
  1692 		self::$link_dialog_printed = true;
  1429 
  1693 
  1430 		// display: none is required here, see #WP27605
  1694 		// display: none is required here, see #WP27605
  1431 		?>
  1695 		?>
  1432 		<div id="wp-link-backdrop" style="display: none"></div>
  1696 		<div id="wp-link-backdrop" style="display: none"></div>
  1433 		<div id="wp-link-wrap" class="wp-core-ui<?php echo $search_panel_visible; ?>" style="display: none">
  1697 		<div id="wp-link-wrap" class="wp-core-ui" style="display: none" role="dialog" aria-labelledby="link-modal-title">
  1434 		<form id="wp-link" tabindex="-1">
  1698 		<form id="wp-link" tabindex="-1">
  1435 		<?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
  1699 		<?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
  1436 		<div id="link-modal-title">
  1700 		<h1 id="link-modal-title"><?php _e( 'Insert/edit link' ) ?></h1>
  1437 			<?php _e( 'Insert/edit link' ) ?>
  1701 		<button type="button" id="wp-link-close"><span class="screen-reader-text"><?php _e( 'Close' ); ?></span></button>
  1438 			<button type="button" id="wp-link-close"><span class="screen-reader-text"><?php _e( 'Close' ); ?></span></button>
       
  1439 	 	</div>
       
  1440 		<div id="link-selector">
  1702 		<div id="link-selector">
  1441 			<div id="link-options">
  1703 			<div id="link-options">
  1442 				<p class="howto"><?php _e( 'Enter the destination URL' ); ?></p>
  1704 				<p class="howto" id="wplink-enter-url"><?php _e( 'Enter the destination URL' ); ?></p>
  1443 				<div>
  1705 				<div>
  1444 					<label><span><?php _e( 'URL' ); ?></span><input id="wp-link-url" type="text" /></label>
  1706 					<label><span><?php _e( 'URL' ); ?></span>
       
  1707 					<input id="wp-link-url" type="text" aria-describedby="wplink-enter-url" /></label>
  1445 				</div>
  1708 				</div>
  1446 				<div class="wp-link-text-field">
  1709 				<div class="wp-link-text-field">
  1447 					<label><span><?php _e( 'Link Text' ); ?></span><input id="wp-link-text" type="text" /></label>
  1710 					<label><span><?php _e( 'Link Text' ); ?></span>
       
  1711 					<input id="wp-link-text" type="text" /></label>
  1448 				</div>
  1712 				</div>
  1449 				<div class="link-target">
  1713 				<div class="link-target">
  1450 					<label><span>&nbsp;</span><input type="checkbox" id="wp-link-target" /> <?php _e( 'Open link in a new window/tab' ); ?></label>
  1714 					<label><span></span>
       
  1715 					<input type="checkbox" id="wp-link-target" /> <?php _e( 'Open link in a new tab' ); ?></label>
  1451 				</div>
  1716 				</div>
  1452 			</div>
  1717 			</div>
  1453 			<p class="howto"><a href="#" id="wp-link-search-toggle"><?php _e( 'Or link to existing content' ); ?></a></p>
  1718 			<p class="howto" id="wplink-link-existing-content"><?php _e( 'Or link to existing content' ); ?></p>
  1454 			<div id="search-panel">
  1719 			<div id="search-panel">
  1455 				<div class="link-search-wrapper">
  1720 				<div class="link-search-wrapper">
  1456 					<label>
  1721 					<label>
  1457 						<span class="search-label"><?php _e( 'Search' ); ?></span>
  1722 						<span class="search-label"><?php _e( 'Search' ); ?></span>
  1458 						<input type="search" id="wp-link-search" class="link-search-field" autocomplete="off" />
  1723 						<input type="search" id="wp-link-search" class="link-search-field" autocomplete="off" aria-describedby="wplink-link-existing-content" />
  1459 						<span class="spinner"></span>
  1724 						<span class="spinner"></span>
  1460 					</label>
  1725 					</label>
  1461 				</div>
  1726 				</div>
  1462 				<div id="search-results" class="query-results" tabindex="0">
  1727 				<div id="search-results" class="query-results" tabindex="0">
  1463 					<ul></ul>
  1728 					<ul></ul>
  1472 					</div>
  1737 					</div>
  1473 					<ul></ul>
  1738 					<ul></ul>
  1474 					<div class="river-waiting">
  1739 					<div class="river-waiting">
  1475 						<span class="spinner"></span>
  1740 						<span class="spinner"></span>
  1476 					</div>
  1741 					</div>
  1477 				</div>
  1742  				</div>
  1478 			</div>
  1743  			</div>
  1479 		</div>
  1744 		</div>
  1480 		<div class="submitbox">
  1745 		<div class="submitbox">
  1481 			<div id="wp-link-cancel">
  1746 			<div id="wp-link-cancel">
  1482 				<a class="submitdelete deletion" href="#"><?php _e( 'Cancel' ); ?></a>
  1747 				<button type="button" class="button"><?php _e( 'Cancel' ); ?></button>
  1483 			</div>
  1748 			</div>
  1484 			<div id="wp-link-update">
  1749 			<div id="wp-link-update">
  1485 				<input type="submit" value="<?php esc_attr_e( 'Add Link' ); ?>" class="button button-primary" id="wp-link-submit" name="wp-link-submit">
  1750 				<input type="submit" value="<?php esc_attr_e( 'Add Link' ); ?>" class="button button-primary" id="wp-link-submit" name="wp-link-submit">
  1486 			</div>
  1751 			</div>
  1487 		</div>
  1752 		</div>