PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/class-wp-editor.php

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