* Print CVS Revision tag on settings page. Patch by richardb.
[project/tinymce.git] / tinymce.module
CommitLineData
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 */
19function 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 */
34function 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 */
47function 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 */
54function 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>
80EOD;
81
82 return $output;
83}
84
85/**
86 * Implementation of hook_img_assist_on_submit().
87 */
88function tinymce_img_assist_on_submit() {
89 return 'parent.insertImage(this.form);';
90}
91
92/**
6f760c55
MW
93 * Implementation of hook_settings().
94 */
95function 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>&lt;front&gt;</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 118function 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>
147EOD;
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 */
162function 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 203function 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 */
225function _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 */
250function _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?>