* Update to make module compatible with TinyMCE 1.44RC2. You must install the latest...
[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 function tinymce_menu($may_cache) {
15 $items = array();
16 if ($may_cache) {
17 $items[] = array('path' => 'admin/settings/tinymce', 'title' => t('tinymce'),
18 'callback' => 'tinymce_admin',
19 'access' => user_access('administer tinymce'));
20 }
21 return $items;
22 }
23
24 /**
25 * Implementation of hook_help().
26 */
27 function tinymce_help($section) {
28 switch ($section) {
29 case 'admin/modules#description':
30 return t('The TinyMCE Javascript HTML WYSIWYG editor.');
31
32 case 'admin/settings/tinymce#pages':
33 return "node/*\nuser/*\ncomment/*";
34 }
35 }
36
37 /**
38 * Implementation of hook_perm().
39 */
40 function tinymce_perm() {
41 return array('administer tinymce', 'access tinymce');
42 }
43
44 /**
45 * Implementation of hook_img_assist_head().
46 */
47 function tinymce_img_assist_head() {
48 global $base_url;
49 // The tinymce docs say to include tiny_mce_popup.js, but this was killing IE!
50 $popup_path = $base_url .'/'. drupal_get_path('module', 'tinymce'). '/tinymce/jscripts/tiny_mce/tiny_mce_popup.js';
51 $img_assist_prop = $base_url .'/'. drupal_get_path('module', 'img_assist'). '/properties.js';
52 $clean_url = variable_get('clean_url', 0);
53 $img_template = variable_get('img_assist_img_html', img_assist_help('img_assist/template'));
54 $img_template = str_replace("\r\n", "\n", $img_template);
55 $img_template = str_replace("\n", '\n', addslashes($img_template));
56
57 $output = <<<EOD
58 <script language="javascript" src="$img_assist_prop"></script>
59 <script language="javascript">
60 var clean_url = $clean_url;
61 var img_template = "$img_template";
62
63 function insertImage(form) {
64 if (window.opener) {
65 form['edit[thumbpath]'].value = window.opener.tinyMCE.convertURL(form['edit[thumbpath]'].value);
66 form['edit[filepath]'].value = window.opener.tinyMCE.convertURL(form['edit[filepath]'].value);
67 form['edit[nodePath]'].value = window.opener.tinyMCE.convertURL(form['edit[nodePath]'].value);
68
69 var img = generate_image_tag(form, 'html');
70
71 // Find the tinymce instance we're dealin' with.
72 var inst = window.opener.tinyMCE.getInstanceById(myTextarea.name);
73 inst.execCommand('mceInsertContent', false, img);
74 }
75 }
76 </script>
77 EOD;
78
79 return $output;
80 }
81
82 /**
83 * Implementation of hook_img_assist_on_submit().
84 */
85 function tinymce_img_assist_on_submit() {
86 return 'parent.insertImage(this.form);';
87 }
88
89 /**
90 * Implementation of hook_textarea().
91 */
92 function tinymce_textarea($op, $textarea_name) {
93 static $is_running = FALSE;
94 if (!user_access('access tinymce')) return NULL;
95
96 global $user;
97 global $base_url;
98 static $profile_name;
99
100 // Since tinymce_config() makes a db hit, only call it when we're pretty sure
101 // we're gonna render tinymce.
102 $valid_so_far = FALSE;
103 if ($op == 'post') {
104 if (!$profile_name) {
105 $profile_name = db_result(db_query('SELECT s.name FROM {tinymce_settings} s INNER JOIN {tinymce_role} r ON r.name = s.name WHERE r.rid IN (%s)', implode(',', array_keys($user->roles))));
106 }
107 $profile = tinymce_profile_load($profile_name);
108 $init = tinymce_config($profile);
109 $init['elements'] = 'edit['. $textarea_name .']';
110 $valid_so_far = TRUE;
111 }
112
113 if ($valid_so_far && _tinymce_page_match($profile)) {
114 // Merge and overrivide user-defined TinyMCE settings.
115 $init = array_merge($init, (array) theme('tinymce_theme', $init, $textarea_name, $init['theme'], $is_running));
116 foreach ($init as $k => $v) {
117 if (strtolower($v) != 'true' && strtolower($v) != 'false') {
118 $v = '"'. $v. '"';
119 }
120 $settings[] = $k. ' : '. $v;
121 }
122 $tinymce_settings = implode(",\n ", $settings);
123
124 if (function_exists('img_assist_help')) {
125 $img_assist_js_on = $base_url .'/'. url('img_assist/add&editor=tinymce') .'&textarea=';
126 $img_assist_js_off = $base_url .'/'. url('img_assist/add') .'&textarea=';
127 $img_assist_on = $base_url .'/'. url('img_assist/add&editor=tinymce') .'&textarea=edit['. $textarea_name .']';
128 $img_assist_off = $base_url .'/'. url('img_assist/add') .'&textarea=edit['. $textarea_name .']';
129 }
130
131 $enable = t('enable rich-text');
132 $disable = t('disable rich-text');
133
134 $tinymce_invoke = <<<EOD
135 <script language="javascript" type="text/javascript">
136 tinyMCE.init({
137 $tinymce_settings
138 });
139 </script>
140 EOD;
141
142 $js_toggle = <<<EOD
143 <script language="javascript" type="text/javascript">
144 function mceToggle(id, linkid) {
145 element = document.getElementById(id);
146 link = document.getElementById(linkid);
147 img_assist = document.getElementById('img_assist-link-'+ id);
148
149 if (tinyMCE.getEditorId(element.name) == null) {
150 tinyMCE.addMCEControl(element, element.name);
151 element.togg = 'on';
152 link.innerHTML = '$disable';
153 link.href = "javascript:mceToggle('" +id+ "', '" +linkid+ "');";
154 if (img_assist)
155 img_assist.href = "$img_assist_js_on"+ element.name;
156 link.blur();
157 }
158 else {
159 tinyMCE.removeMCEControl(tinyMCE.getEditorId(element.name));
160 element.togg = 'off';
161 link.innerHTML = '$enable';
162 link.href = "javascript:mceToggle('" +id+ "', '" +linkid+ "');";
163 if (img_assist)
164 img_assist.href = "$img_assist_js_off"+ element.name;
165 link.blur();
166 }
167 }
168 </script>
169 EOD;
170
171 $status = isset($user->tinymce_status) ? $user->tinymce_status : variable_get('tinymce_default_state', 0);
172 $link_text = $status == 1 ? $disable : $enable;
173 $no_wysiwyg = t('Your current web browser does not support WYSIWYG editing.');
174 $wysiwyg_link = <<<EOD
175 <script language="javascript" type="text/javascript">
176 img_assist = document.getElementById('img_assist-link-edit-$textarea_name');
177 if (img_assist) {
178 img_assist.href = tinyMCE.getEditorId('edit-$textarea_name') == null ? "$img_assist_on" : "$img_assist_off";
179 }
180 if (typeof(document.execCommand) == 'undefined') {
181 img_assist.href = "$img_assist_off";
182 document.write('<div style="font-size:x-small">$no_wysiwyg</div>');
183 }
184 else {
185 document.write("<div><a href=\"javascript:mceToggle('edit-$textarea_name', 'wysiwyg4$textarea_name');\" id=\"wysiwyg4$textarea_name\">$link_text</div></a>");
186 }
187 </script>
188 EOD;
189
190 // We only load the TinyMCE js file once per request
191 if (!$is_running) {
192 $is_running = TRUE;
193 // For some crazy reason IE will only load this JS file if the absolute reference is given to it.
194 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>');
195 drupal_set_html_head($js_toggle);
196 // We have to do this becuase of some unfocused CSS in certain themes. See http://drupal.org/node/18879 for details
197 drupal_set_html_head('<style type="text/css" media="all">.mceEditor img { display: inline; }</style>');
198 }
199 // Load a TinyMCE init for each textarea.
200 drupal_set_html_head($tinymce_invoke);
201
202 return $wysiwyg_link;
203 }
204 }
205
206 /**
207 * Implementation of hook_user().
208 */
209 function tinymce_user($type, &$edit, &$user, $category = NULL) {
210 if ($type == 'form' && $category == 'account' && user_access('access tinymce')) {
211 $user_status = $edit['tinymce_status'] != NULL ? $edit['tinymce_status'] : ($user->tinymce_status != NULL ? $user->tinymce_status : variable_get('tinymce_default_state', 0));
212 $form = form_radios(t('Default status'), 'tinymce_status', $user_status, array(t('Off'), t('On')), t('Should rich-text editing be enabled or disabled by default in textarea fields?'));
213 return array(array('title' => t('TinyMCE settings'), 'data' => $form));
214 }
215 if ($type == 'validate') {
216 return array('tinymce_status' => $edit['tinymce_status']);
217 }
218 }
219
220
221 /**
222 * @addtogroup themeable
223 * @{
224 */
225
226 /**
227 * Customize a TinyMCE theme.
228 *
229 * @param init
230 * An array of settings TinyMCE should invoke a theme. You may override any
231 * of the TinyMCE settings. Details here:
232 *
233 * http://tinymce.moxiecode.com/wrapper.php?url=tinymce/docs/using.htm
234 *
235 * @param textarea_name
236 * The name of the textarea TinyMCE wants to enable.
237 *
238 * @param theme_name
239 * The default theme name to be enabled for this textarea. The sitewide
240 * default is 'simple', but the user may also override this.
241 *
242 * @param is_running
243 * A boolean flag that identifies id TinyMCE is currently running for this
244 * request life cycle. If it's already running then anything returned by this
245 * will be ignored. This is necessary since TinyMCE works by being invoked
246 * once per request and not once per textarea.
247 */
248 function theme_tinymce_theme($init, $textarea_name, $theme_name, $is_running) {
249 // Force the 'simple' theme for some of the smaller textareas.
250 switch ($textarea_name) {
251 case 'log':
252 case 'signature':
253 case 'site_mission':
254 case 'site_footer':
255 case 'settings][access_pages':
256 $init['theme'] = 'simple';
257 unset($init['theme_advanced_toolbar_location']);
258 unset($init['theme_advanced_toolbar_align']);
259 unset($init['theme_advanced_path_location']);
260 unset($init['theme_advanced_blockformats']);
261 unset($init['theme_advanced_styles']);
262 return $init;
263 }
264
265 switch ($theme_name) {
266 case 'advanced':
267 $init['extended_valid_elements'] = 'a[href|target|name|title|onclick]';
268 $init['theme_advanced_buttons3_add_before'] = 'tablecontrols,separator';
269 $init['plugins'] = file_exists(drupal_get_path('module', 'tinymce'). '/tinymce/jscripts/tiny_mce/plugins/drupalimage') ? 'drupalimage,table,emotions,print' : 'table,emotions,print';
270 $init['theme_advanced_buttons3_add'] = 'drupalimage,emotions,separator,print';
271 return $init;
272 }
273 }
274
275 /** @} End of addtogroup themeable */
276
277 /**
278 * Grab the themes available to TinyMCE.
279 *
280 * TinyMCE themes control the functionality and buttons that are available to a
281 * user. Themes are only looked for within the default TinyMCE theme directory.
282 *
283 * @return
284 * An array of theme names.
285 */
286 function _tinymce_get_themes() {
287 static $themes = array();
288
289 if (!$themes) {
290 $theme_loc = drupal_get_path('module', 'tinymce') .'/tinymce/jscripts/tiny_mce/themes/';
291 if (is_dir($theme_loc) && $dh = opendir($theme_loc)) {
292 while (($file = readdir($dh)) !== false) {
293 if (!in_array($file, array('.', '..', 'CVS')) && is_dir($theme_loc . $file)) {
294 $themes[$file] = $file;
295 }
296 }
297 closedir($dh);
298 asort($themes);
299 }
300 }
301
302 return $themes;
303 }
304
305 /********************************************************************
306 * Module Functions :: Public
307 ********************************************************************/
308
309 /**
310 * Controller for tinymce administrative settings.
311 */
312 function tinymce_admin($arg = NULL) {
313 $edit = $_POST['edit'];
314 $op = $_POST['op'];
315
316 $op = $arg && !$op ? $arg : $op;
317
318 switch ($op) {
319 case 'add':
320 $breadcrumb[] = array('path' => 'admin', 'title' => t('administer'));
321 $breadcrumb[] = array('path' => 'admin/settings/tinymce', 'title' => t('tinymce'));
322 $breadcrumb[] = array('path' => 'admin/settings/tinymce/add', 'title' => t('Add new tinymce profile'));
323 menu_set_location($breadcrumb);
324 $output = tinymce_profile_form($edit);
325 break;
326
327 case 'edit':
328 drupal_set_title(t('Edit tinymce profile'));
329 $output = tinymce_profile_form(tinymce_profile_load(urldecode(arg(4))));
330 break;
331
332 case 'delete':
333 tinymce_profile_delete(urldecode(arg(4)));
334 drupal_set_message(t('Deleted profile'));
335 drupal_goto('admin/settings/tinymce');
336 break;
337
338 case t('Create profile');
339 case t('Update profile');
340 if (tinymce_profile_validate($edit)) {
341 tinymce_profile_save($edit);
342 $edit['old_name'] ? drupal_set_message(t('Your tinymce profile has been updated.')) : drupal_set_message(t('Your tinymce profile has been created.'));
343 drupal_goto('admin/settings/tinymce');
344 }
345 else {
346 $output = tinymce_profile_form($edit);
347 }
348 break;
349
350 case t('Save settings'):
351 variable_set('tinymce_default_state', $edit['tinymce_default_state']);
352 drupal_set_message(t('Settings updated'));
353 drupal_goto('admin/settings/tinymce');
354 break;
355
356 default:
357 drupal_set_title(t('TinyMCE settings (%revision)', array('%revision' => '$Revision$')));
358 //Check if TinyMCE is installed.
359 $tinymce_loc = drupal_get_path('module', 'tinymce') .'/tinymce/';
360 if (!is_dir($tinymce_loc)) {
361 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' => $tinymce_loc)), 'error');
362 }
363 $output = tinymce_profile_overview();
364 }
365
366 print theme('page', $output);
367 }
368
369 /**
370 * Return an array of initial tinymce config options from the current role.
371 */
372 function tinymce_config($profile) {
373 global $base_url;
374 global $user;
375
376 $settings = $profile->settings;
377
378 // Build a default list of TinyMCE settings.
379
380 // Is tinymce on by default?
381 $init['mode'] = variable_get('tinymce_default_state', 0) == 1 ? 'exact' : 'none';
382 $status = isset($user->tinymce_status) ? $user->tinymce_status : variable_get('tinymce_default_state', 0);
383 $init['mode'] = $status == 1 ? 'exact' : 'none';
384 $init['theme'] = $settings['theme'] ? $settings['theme'] : 'simple';
385 $init['document_base_url'] = "$base_url/";
386
387 $init['verify_html'] = $settings['verify_html'] ? $settings['verify_html'] : 'false';
388 $init['auto_cleanup_word'] = $settings['msword'] ? $settings['msword'] : 'false';
389 $init['preformatted'] = $settings['preformatted'] ? $settings['preformatted'] : 'false';
390 $init['force_br_newlines'] = $settings['force_br'] ? $settings['force_br'] : 'false';
391 $init['force_p_newlines'] = $settings['force_p'] ? $settings['force_p'] : 'false';
392 if ($init['theme'] == 'advanced') {
393 $init['theme_advanced_toolbar_location'] = $settings['toolbar_loc'] ? $settings['toolbar_loc'] : 'bottom';
394 $init['theme_advanced_toolbar_align'] = $settings['toolbar_align'] ? $settings['toolbar_align'] : 'left';
395 $init['theme_advanced_path_location'] = $settings['path_loc'] ? $settings['path_loc'] : 'none';
396 $init['theme_advanced_blockformats'] = $settings['block_formats'] ? $settings['block_formats'] : 'p,address,pre,h1,h2,h3,h4,h5,h6';
397 }
398
399 if ($edit['css_classes']) $init['theme_advanced_styles'] = $settings['css_classes'];
400 if ($settings['width']) $init['width'] = $settings['width'];
401 if ($settings['height']) $init['height'] = $settings['height'];
402
403 if ($settings['css_setting'] == 'theme') {
404 $css = drupal_get_path('theme', init_theme()) . '/style.css';
405 if (file_exists($css)) {
406 $init['content_css'] = $base_url .'/'. $css;
407 }
408 else if ($settings['css_setting'] == 'self') {
409 $init['content_css'] = $edit['css_path'];
410 }
411 }
412
413 return $init;
414 }
415
416 /**
417 * Remove a profile from the database.
418 */
419 function tinymce_profile_delete($name) {
420 db_query("DELETE FROM {tinymce_settings} WHERE name = '%s'", $name);
421 db_query("DELETE FROM {tinymce_role} WHERE name = '%s'", $name);
422 }
423
424 /**
425 * Return an HTML form for profile configuration.
426 */
427 function tinymce_profile_form($edit) {
428 $edit = array2object($edit);
429
430 // Only display the roles that currently don't have a tinymce profile. One
431 // profile per role.
432 $orig_roles = user_roles();
433 $roles = $orig_roles;
434 if (arg(3) == 'add') {
435 $result = db_query('SELECT DISTINCT(rid) FROM {tinymce_role}');
436 while ($data = db_fetch_object($result)) {
437 unset($roles[$data->rid]);
438 }
439 if (!$roles) {
440 drupal_set_message(t('You will not be allowed to create a new profile since all user roles have already been assigned profiles. First remove an existing tinymce profile from at least one role in order to create a new profile.'), 'error');
441 }
442 else if (count($orig_roles) != count($roles)) {
443 drupal_set_message(t('Not all user roles are shown since they already have tinymce profiles. You must first unassign profiles in order to add them to a new one.'));
444 }
445 $btn = t('Create profile');
446 }
447 else {
448 $output = form_hidden('old_name', $edit->name);
449 $btn = t('Update profile');
450 }
451
452 $group = form_textfield(t('Profile name'), 'name', $edit->name, 40, 128, t('Enter an unique name for this profile. This name is only visible in the tinymce administration page.'), NULL, TRUE);
453 $group .= form_checkboxes(t('Roles allowed to use this profile'), 'rids', array_keys((array) $edit->rids), $roles, t('Select at least one role.'), NULL, TRUE);
454 $group .= form_radios(t('Theme'), 'settings][theme', $edit->settings['theme'] ? $edit->settings['theme'] : 'simple', _tinymce_get_themes(), t('Select the tinymce theme.'));
455 $group .= form_radios(t('Make tinymce visible on'), 'settings][access', $edit->settings['access'], array(t('specific pages'), t('all textareas')));
456 $group .= form_textarea(t('Specific pages'), 'settings][access_pages', $edit->settings['access_pages'] ? $edit->settings['access_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."));
457 $output .= form_group(t('Basic setup'), $group);
458
459 $output .= t('<h3>Advanced options</h3>');
460
461 $group = form_textfield(t('Editor width'), 'settings][width', $edit->settings['width'], 3, 5, t('Set width of editor. Leave blank to use size of textarea being replaced.'));
462 $group .= form_textfield(t('Editor height'), 'settings][height', $edit->settings['height'], 3, 5, t('Set height of editor. Leave blank to use size of textarea being replaced.'));
463 $group .= form_select(t('Toolbar location'), 'settings][toolbar_loc', $edit->settings['toolbar_loc'], array('bottom' => 'bottom', 'top' => 'top'), t('Show toolbar at the top or bottom of the editor area?'));
464 $group .= form_select(t('Toolbar alignment'), 'settings][toolbar_align', $edit->settings['toolbar_align'], array('center' => 'center', 'left' => 'left', 'right' => 'right'), t('Align tool icons left, center, or right within the toolbar.'));
465 $group .= form_select(t('Path location'), 'settings][path_loc', $edit->settings['path_loc'], array('none' => 'none', 'top' => 'top', 'bottom' => 'bottom'), t('Path to html elements (i.e. "body>table>tr>td"). Show at top, bottom, or not at all.'));
466 $output .= form_group(t('Editor display'), $group);
467
468 $group = form_select(t('Auto cleanup Word'), 'settings][msword', $edit->settings['msword'], array('true' => 'true', 'false' => 'false'), t('Automatically cleanup MS Office/Word HTML will be executed automatically on paste operations. (Only works in Internet Explorer)'));
469 $group .= form_select(t('Verify HTML'), 'settings][verify_html', $edit->settings['verify_html'], array('true' => 'true', 'false' => 'false'), t('Should the HTML contents be verified or not? Verifying will strip &lt;head&gt tags, so choose false if you will be editing full page HTML.'));
470 $group .= form_select(t('Preformatted'), 'settings][preformatted', $edit->settings['preformatted'], array('false' => 'false', 'true' => 'true'), t('If this option is set to true, the editor will insert TAB characters on tab and preserve other whitespace characters just like a PRE HTML element does.'));
471 $output .= form_group(t('On save'), $group);
472
473 $group = form_select(t('Editor CSS'), 'settings][css_setting', $edit->settings['css_setting'] ? $edit->settings['css_setting'] : 'theme', array('theme' => 'use theme css', 'self' => 'define css', 'none' => 'tinyMCE default'), t('Defines the CSS to be used in the editor area.<br />use theme css - get css from current Drupal theme.<br/>define css - enter path for css file below.<br />tinyMCE default - uses default CSS from editor.'));
474 $group .= form_textfield(t('CSS path'), 'settings][css_path', $edit->settings['css_path'], 40, 255, t('Enter path to CSS file (example: "/css/editor.css"). Select "define css" above.'));
475 $group .= form_textfield(t('CSS classes'), 'settings][css_classes', $edit->settings['css_classes'], 40, 255, t('Adds CSS classes to the "styles" droplist. Format is "&lt;title&gt;=&lt;class&gt;;"<br/> Example: "Header 1=header1;Header 2=header2;Header 3=header3;"<br />Leave blank to automatically import list of CSS classes from style sheet.'));
476 $output .= form_group(t('CSS'), $group);
477
478 $group = form_textfield(t('Block formats'), 'settings][block_formats', $edit->settings['block_formats'] ? $edit->settings['block_formats'] : 'p,address,pre,h1,h2,h3,h4,h5,h6', 40, 250, t('Comma separated list of HTML block formats. You can only remove elements, not add.'));
479 $group .= form_select(t('Force BR new lines'), 'settings][force_br', $edit->settings['force_br'] ? $edit->settings['force_br'] : 'false', array('true' => 'true', 'false' => 'false'), t('Use BR tags for new lines rather than P.'));
480 $group .= form_select(t('Force P new lines'), 'settings][force_p', $edit->settings['force_p'] ? $edit->settings['force_p'] : 'true', array('true' => 'true', 'false' => 'false'), t('When enabled, Mozilla/Firefox will generate P elements on Enter/Return key and BR elements on Shift+Enter/Return..'));
481 $output .= form_group(t('Formatting'), $group);
482
483 $output .= form_submit($btn);
484
485 return form($output);
486 }
487
488 /**
489 * Load all profiles.
490 */
491 function tinymce_profile_load($name = '') {
492 static $profiles = array();
493
494 if (!$profiles) {
495 $roles = user_roles();
496 $result = db_query('SELECT * FROM {tinymce_settings}');
497 while ($data = db_fetch_object($result)) {
498 $data->settings = unserialize($data->settings);
499 $result2 = db_query("SELECT rid FROM {tinymce_role} WHERE name = '%s'", $data->name);
500 $role = array();
501 while ($r = db_fetch_object($result2)) {
502 $role[$r->rid] = $roles[$r->rid];
503 }
504 $data->rids = $role;
505
506 $profiles[$data->name] = $data;
507 }
508 }
509
510 return ($name ? $profiles[$name] : $profiles);
511 }
512
513 /**
514 * Controller for tinymce profiles.
515 */
516 function tinymce_profile_overview() {
517 $output = '';
518
519 $output .= t('<p><a href="%create-profile-url">Create new profile</a></p>', array('%create-profile-url' => url('admin/settings/tinymce/add')));
520
521 $profiles = tinymce_profile_load();
522 if ($profiles) {
523 $roles = user_roles();
524 $header = array(t('Profile'), t('Roles'), t('Operations'));
525 foreach ($profiles as $p) {
526 $rows[] = array(array('data' => $p->name, 'valign' => 'top'), array('data' => implode("<br />\n", $p->rids)), array('data' => l(t('edit'), 'admin/settings/tinymce/edit/'. urlencode($p->name)) . ' '. l(t('delete'), 'admin/settings/tinymce/delete/'. urlencode($p->name)), 'valign' => 'top'));
527 }
528 $output .= theme('table', $header, $rows). '<p>&nbsp;</p>';
529 }
530 else {
531 $output .= t('<p>No profiles found.</p>');
532 }
533
534 $group = form_radios(t('Default tinymce state'), 'tinymce_default_state', variable_get('tinymce_default_state', 0), array(t('Off'), t('On')), t('Should tinymce be enabled or disabled by default when it\'s first loaded from a textarea? Note: The user may override this setting in their profile.'));
535 $output .= form_group(t('Default settings'), $group);
536 $output .= form_submit(t('Save settings'));
537
538 return form($output);
539 }
540
541 /**
542 * Save a profile to the database.
543 */
544 function tinymce_profile_save($edit) {
545 db_query("DELETE FROM {tinymce_settings} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
546 db_query("DELETE FROM {tinymce_role} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
547 db_query("INSERT INTO {tinymce_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], serialize($edit['settings']));
548 foreach ($edit['rids'] as $rid) {
549 db_query("INSERT INTO {tinymce_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid);
550 }
551 }
552
553 /**
554 * Profile validation.
555 */
556 function tinymce_profile_validate($edit) {
557 $errors = array();
558
559 if (!$edit['name']) {
560 $errors['name'] = t('You must give a profile name.');
561 }
562
563 if (!$edit['rids']) {
564 $errors['rids'] = t('You must select at least one role.');
565 }
566
567 foreach ($errors as $name => $message) {
568 form_set_error($name, $message);
569 }
570
571 return count($errors) == 0;
572 }
573
574 /********************************************************************
575 * Module Functions :: Private
576 ********************************************************************/
577
578 /**
579 * Determine if TinyMCE has permission to be used on the current page.
580 *
581 * @return
582 * TRUE if can render, FALSE if not allowed.
583 */
584 function _tinymce_page_match($edit) {
585 //Kill TinyMCE if we're editing a textarea with PHP in it!
586 if ($_POST['edit']['format'] == 2) {
587 return FALSE;
588 }
589 else {
590 // PHP input formats are #2 in the filters table.
591 preg_match("|^node/(\d+)(/edit)$|", $_GET['q'], $match);
592 if (intval($match[1]) > 0) {
593 if (db_result(db_query('SELECT format FROM {node} WHERE nid = %d AND format = 2', $match[1]))) {
594 return FALSE;
595 }
596 }
597 }
598
599 if ($edit->settings['access'] == 1) {
600 return TRUE;
601 }
602 else {
603 $page_match = FALSE;
604 $pages = $edit->settings['access_pages'] ? $edit->settings['access_pages'] : tinymce_help('admin/settings/tinymce#pages');
605 if ($pages) {
606 $path = drupal_get_path_alias($_GET['q']);
607 $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. variable_get('site_frontpage', 'node') .'\2'), preg_quote($pages, '/')) .')$/';
608 $page_match = preg_match($regexp, $path);
609 }
610 return $page_match;
611 }
612 }
613 ?>