WordPress 3.4
[autoinstalls/wordpress.git] / wp-includes / class-wp-editor.php
1 <?php
2 /**
3  * Facilitates adding of the WordPress editor as used on the Write and Edit screens.
4  *
5  * @package WordPress
6  * @since 3.3.0
7  *
8  * Private, not included by default. See wp_editor() in wp-includes/general-template.php.
9  */
10
11 final class _WP_Editors {
12         public static $mce_locale;
13
14         private static $mce_settings = array();
15         private static $qt_settings = array();
16         private static $plugins = array();
17         private static $qt_buttons = array();
18         private static $ext_plugins;
19         private static $baseurl;
20         private static $first_init;
21         private static $this_tinymce = false;
22         private static $this_quicktags = false;
23         private static $has_tinymce = false;
24         private static $has_quicktags = false;
25         private static $has_medialib = false;
26         private static $editor_buttons_css = true;
27
28         private function __construct() {}
29
30         public static function parse_settings($editor_id, $settings) {
31                 $set = wp_parse_args( $settings,  array(
32                         'wpautop' => true, // use wpautop?
33                         'media_buttons' => true, // show insert/upload button(s)
34                         'textarea_name' => $editor_id, // set the textarea name to something different, square brackets [] can be used here
35                         'textarea_rows' => get_option('default_post_edit_rows', 10), // rows="..."
36                         'tabindex' => '',
37                         'editor_css' => '', // intended for extra styles for both visual and HTML editors buttons, needs to include the <style> tags, can use "scoped".
38                         'editor_class' => '', // add extra class(es) to the editor textarea
39                         'teeny' => false, // output the minimal editor config used in Press This
40                         'dfw' => false, // replace the default fullscreen with DFW (needs specific DOM elements and css)
41                         'tinymce' => true, // load TinyMCE, can be used to pass settings directly to TinyMCE using an array()
42                         'quicktags' => true // load Quicktags, can be used to pass settings directly to Quicktags using an array()
43                 ) );
44
45                 self::$this_tinymce = ( $set['tinymce'] && user_can_richedit() );
46                 self::$this_quicktags = (bool) $set['quicktags'];
47
48                 if ( self::$this_tinymce )
49                         self::$has_tinymce = true;
50
51                 if ( self::$this_quicktags )
52                         self::$has_quicktags = true;
53
54                 return $set;
55         }
56
57         /**
58          * Outputs the HTML for a single instance of the editor.
59          *
60          * @param string $content The initial content of the editor.
61          * @param string $editor_id ID for the textarea and TinyMCE and Quicktags instances (can contain only ASCII letters and numbers).
62          * @param array $settings See the _parse_settings() method for description.
63          */
64         public static function editor( $content, $editor_id, $settings = array() ) {
65
66                 $set = self::parse_settings($editor_id, $settings);
67                 $editor_class = ' class="' . trim( $set['editor_class'] . ' wp-editor-area' ) . '"';
68                 $tabindex = $set['tabindex'] ? ' tabindex="' . (int) $set['tabindex'] . '"' : '';
69                 $rows = ' rows="' . (int) $set['textarea_rows'] . '"';
70                 $switch_class = 'html-active';
71                 $toolbar = $buttons = '';
72
73                 if ( !current_user_can( 'upload_files' ) )
74                         $set['media_buttons'] = false;
75
76                 if ( self::$this_quicktags && self::$this_tinymce ) {
77                         $switch_class = 'html-active';
78
79                         if ( 'html' == wp_default_editor() ) {
80                                 add_filter('the_editor_content', 'wp_htmledit_pre');
81                         } else {
82                                 add_filter('the_editor_content', 'wp_richedit_pre');
83                                 $switch_class = 'tmce-active';
84                         }
85
86                         $buttons .= '<a id="' . $editor_id . '-html" class="hide-if-no-js wp-switch-editor switch-html" onclick="switchEditors.switchto(this);">' . __('HTML') . "</a>\n";
87                         $buttons .= '<a id="' . $editor_id . '-tmce" class="hide-if-no-js wp-switch-editor switch-tmce" onclick="switchEditors.switchto(this);">' . __('Visual') . "</a>\n";
88                 }
89
90                 echo '<div id="wp-' . $editor_id . '-wrap" class="wp-editor-wrap ' . $switch_class . '">';
91
92                 if ( self::$editor_buttons_css ) {
93                         wp_print_styles('editor-buttons');
94                         self::$editor_buttons_css = false;
95                 }
96
97                 if ( !empty($set['editor_css']) )
98                         echo $set['editor_css'] . "\n";
99
100                 if ( !empty($buttons) || $set['media_buttons'] ) {
101                         echo '<div id="wp-' . $editor_id . '-editor-tools" class="wp-editor-tools">';
102                         echo $buttons;
103
104                         if ( $set['media_buttons'] ) {
105                                 self::$has_medialib = true;
106
107                                 if ( !function_exists('media_buttons') )
108                                         include(ABSPATH . 'wp-admin/includes/media.php');
109
110                                 echo '<div id="wp-' . $editor_id . '-media-buttons" class="hide-if-no-js wp-media-buttons">';
111                                 do_action('media_buttons', $editor_id);
112                                 echo "</div>\n";
113                         }
114                         echo "</div>\n";
115                 }
116
117                 $the_editor = apply_filters('the_editor', '<div id="wp-' . $editor_id . '-editor-container" class="wp-editor-container"><textarea' . $editor_class . $rows . $tabindex . ' cols="40" name="' . $set['textarea_name'] . '" id="' . $editor_id . '">%s</textarea></div>');
118                 $content = apply_filters('the_editor_content', $content);
119
120                 printf($the_editor, $content);
121                 echo "\n</div>\n\n";
122
123                 self::editor_settings($editor_id, $set);
124         }
125
126         public static function editor_settings($editor_id, $set) {
127                 global $editor_styles, $post;
128                 $first_run = false;
129
130                 if ( empty(self::$first_init) ) {
131                         if ( is_admin() ) {
132                                 add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
133                                 add_action( 'admin_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
134                         } else {
135                                 add_action( 'wp_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
136                                 add_action( 'wp_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
137                         }
138                 }
139
140                 if ( self::$this_quicktags ) {
141
142                         $qtInit = array(
143                                 'id' => $editor_id,
144                                 'buttons' => ''
145                         );
146
147                         if ( is_array($set['quicktags']) )
148                                 $qtInit = array_merge($qtInit, $set['quicktags']);
149
150                         if ( empty($qtInit['buttons']) )
151                                 $qtInit['buttons'] = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,spell,close';
152
153                         if ( $set['dfw'] )
154                                 $qtInit['buttons'] .= ',fullscreen';
155
156                         $qtInit = apply_filters('quicktags_settings', $qtInit, $editor_id);
157                         self::$qt_settings[$editor_id] = $qtInit;
158
159                         self::$qt_buttons = array_merge( self::$qt_buttons, explode(',', $qtInit['buttons']) );
160                 }
161
162                 if ( self::$this_tinymce ) {
163
164                         if ( empty(self::$first_init) ) {
165                                 self::$baseurl = includes_url('js/tinymce');
166                                 self::$mce_locale = $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
167                                 $no_captions = (bool) apply_filters( 'disable_captions', '' );
168                                 $plugins = array( 'inlinepopups', 'spellchecker', 'tabfocus', 'paste', 'media', 'fullscreen', 'wordpress', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs' );
169                                 $first_run = true;
170                                 $ext_plugins = '';
171
172                                 if ( $set['teeny'] ) {
173                                         self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs'), $editor_id );
174                                 } else {
175                                         /*
176                                         The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
177                                         It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
178                                         The url should be absolute and should include the js file name to be loaded. Example:
179                                         array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
180                                         If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
181                                         */
182                                         $mce_external_plugins = apply_filters('mce_external_plugins', array());
183
184                                         if ( ! empty($mce_external_plugins) ) {
185
186                                                 /*
187                                                 The following filter loads external language files for TinyMCE plugins.
188                                                 It takes an associative array 'plugin_name' => 'path', where path is the
189                                                 include path to the file. The language file should follow the same format as
190                                                 /tinymce/langs/wp-langs.php and should define a variable $strings that
191                                                 holds all translated strings.
192                                                 When this filter is not used, the function will try to load {mce_locale}.js.
193                                                 If that is not found, en.js will be tried next.
194                                                 */
195                                                 $mce_external_languages = apply_filters('mce_external_languages', array());
196
197                                                 $loaded_langs = array();
198                                                 $strings = '';
199
200                                                 if ( ! empty($mce_external_languages) ) {
201                                                         foreach ( $mce_external_languages as $name => $path ) {
202                                                                 if ( @is_file($path) && @is_readable($path) ) {
203                                                                         include_once($path);
204                                                                         $ext_plugins .= $strings . "\n";
205                                                                         $loaded_langs[] = $name;
206                                                                 }
207                                                         }
208                                                 }
209
210                                                 foreach ( $mce_external_plugins as $name => $url ) {
211
212                                                         if ( is_ssl() ) $url = str_replace('http://', 'https://', $url);
213
214                                                         $plugins[] = '-' . $name;
215
216                                                         $plugurl = dirname($url);
217                                                         $strings = $str1 = $str2 = '';
218                                                         if ( ! in_array($name, $loaded_langs) ) {
219                                                                 $path = str_replace( content_url(), '', $plugurl );
220                                                                 $path = WP_CONTENT_DIR . $path . '/langs/';
221
222                                                                 if ( function_exists('realpath') )
223                                                                         $path = trailingslashit( realpath($path) );
224
225                                                                 if ( @is_file($path . $mce_locale . '.js') )
226                                                                         $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
227
228                                                                 if ( @is_file($path . $mce_locale . '_dlg.js') )
229                                                                         $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
230
231                                                                 if ( 'en' != $mce_locale && empty($strings) ) {
232                                                                         if ( @is_file($path . 'en.js') ) {
233                                                                                 $str1 = @file_get_contents($path . 'en.js');
234                                                                                 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
235                                                                         }
236
237                                                                         if ( @is_file($path . 'en_dlg.js') ) {
238                                                                                 $str2 = @file_get_contents($path . 'en_dlg.js');
239                                                                                 $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
240                                                                         }
241                                                                 }
242
243                                                                 if ( ! empty($strings) )
244                                                                         $ext_plugins .= "\n" . $strings . "\n";
245                                                         }
246
247                                                         $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
248                                                         $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
249                                                 }
250                                         }
251
252                                         $plugins = array_unique( apply_filters('tiny_mce_plugins', $plugins) );
253                                 }
254
255                                 if ( $set['dfw'] )
256                                         $plugins[] = 'wpfullscreen';
257
258                                 self::$plugins = $plugins;
259                                 self::$ext_plugins = $ext_plugins;
260
261                                 /*
262                                 translators: These languages show up in the spellchecker drop-down menu, in the order specified, and with the first
263                                 language listed being the default language. They must be comma-separated and take the format of name=code, where name
264                                 is the language name (which you may internationalize), and code is a valid ISO 639 language code. Please test the
265                                 spellchecker with your values.
266                                 */
267                                 $mce_spellchecker_languages = __( 'English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv' );
268
269                                 /*
270                                 The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
271                                 By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
272                                 The + sign marks the default language. More: http://www.tinymce.com/wiki.php/Plugin:spellchecker.
273                                 */
274                                 $mce_spellchecker_languages = apply_filters( 'mce_spellchecker_languages', '+' . $mce_spellchecker_languages );
275
276                                 self::$first_init = array(
277                                         'mode' => 'exact',
278                                         'width' => '100%',
279                                         'theme' => 'advanced',
280                                         'skin' => 'wp_theme',
281                                         'language' => self::$mce_locale,
282                                         'spellchecker_languages' => $mce_spellchecker_languages,
283                                         'theme_advanced_toolbar_location' => 'top',
284                                         'theme_advanced_toolbar_align' => 'left',
285                                         'theme_advanced_statusbar_location' => 'bottom',
286                                         'theme_advanced_resizing' => true,
287                                         'theme_advanced_resize_horizontal' => false,
288                                         'dialog_type' => 'modal',
289                                         'formats' => "{
290                                                 alignleft : [
291                                                         {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
292                                                         {selector : 'img,table', classes : 'alignleft'}
293                                                 ],
294                                                 aligncenter : [
295                                                         {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
296                                                         {selector : 'img,table', classes : 'aligncenter'}
297                                                 ],
298                                                 alignright : [
299                                                         {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
300                                                         {selector : 'img,table', classes : 'alignright'}
301                                                 ],
302                                                 strikethrough : {inline : 'del'}
303                                         }",
304                                         'relative_urls' => false,
305                                         'remove_script_host' => false,
306                                         'convert_urls' => false,
307                                         'remove_linebreaks' => true,
308                                         'gecko_spellcheck' => true,
309                                         'fix_list_elements' => true,
310                                         'keep_styles' => false,
311                                         'entities' => '38,amp,60,lt,62,gt',
312                                         'accessibility_focus' => true,
313                                         'tabfocus_elements' => 'title,publish',
314                                         'media_strict' => false,
315                                         'paste_remove_styles' => true,
316                                         'paste_remove_spans' => true,
317                                         'paste_strip_class_attributes' => 'all',
318                                         'paste_text_use_dialog' => true,
319                                         'spellchecker_rpc_url' => self::$baseurl . '/plugins/spellchecker/rpc.php',
320                                         'extended_valid_elements' => 'article[*],aside[*],audio[*],canvas[*],command[*],datalist[*],details[*],embed[*],figcaption[*],figure[*],footer[*],header[*],hgroup[*],keygen[*],mark[*],meter[*],nav[*],output[*],progress[*],section[*],source[*],summary,time[*],video[*],wbr',
321                                         'wpeditimage_disable_captions' => $no_captions,
322                                         'wp_fullscreen_content_css' => self::$baseurl . '/plugins/wpfullscreen/css/wp-fullscreen.css',
323                                         'plugins' => implode( ',', $plugins )
324                                 );
325
326                                 // load editor_style.css if the current theme supports it
327                                 if ( ! empty( $editor_styles ) && is_array( $editor_styles ) ) {
328                                         $mce_css = array();
329                                         $editor_styles = array_unique($editor_styles);
330                                         $style_uri = get_stylesheet_directory_uri();
331                                         $style_dir = get_stylesheet_directory();
332
333                                         if ( is_child_theme() ) {
334                                                 $template_uri = get_template_directory_uri();
335                                                 $template_dir = get_template_directory();
336
337                                                 foreach ( $editor_styles as $key => $file ) {
338                                                         if ( $file && file_exists( "$template_dir/$file" ) ) {
339                                                                 $mce_css[] = "$template_uri/$file";
340                                                                 $editor_styles[$key] = '';
341                                                         }
342                                                 }
343                                         }
344
345                                         foreach ( $editor_styles as $file ) {
346                                                 if ( $file && file_exists( "$style_dir/$file" ) )
347                                                         $mce_css[] = "$style_uri/$file";
348                                         }
349
350                                         $mce_css = implode( ',', $mce_css );
351                                 } else {
352                                         $mce_css = '';
353                                 }
354
355                                 $mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
356
357                                 if ( ! empty($mce_css) )
358                                         self::$first_init['content_css'] = $mce_css;
359                         }
360
361                         if ( $set['teeny'] ) {
362                                 $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold', 'italic', 'underline', 'blockquote', 'separator', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'undo', 'redo', 'link', 'unlink', 'fullscreen'), $editor_id );
363                                 $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array();
364                         } else {
365                                 $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', '|', 'bullist', 'numlist', 'blockquote', '|', 'justifyleft', 'justifycenter', 'justifyright', '|', 'link', 'unlink', 'wp_more', '|', 'spellchecker', 'fullscreen', 'wp_adv' ), $editor_id);
366                                 $mce_buttons_2 = apply_filters('mce_buttons_2', array( 'formatselect', 'underline', 'justifyfull', 'forecolor', '|', 'pastetext', 'pasteword', 'removeformat', '|', 'charmap', '|', 'outdent', 'indent', '|', 'undo', 'redo', 'wp_help' ), $editor_id);
367                                 $mce_buttons_3 = apply_filters('mce_buttons_3', array(), $editor_id);
368                                 $mce_buttons_4 = apply_filters('mce_buttons_4', array(), $editor_id);
369                         }
370
371                         $body_class = $editor_id;
372
373                         if ( isset($post) )
374                                 $body_class .= " post-type-$post->post_type";
375
376                         if ( !empty($set['tinymce']['body_class']) ) {
377                                 $body_class .= ' ' . $set['tinymce']['body_class'];
378                                 unset($set['tinymce']['body_class']);
379                         }
380
381                         if ( $set['dfw'] ) {
382                                 // replace the first 'fullscreen' with 'wp_fullscreen'
383                                 if ( ($key = array_search('fullscreen', $mce_buttons)) !== false )
384                                         $mce_buttons[$key] = 'wp_fullscreen';
385                                 elseif ( ($key = array_search('fullscreen', $mce_buttons_2)) !== false )
386                                         $mce_buttons_2[$key] = 'wp_fullscreen';
387                                 elseif ( ($key = array_search('fullscreen', $mce_buttons_3)) !== false )
388                                         $mce_buttons_3[$key] = 'wp_fullscreen';
389                                 elseif ( ($key = array_search('fullscreen', $mce_buttons_4)) !== false )
390                                         $mce_buttons_4[$key] = 'wp_fullscreen';
391                         }
392
393                         $mceInit = array (
394                                 'elements' => $editor_id,
395                                 'wpautop' => (bool) $set['wpautop'],
396                                 'remove_linebreaks' => (bool) $set['wpautop'],
397                                 'apply_source_formatting' => (bool) !$set['wpautop'],
398                                 'theme_advanced_buttons1' => implode($mce_buttons, ','),
399                                 'theme_advanced_buttons2' => implode($mce_buttons_2, ','),
400                                 'theme_advanced_buttons3' => implode($mce_buttons_3, ','),
401                                 'theme_advanced_buttons4' => implode($mce_buttons_4, ','),
402                                 'body_class' => $body_class
403                         );
404
405                         if ( $first_run )
406                                 $mceInit = array_merge(self::$first_init, $mceInit);
407
408                         if ( is_array($set['tinymce']) )
409                                 $mceInit = array_merge($mceInit, $set['tinymce']);
410
411                         // For people who really REALLY know what they're doing with TinyMCE
412                         // You can modify initArray to add, remove, change elements of the config before tinyMCE.init
413                         // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through this filter.
414                         // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
415                         if ( $set['teeny'] ) {
416                                 $mceInit = apply_filters('teeny_mce_before_init', $mceInit, $editor_id);
417                         } else {
418                                 $mceInit = apply_filters('tiny_mce_before_init', $mceInit, $editor_id);
419                         }
420
421                         if ( empty($mceInit['theme_advanced_buttons3']) && !empty($mceInit['theme_advanced_buttons4']) ) {
422                                 $mceInit['theme_advanced_buttons3'] = $mceInit['theme_advanced_buttons4'];
423                                 $mceInit['theme_advanced_buttons4'] = '';
424                         }
425
426                         self::$mce_settings[$editor_id] = $mceInit;
427                 } // end if self::$this_tinymce
428         }
429
430         private static function _parse_init($init) {
431                 $options = '';
432
433                 foreach ( $init as $k => $v ) {
434                         if ( is_bool($v) ) {
435                                 $val = $v ? 'true' : 'false';
436                                 $options .= $k . ':' . $val . ',';
437                                 continue;
438                         } elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
439                                 $options .= $k . ':' . $v . ',';
440                                 continue;
441                         }
442                         $options .= $k . ':"' . $v . '",';
443                 }
444
445                 return '{' . trim( $options, ' ,' ) . '}';
446         }
447
448         public static function enqueue_scripts() {
449                 wp_enqueue_script('word-count');
450
451                 if ( self::$has_tinymce )
452                         wp_enqueue_script('editor');
453
454                 if ( self::$has_quicktags )
455                         wp_enqueue_script('quicktags');
456
457                 if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) ) {
458                         wp_enqueue_script('wplink');
459                         wp_enqueue_script('wpdialogs-popup');
460                         wp_enqueue_style('wp-jquery-ui-dialog');
461                 }
462
463                 if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
464                         wp_enqueue_script('wp-fullscreen');
465
466                 if ( self::$has_medialib ) {
467                         add_thickbox();
468                         wp_enqueue_script('media-upload');
469                 }
470         }
471
472         public static function editor_js() {
473                 global $tinymce_version, $concatenate_scripts, $compress_scripts;
474
475                 /**
476                  * Filter "tiny_mce_version" is deprecated
477                  *
478                  * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
479                  * These plugins can be refreshed by appending query string to the URL passed to "mce_external_plugins" filter.
480                  * 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).
481                  */
482                 $version = 'ver=' . $tinymce_version;
483                 $tmce_on = !empty(self::$mce_settings);
484
485                 if ( ! isset($concatenate_scripts) )
486                         script_concat_settings();
487
488                 $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
489                         && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
490
491                 if ( $tmce_on && 'en' != self::$mce_locale )
492                         include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
493
494                 $mceInit = $qtInit = '';
495                 if ( $tmce_on ) {
496                         foreach ( self::$mce_settings as $editor_id => $init ) {
497                                 $options = self::_parse_init( $init );
498                                 $mceInit .= "'$editor_id':{$options},";
499                         }
500                         $mceInit = '{' . trim($mceInit, ',') . '}';
501                 } else {
502                         $mceInit = '{}';
503                 }
504
505                 if ( !empty(self::$qt_settings) ) {
506                         foreach ( self::$qt_settings as $editor_id => $init ) {
507                                 $options = self::_parse_init( $init );
508                                 $qtInit .= "'$editor_id':{$options},";
509                         }
510                         $qtInit = '{' . trim($qtInit, ',') . '}';
511                 } else {
512                         $qtInit = '{}';
513                 }
514
515                 $ref = array(
516                         'plugins' => implode( ',', self::$plugins ),
517                         'theme' => 'advanced',
518                         'language' => self::$mce_locale
519                 );
520
521                 $suffix = ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) ? '_src' : '';
522
523                 do_action('before_wp_tiny_mce', self::$mce_settings);
524 ?>
525
526         <script type="text/javascript">
527                 tinyMCEPreInit = {
528                         base : "<?php echo self::$baseurl; ?>",
529                         suffix : "<?php echo $suffix; ?>",
530                         query : "<?php echo $version; ?>",
531                         mceInit : <?php echo $mceInit; ?>,
532                         qtInit : <?php echo $qtInit; ?>,
533                         ref : <?php echo self::_parse_init( $ref ); ?>,
534                         load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
535                 };
536         </script>
537 <?php
538
539                 $baseurl = self::$baseurl;
540
541                 if ( $tmce_on ) {
542                         if ( $compressed )
543                                 echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
544                         else
545                                 echo "<script type='text/javascript' src='{$baseurl}/tiny_mce.js?$version'></script>\n";
546
547                         if ( 'en' != self::$mce_locale && isset($lang) )
548                                 echo "<script type='text/javascript'>\n$lang\n</script>\n";
549                         else
550                                 echo "<script type='text/javascript' src='{$baseurl}/langs/wp-langs-en.js?$version'></script>\n";
551                 }
552 ?>
553
554         <script type="text/javascript">
555                 (function(){
556                         var init, ed, qt, first_init, mce = <?php echo wp_default_editor() == 'tinymce' ? 'true' : 'false'; ?>;
557
558                         if ( typeof(tinymce) == 'object' ) {
559                                 // mark wp_theme/ui.css as loaded
560                                 tinymce.DOM.files[tinymce.baseURI.getURI() + '/themes/advanced/skins/wp_theme/ui.css'] = true;
561
562                                 for ( ed in tinyMCEPreInit.mceInit ) {
563                                         if ( first_init ) {
564                                                 init = tinyMCEPreInit.mceInit[ed] = tinymce.extend( {}, first_init, tinyMCEPreInit.mceInit[ed] );
565                                         } else {
566                                                 init = first_init = tinyMCEPreInit.mceInit[ed];
567                                         }
568
569                                         if ( mce )
570                                                 try { tinymce.init(init); } catch(e){}
571                                 }
572                         }
573
574                         if ( typeof(QTags) == 'function' ) {
575                                 for ( qt in tinyMCEPreInit.qtInit ) {
576                                         try { quicktags( tinyMCEPreInit.qtInit[qt] ); } catch(e){}
577                                 }
578                         }
579                 })();
580
581                 var wpActiveEditor;
582
583                 jQuery('.wp-editor-wrap').mousedown(function(e){
584                         wpActiveEditor = this.id.slice(3, -5);
585                 });
586
587 <?php
588
589                 if ( self::$ext_plugins )
590                         echo self::$ext_plugins . "\n";
591
592                 if ( ! $compressed && $tmce_on ) {
593 ?>
594                 (function(){var t=tinyMCEPreInit,sl=tinymce.ScriptLoader,ln=t.ref.language,th=t.ref.theme,pl=t.ref.plugins;sl.markDone(t.base+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'_dlg.js');sl.markDone(t.base+'/themes/advanced/skins/wp_theme/ui.css');tinymce.each(pl.split(','),function(n){if(n&&n.charAt(0)!='-'){sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'.js');sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'_dlg.js');}});})();
595 <?php
596                 }
597
598                 if ( !is_admin() )
599                         echo 'var ajaxurl = "' . admin_url( 'admin-ajax.php', 'relative' ) . '";';
600 ?>
601         </script>
602 <?php
603
604                 if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) )
605                         self::wp_link_dialog();
606
607                 if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
608                         self::wp_fullscreen_html();
609
610                 do_action('after_wp_tiny_mce', self::$mce_settings);
611         }
612
613         public static function wp_fullscreen_html() {
614                 global $content_width, $post;
615
616                 $width = isset($content_width) && 800 > $content_width ? $content_width : 800;
617                 $width = $width + 22; // compensate for the padding and border
618                 $dfw_width = get_user_setting( 'dfw_width', $width );
619                 $save = isset($post->post_status) && $post->post_status == 'publish' ? __('Update') : __('Save');
620         ?>
621         <div id="wp-fullscreen-body"<?php if ( is_rtl() ) echo ' class="rtl"'; ?>>
622         <div id="fullscreen-topbar">
623                 <div id="wp-fullscreen-toolbar">
624                         <div id="wp-fullscreen-close"><a href="#" onclick="fullscreen.off();return false;"><?php _e('Exit fullscreen'); ?></a></div>
625                         <div id="wp-fullscreen-central-toolbar" style="width:<?php echo $width; ?>px;">
626
627                         <div id="wp-fullscreen-mode-bar"><div id="wp-fullscreen-modes">
628                                 <a href="#" onclick="fullscreen.switchmode('tinymce');return false;"><?php _e('Visual'); ?></a>
629                                 <a href="#" onclick="fullscreen.switchmode('html');return false;"><?php _e('HTML'); ?></a>
630                         </div></div>
631
632                         <div id="wp-fullscreen-button-bar"><div id="wp-fullscreen-buttons" class="wp_themeSkin">
633         <?php
634
635                 $buttons = array(
636                         // format: title, onclick, show in both editors
637                         'bold' => array( 'title' => __('Bold (Ctrl + B)'), 'onclick' => 'fullscreen.b();', 'both' => false ),
638                         'italic' => array( 'title' => __('Italic (Ctrl + I)'), 'onclick' => 'fullscreen.i();', 'both' => false ),
639                         '0' => 'separator',
640                         'bullist' => array( 'title' => __('Unordered list (Alt + Shift + U)'), 'onclick' => 'fullscreen.ul();', 'both' => false ),
641                         'numlist' => array( 'title' => __('Ordered list (Alt + Shift + O)'), 'onclick' => 'fullscreen.ol();', 'both' => false ),
642                         '1' => 'separator',
643                         'blockquote' => array( 'title' => __('Blockquote (Alt + Shift + Q)'), 'onclick' => 'fullscreen.blockquote();', 'both' => false ),
644                         'image' => array( 'title' => __('Insert/edit image (Alt + Shift + M)'), 'onclick' => "fullscreen.medialib();", 'both' => true ),
645                         '2' => 'separator',
646                         'link' => array( 'title' => __('Insert/edit link (Alt + Shift + A)'), 'onclick' => 'fullscreen.link();', 'both' => true ),
647                         'unlink' => array( 'title' => __('Unlink (Alt + Shift + S)'), 'onclick' => 'fullscreen.unlink();', 'both' => false ),
648                         '3' => 'separator',
649                         'help' => array( 'title' => __('Help (Alt + Shift + H)'), 'onclick' => 'fullscreen.help();', 'both' => false )
650                 );
651
652                 $buttons = apply_filters( 'wp_fullscreen_buttons', $buttons );
653
654                 foreach ( $buttons as $button => $args ) {
655                         if ( 'separator' == $args ) { ?>
656                                 <div><span aria-orientation="vertical" role="separator" class="mceSeparator"></span></div>
657         <?php           continue;
658                         } ?>
659
660                         <div<?php if ( $args['both'] ) { ?> class="wp-fullscreen-both"<?php } ?>>
661                         <a title="<?php echo $args['title']; ?>" onclick="<?php echo $args['onclick']; ?>return false;" class="mceButton mceButtonEnabled mce_<?php echo $button; ?>" href="#" id="wp_fs_<?php echo $button; ?>" role="button" aria-pressed="false">
662                         <span class="mceIcon mce_<?php echo $button; ?>"></span>
663                         </a>
664                         </div>
665         <?php
666                 } ?>
667
668                         </div></div>
669
670                         <div id="wp-fullscreen-save">
671                                 <span><?php if ( $post->post_status == 'publish' ) _e('Updated.'); else _e('Saved.'); ?></span>
672                                 <img src="<?php echo admin_url('images/wpspin_light.gif'); ?>" alt="" />
673                                 <input type="button" class="button-primary" value="<?php echo $save; ?>" onclick="fullscreen.save();" />
674                         </div>
675
676                         </div>
677                 </div>
678         </div>
679
680         <div id="wp-fullscreen-wrap" style="width:<?php echo $dfw_width; ?>px;">
681                 <?php if ( post_type_supports($post->post_type, 'title') ) { ?>
682                 <label id="wp-fullscreen-title-prompt-text" for="wp-fullscreen-title"><?php echo apply_filters( 'enter_title_here', __( 'Enter title here' ), $post ); ?></label>
683                 <input type="text" id="wp-fullscreen-title" value="" autocomplete="off" />
684                 <?php } ?>
685
686                 <div id="wp-fullscreen-container">
687                         <textarea id="wp_mce_fullscreen"></textarea>
688                 </div>
689
690                 <div id="wp-fullscreen-status">
691                         <div id="wp-fullscreen-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></div>
692                         <div id="wp-fullscreen-tagline"><?php _e('Just write.'); ?></div>
693                 </div>
694         </div>
695         </div>
696
697         <div class="fullscreen-overlay" id="fullscreen-overlay"></div>
698         <div class="fullscreen-overlay fullscreen-fader fade-600" id="fullscreen-fader"></div>
699         <?php
700         }
701
702         /**
703          * Performs post queries for internal linking.
704          *
705          * @since 3.1.0
706          *
707          * @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments.
708          * @return array Results.
709          */
710         public static function wp_link_query( $args = array() ) {
711                 $pts = get_post_types( array( 'public' => true ), 'objects' );
712                 $pt_names = array_keys( $pts );
713
714                 $query = array(
715                         'post_type' => $pt_names,
716                         'suppress_filters' => true,
717                         'update_post_term_cache' => false,
718                         'update_post_meta_cache' => false,
719                         'post_status' => 'publish',
720                         'order' => 'DESC',
721                         'orderby' => 'post_date',
722                         'posts_per_page' => 20,
723                 );
724
725                 $args['pagenum'] = isset( $args['pagenum'] ) ? absint( $args['pagenum'] ) : 1;
726
727                 if ( isset( $args['s'] ) )
728                         $query['s'] = $args['s'];
729
730                 $query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0;
731
732                 // Do main query.
733                 $get_posts = new WP_Query;
734                 $posts = $get_posts->query( $query );
735                 // Check if any posts were found.
736                 if ( ! $get_posts->post_count )
737                         return false;
738
739                 // Build results.
740                 $results = array();
741                 foreach ( $posts as $post ) {
742                         if ( 'post' == $post->post_type )
743                                 $info = mysql2date( __( 'Y/m/d' ), $post->post_date );
744                         else
745                                 $info = $pts[ $post->post_type ]->labels->singular_name;
746
747                         $results[] = array(
748                                 'ID' => $post->ID,
749                                 'title' => trim( esc_html( strip_tags( get_the_title( $post ) ) ) ),
750                                 'permalink' => get_permalink( $post->ID ),
751                                 'info' => $info,
752                         );
753                 }
754
755                 return $results;
756         }
757
758         /**
759          * Dialog for internal linking.
760          *
761          * @since 3.1.0
762          */
763         public static function wp_link_dialog() {
764         ?>
765         <div style="display:none;">
766         <form id="wp-link" tabindex="-1">
767         <?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
768         <div id="link-selector">
769                 <div id="link-options">
770                         <p class="howto"><?php _e( 'Enter the destination URL' ); ?></p>
771                         <div>
772                                 <label><span><?php _e( 'URL' ); ?></span><input id="url-field" type="text" tabindex="10" name="href" /></label>
773                         </div>
774                         <div>
775                                 <label><span><?php _e( 'Title' ); ?></span><input id="link-title-field" type="text" tabindex="20" name="linktitle" /></label>
776                         </div>
777                         <div class="link-target">
778                                 <label><input type="checkbox" id="link-target-checkbox" tabindex="30" /> <?php _e( 'Open link in a new window/tab' ); ?></label>
779                         </div>
780                 </div>
781                 <?php $show_internal = '1' == get_user_setting( 'wplink', '0' ); ?>
782                 <p class="howto toggle-arrow <?php if ( $show_internal ) echo 'toggle-arrow-active'; ?>" id="internal-toggle"><?php _e( 'Or link to existing content' ); ?></p>
783                 <div id="search-panel"<?php if ( ! $show_internal ) echo ' style="display:none"'; ?>>
784                         <div class="link-search-wrapper">
785                                 <label>
786                                         <span><?php _e( 'Search' ); ?></span>
787                                         <input type="search" id="search-field" class="link-search-field" tabindex="60" autocomplete="off" />
788                                         <img class="waiting" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
789                                 </label>
790                         </div>
791                         <div id="search-results" class="query-results">
792                                 <ul></ul>
793                                 <div class="river-waiting">
794                                         <img class="waiting" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
795                                 </div>
796                         </div>
797                         <div id="most-recent-results" class="query-results">
798                                 <div class="query-notice"><em><?php _e( 'No search term specified. Showing recent items.' ); ?></em></div>
799                                 <ul></ul>
800                                 <div class="river-waiting">
801                                         <img class="waiting" src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" />
802                                 </div>
803                         </div>
804                 </div>
805         </div>
806         <div class="submitbox">
807                 <div id="wp-link-cancel">
808                         <a class="submitdelete deletion" href="#"><?php _e( 'Cancel' ); ?></a>
809                 </div>
810                 <div id="wp-link-update">
811                         <input type="submit" tabindex="100" value="<?php esc_attr_e( 'Add Link' ); ?>" class="button-primary" id="wp-link-submit" name="wp-link-submit">
812                 </div>
813         </div>
814         </form>
815         </div>
816         <?php
817         }
818 }