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