* Added a user_access permission to choose which roles can select their own TinyMCE...
[project/tinymce.git] / tinymce.module
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) {
20 if (!$may_cache) {
21 drupal_set_html_head('<script language="javascript" type="text/javascript" src="'. drupal_get_path('module', 'tinymce') .'/tinymce/jscripts/tiny_mce/tiny_mce.js"></script>');
22 }
23 }
24
25 /**
26 * Implementation of hook_help().
27 */
28 function tinymce_help($section) {
29 switch ($section) {
30 case 'admin/modules#description':
31 return t('The TinyMCE Javascript HTML WYSIWYG editor.');
32
33 case 'admin/settings/tinymce#pages':
34 return "node/*\nuser/*\ncomment/*";
35 }
36 }
37
38 /**
39 * Implementation of hook_perm().
40 */
41 function tinymce_perm() {
42 return array('access tinymce', 'choose own tinymce theme');
43 }
44
45 /**
46 * Implementation of hook_settings().
47 */
48 function tinymce_settings() {
49 drupal_set_title(t('TinyMCE settings'));
50
51 //Check if TinyMCE is installed.
52 $tinymce_loc = drupal_get_path('module', 'tinymce') .'/tinymce/';
53 if (!is_dir($tinymce_loc)) {
54 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');
55 }
56
57 $group = form_radios(t('Default theme'), 'tinymce_theme', variable_get('tinymce_theme', 'simple'), _tinymce_get_themes());
58 $output = form_group(t('Themes'), $group);
59
60 $group = form_radios(t('access tinymce'), 'tinymce_all', variable_get('tinymce_all', 1), array(t('on specific pages'), t('on all textareas')));
61 if (!variable_get('tinymce_all', 1)) {
62 $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."));
63 }
64 $output .= form_group('', $group);
65 return $output;
66 }
67
68 function tinymce_textarea($op, $name) {
69 static $is_running = FALSE;
70 if (!user_access('access tinymce')) return NULL;
71
72 global $user;
73 $theme_name = $user->tinymce_theme ? $user->tinymce_theme : variable_get('tinymce_theme', 'simple');
74 $user_status = $user->tinymce_status != NULL ? $user->tinymce_status : TRUE;
75
76 if ($op == 'pre' && _tinymce_page_match() && $user_status) {
77 global $base_url;
78
79 // Build a default list of TinyMCE settings.
80 $init['mode'] = 'textareas';
81 $init['theme'] = $theme_name;
82 $init['document_base_url'] = "$base_url/";
83
84 // Merge and overrivide user-defined TinyMCE settings.
85 $init = array_merge($init, (array) theme('tinymce_theme', $init, $textarea_name, $theme_name, $is_running));
86 foreach ($init as $k => $v) {
87 $settings[] = $k. ' : "'. $v. '"';
88 }
89 $tinymce_settings = implode(",\n", $settings);
90
91 $output = <<<EOD
92 <script language="javascript" type="text/javascript">
93 tinyMCE.init({
94 $tinymce_settings
95 });
96 </script>
97 EOD;
98
99 // We only invoke TinyMCE once per request, not once per textarea. We could
100 // do this check earlier in the conditional, but it's probably wise to let
101 // the themed functions know what's going on.
102 if (!$is_running) {
103 $is_running = TRUE;
104 return $output;
105 }
106 }
107 }
108
109 /**
110 * Implementation of hook_user().
111 */
112 function tinymce_user($type, &$edit, &$user, $category = NULL) {
113 if ($type == 'form' && $category == 'account' && user_access('access tinymce')) {
114 $user_status = $edit['tinymce_status'] != NULL ? $edit['tinymce_status'] : ($user->tinymce_status != NULL ? $user->tinymce_status : 1);
115 $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?'));
116 if ($user_status && user_access('choose own tinymce theme')) {
117 $form .= form_radios(t('Default theme'), 'tinymce_theme', $edit['tinymce_theme'] ? $edit['tinymce_theme'] : variable_get('tinymce_theme', 'simple'), _tinymce_get_themes());
118 }
119 else {
120 $form .= form_hidden('tinymce_theme', $edit['tinymce_theme'] ? $edit['tinymce_theme'] : variable_get('tinymce_theme', 'simple'));
121 }
122 return array(array('title' => t('TinyMCE settings'), 'data' => $form));
123 }
124 if ($type == 'validate') {
125 return array('tinymce_theme' => $edit['tinymce_theme'], 'tinymce_status' => $edit['tinymce_status']);
126 }
127 }
128
129 /**
130 * @addtogroup themeable
131 * @{
132 */
133
134 /**
135 * Customize a TinyMCE theme.
136 *
137 * @param init
138 * An array of settings TinyMCE should invoke a theme. You may override any
139 * of the TinyMCE settings. Details here:
140 *
141 * http://tinymce.moxiecode.com/wrapper.php?url=tinymce/docs/using.htm
142 *
143 * @param textarea_name
144 * The name of the textarea TinyMCE wants to enable.
145 *
146 * @param theme_name
147 * The default theme name to be enabled for this textarea. The sitewide
148 * default is 'simple', but the user may also override this.
149 *
150 * @param is_running
151 * A boolean flag that identifies id TinyMCE is currently running for this
152 * request life cycle. If it's already running then anything returned by this
153 * will be ignored. This is necessary since TinyMCE works by being invoked
154 * once per request and not once per textarea.
155 */
156 function theme_tinymce_theme($init, $textarea_name, $theme_name, $is_running) {
157 switch ($theme_name) {
158 case 'advanced':
159 $init['extended_valid_elements'] = 'a[href|target|name]';
160 $init['plugins'] = 'table';
161 $init['theme_advanced_buttons3_add_before'] = 'tablecontrols,separator';
162 $init['plugins'] = 'table,emotions,iespell, print';
163 $init['theme_advanced_buttons3_add'] = 'emotions,iespell,separator,print';
164 return $init;
165 }
166 }
167
168 /** @} End of addtogroup themeable */
169
170 /**
171 * Grab the themes available to TinyMCE.
172 *
173 * TinyMCE themes control the functionality and buttons that are available to a
174 * user. Themes are only looked for within the default TinyMCE theme directory.
175 *
176 * @return
177 * An array of theme names.
178 */
179 function _tinymce_get_themes() {
180 static $themes = array();
181
182 if (!$themes) {
183 $theme_loc = drupal_get_path('module', 'tinymce') .'/tinymce/jscripts/tiny_mce/themes/';
184 if (is_dir($theme_loc) && $dh = opendir($theme_loc)) {
185 while (($file = readdir($dh)) !== false) {
186 if ($file != '.' && $file != '..' && is_dir($theme_loc . $file)) {
187 $themes[$file] = $file;
188 }
189 }
190 closedir($dh);
191 asort($themes);
192 }
193 }
194
195 return $themes;
196 }
197
198 /**
199 * Determine if TinyMCE can render the current page.
200 *
201 * @return
202 * TRUE if can render, FALSE if not allowed.
203 */
204 function _tinymce_page_match() {
205 $edit = $_POST['edit'];
206
207 //Kill TinyMCE if we're editing a textarea with PHP in it!
208 if ($edit) {
209 if ($edit['format'] == 2) {
210 return FALSE;
211 }
212 }
213 else {
214 // PHP input formats are #2 in the filters table.
215 preg_match("|^node/(\d+)(/edit)$|", $_GET['q'], $match);
216 if (intval($match[1]) > 0) {
217 if (db_result(db_query('SELECT format FROM {node} WHERE nid = %d AND format = 2', $match[1]))) {
218 return FALSE;
219 }
220 }
221 }
222
223 if (variable_get('tinymce_all', 1)) {
224 return TRUE;
225 }
226 else {
227 $page_match = FALSE;
228 $pages = variable_get('tinymce_pages', tinymce_help('admin/settings/tinymce#pages'));
229 if ($pages) {
230 $path = drupal_get_path_alias($_GET['q']);
231 $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. variable_get('site_frontpage', 'node') .'\2'), preg_quote($pages, '/')) .')$/';
232 $page_match = preg_match($regexp, $path);
233 }
234 return $page_match;
235 }
236 }
237 ?>