| Commit | Line | Data |
|---|---|---|
| 6f760c55 MW |
1 | <?php |
| 2 | // $Id$ | |
| 3 | // A collaborative project by Matt Westgate <drupal at asitis dot org> | |
| 4 | // and Richard Bennett <richard.b@gritechnologies.com> | |
| 5 | ||
| 6 | /** | |
| 7 | * @file | |
| 8 | * Integrate the TinyMCE editor (http://tinymce.moxiecode.com/) into Drupal. | |
| 9 | */ | |
| 10 | ||
| 11 | /** | |
| 12 | * Implementation of hook_menu(). | |
| 13 | * | |
| 14 | * Add the JavaScript file to the page head. Doing this in a menu hook is a | |
| 15 | * little less expensive that in *_init since we don't need to load the head for | |
| 16 | * Drupal-cached pages. | |
| 17 | * | |
| 18 | */ | |
| 19 | function tinymce_menu($may_cache) { | |
| 64d74024 | 20 | global $base_url; |
| 6f760c55 | 21 | if (!$may_cache) { |
| 2b031c84 MW |
22 | // For some crazy reason IE will only load this JS file if the absolute reference is given to it. |
| 23 | drupal_set_html_head('<script language="javascript" type="text/javascript" src="'. $base_url . '/'. drupal_get_path('module', 'tinymce') .'/tinymce/jscripts/tiny_mce/tiny_mce.js"></script>'); | |
| 64d74024 MW |
24 | //We may need this so TinyMCE has the right path to Drupal to invoke drupal tinymce plugins. |
| 25 | //drupal_set_html_head('<script language="javascript" type="text/javascript"> var baseUrl = "'. $base_url .'"; </script>'); | |
| 1fb961dc MW |
26 | // We have to do this becuase of some unfocused CSS in certain themes. See http://drupal.org/node/18879 for details |
| 27 | drupal_set_html_head('<style type="text/css" media="all">.mceEditor img { display: inline; }</style>'); | |
| 6f760c55 MW |
28 | } |
| 29 | } | |
| 30 | ||
| 31 | /** | |
| 32 | * Implementation of hook_help(). | |
| 33 | */ | |
| 34 | function tinymce_help($section) { | |
| 35 | switch ($section) { | |
| 36 | case 'admin/modules#description': | |
| 37 | return t('The TinyMCE Javascript HTML WYSIWYG editor.'); | |
| 38 | ||
| 39 | case 'admin/settings/tinymce#pages': | |
| 40 | return "node/*\nuser/*\ncomment/*"; | |
| 41 | } | |
| 42 | } | |
| 43 | ||
| 44 | /** | |
| 45 | * Implementation of hook_perm(). | |
| 46 | */ | |
| 47 | function tinymce_perm() { | |
| dd7d7335 | 48 | return array('access tinymce', 'choose own tinymce theme'); |
| 6f760c55 MW |
49 | } |
| 50 | ||
| 51 | /** | |
| 64d74024 MW |
52 | * Implementation of hook_img_assist_head(). |
| 53 | */ | |
| 54 | function tinymce_img_assist_head() { | |
| 55 | $popup_path = drupal_get_path('module', 'tinymce'). '/tinymce/jscripts/tiny_mce'; | |
| 56 | ||
| 57 | $output = <<<EOD | |
| 58 | <script language="javascript" src="$popup_path/tiny_mce_popup.js"></script> | |
| 59 | <script language="javascript"> | |
| 60 | function insertImage(form) { | |
| 61 | if (window.opener) { | |
| 62 | var thumb = (form['edit-thumb'].checked) ? 1 : 0; | |
| 63 | ||
| 64 | if (thumb == 1) { | |
| 65 | var src = form['edit[thumbpath]'].value; | |
| 66 | var width = form['edit[thumbWidth]'].value; | |
| 67 | var height = form['edit[thumbHeight]'].value; | |
| 68 | } | |
| 69 | else { | |
| 70 | var src = form['edit[filepath]'].value; | |
| 71 | var width = form['edit[width]'].value != '' ? form['edit[width]'].value : form['edit[origWidth]'].value; | |
| 72 | var height = form['edit[height]'].value != '' ? form['edit[height]'].value : form['edit[origHeight]'].value; | |
| 73 | } | |
| 74 | var alt = form['edit[alt]'].value; | |
| 75 | ||
| 76 | window.opener.tinyMCE.insertImage(src, alt, '', '', '', width, height); | |
| 77 | } | |
| 78 | } | |
| 79 | </script> | |
| 80 | EOD; | |
| 81 | ||
| 82 | return $output; | |
| 83 | } | |
| 84 | ||
| 85 | /** | |
| 86 | * Implementation of hook_img_assist_on_submit(). | |
| 87 | */ | |
| 88 | function tinymce_img_assist_on_submit() { | |
| 89 | return 'parent.insertImage(this.form);'; | |
| 90 | } | |
| 91 | ||
| 92 | /** | |
| 6f760c55 MW |
93 | * Implementation of hook_settings(). |
| 94 | */ | |
| 95 | function tinymce_settings() { | |
| f9856b80 | 96 | drupal_set_title(t('TinyMCE settings (%revision)', array('%revision' => '$Revision$'))); |
| ae7b55ca MW |
97 | |
| 98 | //Check if TinyMCE is installed. | |
| 99 | $tinymce_loc = drupal_get_path('module', 'tinymce') .'/tinymce/'; | |
| 100 | if (!is_dir($tinymce_loc)) { | |
| 101 | drupal_set_message(t('Could not find the TinyMCE engine installed at <strong>%tinymce-directory</strong>. Please <a href="http://tinymce.moxiecode.com/">download TinyMCE</a>, uncompress it and copy the folder into %tinymce-path.', array('%tinymce-path' => drupal_get_path('module', 'tinymce'), '%tinymce-directory' => drupal_get_path('module', 'tinymce'). '/tinymce/')), 'error'); | |
| 102 | } | |
| 103 | ||
| 6739c75d | 104 | $group = form_radios(t('Default theme'), 'tinymce_theme', variable_get('tinymce_theme', 'simple'), _tinymce_get_themes()); |
| dd7d7335 | 105 | $output = form_group(t('Themes'), $group); |
| 6f760c55 | 106 | |
| dd7d7335 | 107 | $group = form_radios(t('access tinymce'), 'tinymce_all', variable_get('tinymce_all', 1), array(t('on specific pages'), t('on all textareas'))); |
| 6f760c55 MW |
108 | if (!variable_get('tinymce_all', 1)) { |
| 109 | $group .= form_textarea(t('Pages'), 'tinymce_pages', variable_get('tinymce_pages', tinymce_help('admin/settings/tinymce#pages')), 40, 5, t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are '<em>blog</em>' for the blog page and '<em>blog/*</em>' for every personal blog. '<em><front></em>' is the front page.")); | |
| 110 | } | |
| 111 | $output .= form_group('', $group); | |
| 112 | return $output; | |
| 113 | } | |
| 114 | ||
| 64d74024 MW |
115 | /** |
| 116 | * Implementation of hook_textarea(). | |
| 117 | */ | |
| 6f760c55 | 118 | function tinymce_textarea($op, $name) { |
| dd7d7335 MW |
119 | static $is_running = FALSE; |
| 120 | if (!user_access('access tinymce')) return NULL; | |
| 6f760c55 MW |
121 | |
| 122 | global $user; | |
| 6739c75d | 123 | $theme_name = $user->tinymce_theme ? $user->tinymce_theme : variable_get('tinymce_theme', 'simple'); |
| e4a1c221 | 124 | $user_status = $user->tinymce_status != NULL ? $user->tinymce_status : TRUE; |
| 6f760c55 | 125 | |
| e4a1c221 | 126 | if ($op == 'pre' && _tinymce_page_match() && $user_status) { |
| 6f760c55 MW |
127 | global $base_url; |
| 128 | ||
| 6739c75d MW |
129 | // Build a default list of TinyMCE settings. |
| 130 | $init['mode'] = 'textareas'; | |
| 131 | $init['theme'] = $theme_name; | |
| 132 | $init['document_base_url'] = "$base_url/"; | |
| 133 | ||
| 134 | // Merge and overrivide user-defined TinyMCE settings. | |
| dd7d7335 | 135 | $init = array_merge($init, (array) theme('tinymce_theme', $init, $textarea_name, $theme_name, $is_running)); |
| 6739c75d MW |
136 | foreach ($init as $k => $v) { |
| 137 | $settings[] = $k. ' : "'. $v. '"'; | |
| 138 | } | |
| 2b031c84 | 139 | $tinymce_settings = implode(",\n ", $settings); |
| 6739c75d | 140 | |
| 6f760c55 MW |
141 | $output = <<<EOD |
| 142 | <script language="javascript" type="text/javascript"> | |
| 143 | tinyMCE.init({ | |
| 6739c75d | 144 | $tinymce_settings |
| 6f760c55 MW |
145 | }); |
| 146 | </script> | |
| 147 | EOD; | |
| 148 | ||
| dd7d7335 MW |
149 | // We only invoke TinyMCE once per request, not once per textarea. We could |
| 150 | // do this check earlier in the conditional, but it's probably wise to let | |
| 151 | // the themed functions know what's going on. | |
| 152 | if (!$is_running) { | |
| 153 | $is_running = TRUE; | |
| 2b031c84 | 154 | drupal_set_html_head($output); |
| dd7d7335 | 155 | } |
| 6f760c55 MW |
156 | } |
| 157 | } | |
| 158 | ||
| 159 | /** | |
| 160 | * Implementation of hook_user(). | |
| 161 | */ | |
| 162 | function tinymce_user($type, &$edit, &$user, $category = NULL) { | |
| dd7d7335 | 163 | if ($type == 'form' && $category == 'account' && user_access('access tinymce')) { |
| 6739c75d | 164 | $user_status = $edit['tinymce_status'] != NULL ? $edit['tinymce_status'] : ($user->tinymce_status != NULL ? $user->tinymce_status : 1); |
| dd7d7335 MW |
165 | $form = form_radios(t('Status'), 'tinymce_status', $user_status, array(t('Disabled'), t('Enabled')), t('Would you like to enable rich-text editing of your content?')); |
| 166 | if ($user_status && user_access('choose own tinymce theme')) { | |
| 6739c75d | 167 | $form .= form_radios(t('Default theme'), 'tinymce_theme', $edit['tinymce_theme'] ? $edit['tinymce_theme'] : variable_get('tinymce_theme', 'simple'), _tinymce_get_themes()); |
| 6f760c55 | 168 | } |
| 6f760c55 MW |
169 | return array(array('title' => t('TinyMCE settings'), 'data' => $form)); |
| 170 | } | |
| 171 | if ($type == 'validate') { | |
| 6f760c55 MW |
172 | return array('tinymce_theme' => $edit['tinymce_theme'], 'tinymce_status' => $edit['tinymce_status']); |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | /** | |
| 6739c75d MW |
177 | * @addtogroup themeable |
| 178 | * @{ | |
| 179 | */ | |
| 180 | ||
| 181 | /** | |
| ae7b55ca | 182 | * Customize a TinyMCE theme. |
| 6739c75d MW |
183 | * |
| 184 | * @param init | |
| ae7b55ca MW |
185 | * An array of settings TinyMCE should invoke a theme. You may override any |
| 186 | * of the TinyMCE settings. Details here: | |
| 6739c75d MW |
187 | * |
| 188 | * http://tinymce.moxiecode.com/wrapper.php?url=tinymce/docs/using.htm | |
| ae7b55ca MW |
189 | * |
| 190 | * @param textarea_name | |
| 191 | * The name of the textarea TinyMCE wants to enable. | |
| 192 | * | |
| 193 | * @param theme_name | |
| 194 | * The default theme name to be enabled for this textarea. The sitewide | |
| 195 | * default is 'simple', but the user may also override this. | |
| dd7d7335 MW |
196 | * |
| 197 | * @param is_running | |
| 198 | * A boolean flag that identifies id TinyMCE is currently running for this | |
| 199 | * request life cycle. If it's already running then anything returned by this | |
| 200 | * will be ignored. This is necessary since TinyMCE works by being invoked | |
| 201 | * once per request and not once per textarea. | |
| 6739c75d | 202 | */ |
| dd7d7335 | 203 | function theme_tinymce_theme($init, $textarea_name, $theme_name, $is_running) { |
| ae7b55ca MW |
204 | switch ($theme_name) { |
| 205 | case 'advanced': | |
| 206 | $init['extended_valid_elements'] = 'a[href|target|name]'; | |
| ae7b55ca | 207 | $init['theme_advanced_buttons3_add_before'] = 'tablecontrols,separator'; |
| aeb7ca13 | 208 | $init['plugins'] = module_exist('img_assist') ? 'drupalimage,table,emotions,print' : 'table,emotions,print'; |
| f9856b80 | 209 | $init['theme_advanced_buttons3_add'] = 'emotions,separator,print'; |
| ae7b55ca MW |
210 | return $init; |
| 211 | } | |
| 6739c75d MW |
212 | } |
| 213 | ||
| 214 | /** @} End of addtogroup themeable */ | |
| 215 | ||
| 216 | /** | |
| 6f760c55 MW |
217 | * Grab the themes available to TinyMCE. |
| 218 | * | |
| 219 | * TinyMCE themes control the functionality and buttons that are available to a | |
| 220 | * user. Themes are only looked for within the default TinyMCE theme directory. | |
| 221 | * | |
| 222 | * @return | |
| 223 | * An array of theme names. | |
| 224 | */ | |
| 225 | function _tinymce_get_themes() { | |
| 226 | static $themes = array(); | |
| 227 | ||
| 228 | if (!$themes) { | |
| 229 | $theme_loc = drupal_get_path('module', 'tinymce') .'/tinymce/jscripts/tiny_mce/themes/'; | |
| 230 | if (is_dir($theme_loc) && $dh = opendir($theme_loc)) { | |
| 231 | while (($file = readdir($dh)) !== false) { | |
| ae24db96 | 232 | if (!in_array($file, array('.', '..', 'CVS')) && is_dir($theme_loc . $file)) { |
| 6f760c55 MW |
233 | $themes[$file] = $file; |
| 234 | } | |
| 235 | } | |
| 236 | closedir($dh); | |
| 237 | asort($themes); | |
| 238 | } | |
| 239 | } | |
| 240 | ||
| 241 | return $themes; | |
| 242 | } | |
| 243 | ||
| 244 | /** | |
| 245 | * Determine if TinyMCE can render the current page. | |
| 246 | * | |
| 247 | * @return | |
| 248 | * TRUE if can render, FALSE if not allowed. | |
| 249 | */ | |
| 250 | function _tinymce_page_match() { | |
| 251 | $edit = $_POST['edit']; | |
| 252 | ||
| 253 | //Kill TinyMCE if we're editing a textarea with PHP in it! | |
| 254 | if ($edit) { | |
| 255 | if ($edit['format'] == 2) { | |
| 256 | return FALSE; | |
| 257 | } | |
| 258 | } | |
| 259 | else { | |
| 260 | // PHP input formats are #2 in the filters table. | |
| 261 | preg_match("|^node/(\d+)(/edit)$|", $_GET['q'], $match); | |
| 262 | if (intval($match[1]) > 0) { | |
| 263 | if (db_result(db_query('SELECT format FROM {node} WHERE nid = %d AND format = 2', $match[1]))) { | |
| 264 | return FALSE; | |
| 265 | } | |
| 266 | } | |
| 267 | } | |
| 268 | ||
| 269 | if (variable_get('tinymce_all', 1)) { | |
| 270 | return TRUE; | |
| 271 | } | |
| 272 | else { | |
| 273 | $page_match = FALSE; | |
| 274 | $pages = variable_get('tinymce_pages', tinymce_help('admin/settings/tinymce#pages')); | |
| 275 | if ($pages) { | |
| 276 | $path = drupal_get_path_alias($_GET['q']); | |
| 277 | $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. variable_get('site_frontpage', 'node') .'\2'), preg_quote($pages, '/')) .')$/'; | |
| 278 | $page_match = preg_match($regexp, $path); | |
| 279 | } | |
| 280 | return $page_match; | |
| 281 | } | |
| 282 | } | |
| ae24db96 | 283 | ?> |