Removing translation directories
[project/tinymce.git] / tinymce.module
CommitLineData
6f760c55 1<?php
76a1692d
MW
2// A collaborative project by Matt Westgate <drupal at asitis dot org>,
3// Richard Bennett <richard.b@ at ritechnologies dot com> and Jeff Robbins <robbins at jjeff dot com>
6f760c55
MW
4
5/**
6 * @file
7 * Integrate the TinyMCE editor (http://tinymce.moxiecode.com/) into Drupal.
8 */
9
10/**
11 * Implementation of hook_menu().
6f760c55
MW
12 */
13function tinymce_menu($may_cache) {
01a85ffd 14 $items = array();
277d4328 15 if ($may_cache) {
401a6487 16 $items[] = array('path' => 'admin/settings/tinymce', 'title' => t('TinyMCE'),
277d4328 17 'callback' => 'tinymce_admin',
401a6487 18 'description' => t('Configure the rich editor.'),
277d4328 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) {
6f760c55
MW
29 case 'admin/settings/tinymce#pages':
30 return "node/*\nuser/*\ncomment/*";
2227c39d 31 case 'admin/settings/tinymce':
020cd8d1 32 case 'admin/help#tinymce' :
0cc5775a
TS
33 return t('<p style="font-size:x-small">$Revision$ $Date$</p>' .
34 '<p>TinyMCE adds what-you-see-is-what-you-get (WYSIWYG) html editing to textareas. This editor can be enabled/disabled without reloading the page by clicking a link below each textarea.</p>
020cd8d1 35 <p>Profiles can be defined based on user roles. A 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.</p>
401a6487 36 <p>Lastly, only users with the <code>access tinymce</code> <a href="!url">permission</a> will be able to use TinyMCE.</p>', array('!url' => url('admin/user/access'))
020cd8d1 37 );
6f760c55
MW
38 }
39}
40
41/**
42 * Implementation of hook_perm().
43 */
44function tinymce_perm() {
0cc5775a
TS
45 $array = array('administer tinymce', 'access tinymce');
46 $tinymce_mod_path = drupal_get_path('module', 'tinymce');
5f3fa2a4 47
0cc5775a
TS
48 if (is_dir($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/imagemanager/')) {
49 $array[] = 'access tinymce imagemanager';
50 }
51 if (is_dir($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/filemanager/')) {
52 $array[] = 'access tinymce filemanager';
53 }
5f3fa2a4 54
0cc5775a 55 return $array;
6f760c55
MW
56}
57
58/**
5120a0c6 59 * Implementation of hook_elements().
64d74024 60 */
5120a0c6 61function tinymce_elements() {
eb76ebc7
MW
62 $type = array();
63
64 if (user_access('access tinymce')) {
5f3fa2a4
KR
65 // Let TinyMCE potentially process each textarea.
66 $type['textarea'] = array('#process' => array('tinymce_process_textarea' => array()));
eb76ebc7
MW
67 }
68
5120a0c6
MW
69 return $type;
70}
71
72/**
73 * Attach tinymce to a textarea
74 */
75function tinymce_process_textarea($element) {
dd7d7335 76 static $is_running = FALSE;
6f760c55 77 global $user;
6a17f63a 78 static $profile_name;
5f3fa2a4 79
5120a0c6
MW
80 //$element is an array of attributes for the textarea but there is no just 'name' value, so we extract this from the #id field
81 $textarea_name = substr($element['#id'], strpos($element['#id'], '-') + 1);
6f760c55 82
01a85ffd
MW
83 // Since tinymce_config() makes a db hit, only call it when we're pretty sure
84 // we're gonna render tinymce.
5120a0c6
MW
85 if (!$profile_name) {
86 $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))));
5f3fa2a4
KR
87 if (!$profile_name) {
88 return $element;
89 }
01a85ffd 90 }
5120a0c6
MW
91 $profile = tinymce_profile_load($profile_name);
92 $init = tinymce_config($profile);
2bc52cdf 93 $init['elements'] = 'edit-'. $textarea_name;
6739c75d 94
5120a0c6 95 if (_tinymce_page_match($profile)) {
2227c39d
MW
96 // Merge user-defined TinyMCE settings.
97 $init = (array) theme('tinymce_theme', $init, $textarea_name, $init['theme'], $is_running);
5120a0c6
MW
98
99 // If $init array is empty no need to execute rest of code since there are no textareas to theme with TinyMCE
100 if (count($init) < 1) {
101 return $element;
102 }
d8e137a6 103
2227c39d 104 $settings = array();
6739c75d 105 foreach ($init as $k => $v) {
a59a8ef6 106 $v = is_array($v) ? implode(',', $v) : $v;
76a1692d
MW
107 // Don't wrap the JS init in quotes for boolean values or functions.
108 if (strtolower($v) != 'true' && strtolower($v) != 'false' && $v[0] != '{') {
01a85ffd
MW
109 $v = '"'. $v. '"';
110 }
111 $settings[] = $k. ' : '. $v;
6739c75d 112 }
2b031c84 113 $tinymce_settings = implode(",\n ", $settings);
6739c75d 114
277d4328
MW
115 $enable = t('enable rich-text');
116 $disable = t('disable rich-text');
117
01a85ffd 118$tinymce_invoke = <<<EOD
401a6487 119
6f760c55 120 tinyMCE.init({
6739c75d 121 $tinymce_settings
6f760c55 122 });
401a6487 123
277d4328
MW
124EOD;
125
5f3fa2a4
KR
126$tinymce_gz_invoke = <<<EOD
127
128 tinyMCE_GZ.init({
129 $tinymce_settings
130 });
131
132EOD;
133
277d4328 134$js_toggle = <<<EOD
401a6487 135
277d4328
MW
136 function mceToggle(id, linkid) {
137 element = document.getElementById(id);
138 link = document.getElementById(linkid);
139 img_assist = document.getElementById('img_assist-link-'+ id);
140
dd9e8af1
TS
141 if (tinyMCE.getEditorId(element.id) == null) {
142 tinyMCE.addMCEControl(element, element.id);
277d4328
MW
143 element.togg = 'on';
144 link.innerHTML = '$disable';
145 link.href = "javascript:mceToggle('" +id+ "', '" +linkid+ "');";
146 if (img_assist)
3898aa05 147 img_assist.innerHTML = '';
277d4328
MW
148 link.blur();
149 }
150 else {
dd9e8af1 151 tinyMCE.removeMCEControl(tinyMCE.getEditorId(element.id));
277d4328
MW
152 element.togg = 'off';
153 link.innerHTML = '$enable';
154 link.href = "javascript:mceToggle('" +id+ "', '" +linkid+ "');";
155 if (img_assist)
3898aa05 156 img_assist.innerHTML = img_assist_default_link;
277d4328
MW
157 link.blur();
158 }
159 }
401a6487 160
6f760c55
MW
161EOD;
162
0cc5775a
TS
163$status = tinymce_user_get_status($user, $profile);
164
165// note we test for string == true because we save our settings as strings
166$link_text = $status == 'true' ? $disable : $enable;
3898aa05 167$img_assist_link = ($status == 'true') ? 'yes' : 'no';
277d4328 168$no_wysiwyg = t('Your current web browser does not support WYSIWYG editing.');
01a85ffd 169$wysiwyg_link = <<<EOD
0bdcb567 170<script type="text/javascript">
6a17f63a
MW
171 img_assist = document.getElementById('img_assist-link-edit-$textarea_name');
172 if (img_assist) {
3898aa05
TS
173 var img_assist_default_link = img_assist.innerHTML;
174 if ('$img_assist_link' == 'yes') {
175 img_assist.innerHTML = tinyMCE.getEditorId('edit-$textarea_name') == null ? '' : img_assist_default_link;
5f3fa2a4 176 }
3898aa05
TS
177 else {
178 img_assist.innerHTML = tinyMCE.getEditorId('edit-$textarea_name') == null ? img_assist_default_link : '';
179 }
6a17f63a 180 }
01a85ffd 181 if (typeof(document.execCommand) == 'undefined') {
3898aa05 182 img_assist.innerHTML = img_assist_default_link;
0bdcb567 183 document.write('<div style="font-size:x-small">$no_wysiwyg</div>');
01a85ffd
MW
184 }
185 else {
0bdcb567 186 document.write("<div><a href=\"javascript:mceToggle('edit-$textarea_name', 'wysiwyg4$textarea_name');\" id=\"wysiwyg4$textarea_name\">$link_text</a></div>");
01a85ffd
MW
187 }
188</script>
189EOD;
190
65badaba 191 // We only load the TinyMCE js file once per request
76a1692d 192 if (!$is_running) {
dd7d7335 193 $is_running = TRUE;
1689159f 194 $tinymce_mod_path = drupal_get_path('module', 'tinymce');
5f3fa2a4 195
0cc5775a 196 if (is_dir($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/imagemanager/') && user_access('access tinymce imagemanager') ) {
9a6185a0 197 // if tinymce imagemanager is installed
0cc5775a 198 drupal_add_js($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/imagemanager/jscripts/mcimagemanager.js');
9a6185a0 199 }
5f3fa2a4 200
0cc5775a
TS
201 if (is_dir($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/filemanager/') && user_access('access tinymce filemanager') ) {
202 // if tinymce filemanager is installed
203 drupal_add_js($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/filemanager/jscripts/mcfilemanager.js');
204 }
5f3fa2a4
KR
205
206 // TinyMCE Compressor 1.0.9 and greater
207 if (file_exists($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/tiny_mce_gzip.js')) {
208 drupal_add_js($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/tiny_mce_gzip.js');
209 drupal_add_js($tinymce_gz_invoke, 'inline');
210 }
211 // TinyMCE Compressor (versions < 1.0.9)
212 elseif (file_exists($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/tiny_mce_gzip.php')) {
71e75abb 213 drupal_add_js($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/tiny_mce_gzip.php');
1689159f
MW
214 }
215 else {
216 // For some crazy reason IE will only load this JS file if the absolute reference is given to it.
71e75abb 217 drupal_add_js($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/tiny_mce.js');
1689159f 218 }
401a6487 219 drupal_add_js($js_toggle, 'inline');
277d4328
MW
220 // We have to do this becuase of some unfocused CSS in certain themes. See http://drupal.org/node/18879 for details
221 drupal_set_html_head('<style type="text/css" media="all">.mceEditor img { display: inline; }</style>');
dd7d7335 222 }
65badaba 223 // Load a TinyMCE init for each textarea.
401a6487 224 if ($init) drupal_add_js($tinymce_invoke, 'inline');
d8e137a6 225
bd27043d
TS
226 //settings are saved as strings, not booleans
227 if ($profile->settings['show_toggle'] == 'true') {
228 // Make sure to append to #suffix so it isn't completely overwritten
229 $element['#suffix'] .= $wysiwyg_link;
230 }
5f3fa2a4
KR
231 // Set resizable to false to avoid drupal.js resizable function from taking control of the textarea
232 $element['#resizable'] = FALSE;
6f760c55 233 }
5120a0c6
MW
234
235 return $element;
6f760c55
MW
236}
237
238/**
239 * Implementation of hook_user().
240 */
241function tinymce_user($type, &$edit, &$user, $category = NULL) {
dd7d7335 242 if ($type == 'form' && $category == 'account' && user_access('access tinymce')) {
0cc5775a
TS
243 $profile = tinymce_user_get_profile($user);
244
245 // because the settings are saved as strings we need to test for the string 'true'
246 if ($profile->settings['user_choose'] == 'true') {
247 $form['tinymce'] = array(
5f3fa2a4
KR
248 '#type' => 'fieldset',
249 '#title' => t('TinyMCE rich-text settings'),
250 '#weight' => 10,
251 '#collapsible' => TRUE,
0cc5775a
TS
252 '#collapsed' => TRUE
253 );
5f3fa2a4 254
0cc5775a 255 $form['tinymce']['tinymce_status'] = array(
5f3fa2a4 256 '#type' => 'select',
0cc5775a 257 '#title' => t('Default state'),
5f3fa2a4
KR
258 '#default_value' => isset($user->tinymce_status) ? $user->tinymce_status : (isset($profile->settings['default']) ? $profile->settings['default'] : 'false'),
259 '#options' => array('false' => t('disabled'), 'true' => t('enabled')),
0cc5775a 260 '#description' => t('Should rich-text editing be enabled or disabled by default in textarea fields?')
5f3fa2a4
KR
261 );
262
0cc5775a
TS
263 return array('tinymce' => $form);
264 }
6f760c55
MW
265 }
266 if ($type == 'validate') {
01a85ffd 267 return array('tinymce_status' => $edit['tinymce_status']);
6f760c55
MW
268 }
269}
270
271/**
6739c75d
MW
272 * @addtogroup themeable
273 * @{
274 */
275
276/**
ae7b55ca 277 * Customize a TinyMCE theme.
6739c75d
MW
278 *
279 * @param init
ae7b55ca
MW
280 * An array of settings TinyMCE should invoke a theme. You may override any
281 * of the TinyMCE settings. Details here:
6739c75d
MW
282 *
283 * http://tinymce.moxiecode.com/wrapper.php?url=tinymce/docs/using.htm
ae7b55ca
MW
284 *
285 * @param textarea_name
286 * The name of the textarea TinyMCE wants to enable.
287 *
288 * @param theme_name
2227c39d
MW
289 * The default tinymce theme name to be enabled for this textarea. The
290 * sitewide default is 'simple', but the user may also override this.
dd7d7335
MW
291 *
292 * @param is_running
293 * A boolean flag that identifies id TinyMCE is currently running for this
2227c39d 294 * request life cycle. It can be ignored.
6739c75d 295 */
dd7d7335 296function theme_tinymce_theme($init, $textarea_name, $theme_name, $is_running) {
9670911b 297 switch ($textarea_name) {
2227c39d 298 // Disable tinymce for these textareas
1161cf9b 299 case 'log': // book and page log
2227c39d 300 case 'img_assist_pages':
4048ba98 301 case 'caption': // signature
097b5629 302 case 'pages':
5120a0c6 303 case 'access_pages': //TinyMCE profile settings.
af1fa2b0
TS
304 case 'user_mail_welcome_body': // user config settings
305 case 'user_mail_approval_body': // user config settings
306 case 'user_mail_pass_body': // user config settings
307 case 'synonyms': // taxonomy terms
308 case 'description': // taxonomy terms
2227c39d
MW
309 unset($init);
310 break;
311
312 // Force the 'simple' theme for some of the smaller textareas.
9670911b
MW
313 case 'signature':
314 case 'site_mission':
315 case 'site_footer':
f3d0d7eb
TS
316 case 'site_offline_message':
317 case 'page_help':
318 case 'user_registration_help':
319 case 'user_picture_guidelines':
9670911b 320 $init['theme'] = 'simple';
a59a8ef6
MW
321 foreach ($init as $k => $v) {
322 if (strstr($k, 'theme_advanced_')) unset($init[$k]);
323 }
2227c39d 324 break;
9670911b
MW
325 }
326
7a2a524b 327 /* Example, add some extra features when using the advanced theme.
5f3fa2a4 328
7a2a524b
TS
329 // If $init is available, we can extend it
330 if (isset($init)) {
331 switch ($theme_name) {
332 case 'advanced':
333 $init['extended_valid_elements'] = array('a[href|target|name|title|onclick]');
334 break;
335 }
ae7b55ca 336 }
5f3fa2a4 337
633100e5 338 */
2227c39d 339
7a2a524b 340 // Always return $init
2227c39d 341 return $init;
6739c75d
MW
342}
343
344/** @} End of addtogroup themeable */
345
346/**
6f760c55
MW
347 * Grab the themes available to TinyMCE.
348 *
349 * TinyMCE themes control the functionality and buttons that are available to a
350 * user. Themes are only looked for within the default TinyMCE theme directory.
351 *
a59a8ef6
MW
352 * NOTE: This function is not used in this release. We are only using advanced theme.
353 *
6f760c55
MW
354 * @return
355 * An array of theme names.
356 */
357function _tinymce_get_themes() {
358 static $themes = array();
359
360 if (!$themes) {
361 $theme_loc = drupal_get_path('module', 'tinymce') .'/tinymce/jscripts/tiny_mce/themes/';
362 if (is_dir($theme_loc) && $dh = opendir($theme_loc)) {
363 while (($file = readdir($dh)) !== false) {
ae24db96 364 if (!in_array($file, array('.', '..', 'CVS')) && is_dir($theme_loc . $file)) {
6f760c55
MW
365 $themes[$file] = $file;
366 }
367 }
368 closedir($dh);
369 asort($themes);
370 }
371 }
372
373 return $themes;
374}
375
a59a8ef6
MW
376/**
377 * Return plugin metadata from the plugin registry.
378 *
379 * We also scrape each plugin's *.js file for the human friendly name and help
380 * text URL of each plugin.
381 *
382 * @return
383 * An array for each plugin.
384 */
385function _tinymce_get_buttons($skip_metadata = TRUE) {
386 include_once(drupal_get_path('module', 'tinymce'). '/plugin_reg.php');
387 $plugins = _tinymce_plugins();
5f3fa2a4 388
a59a8ef6
MW
389 if ($skip_metadata == FALSE && is_array($plugins)) {
390 foreach ($plugins as $name => $plugin) {
391 $file = drupal_get_path('module', 'tinymce'). '/tinymce/jscripts/tiny_mce/plugins/'. $name .'/editor_plugin_src.js';
392 // Grab the plugin metadata by scanning the *.js file.
393 if (file_exists($file)) {
a48b5273 394 $lines = file($file);
a59a8ef6
MW
395 $has_longname = FALSE;
396 $has_infourl = FALSE;
397 foreach ($lines as $line) {
398 if ($has_longname && $has_infourl) break;
399 if (strstr($line, 'longname')) {
400 $start = strpos($line, "'") + 1;
401 $end = strrpos($line, "'") - $start;
402 $metadata[$name]['longname'] = substr($line, $start, $end);
403 $has_longname = TRUE;
404 }
405 elseif (strstr($line, 'infourl')) {
406 $start = strpos($line, "'") + 1;
407 $end = strrpos($line, "'") - $start;
408 $metadata[$name]['infourl'] = substr($line, $start, $end);
409 $has_infourl = TRUE;
410 }
411 }
412 }
413
414 // Find out the buttons a plugin has.
415 foreach ($plugin as $k => $v) {
416 if (strstr($k, 'theme_advanced_buttons')) {
417 $metadata[$name]['buttons'] = array_merge((array) $metadata[$name]['buttons'], $plugin[$k]);
418 }
419 }
420 }
421 return $metadata;
422 }
423
424 return $plugins;
425}
01a85ffd
MW
426/********************************************************************
427 * Module Functions :: Public
428 ********************************************************************/
429
430/**
431 * Controller for tinymce administrative settings.
432 */
433function tinymce_admin($arg = NULL) {
d8e137a6 434
401a6487 435 $edit = $_POST;
01a85ffd
MW
436 $op = $_POST['op'];
437
438 $op = $arg && !$op ? $arg : $op;
439
440 switch ($op) {
441 case 'add':
442 $breadcrumb[] = array('path' => 'admin', 'title' => t('administer'));
277d4328 443 $breadcrumb[] = array('path' => 'admin/settings/tinymce', 'title' => t('tinymce'));
0cc5775a 444 $breadcrumb[] = array('path' => 'admin/settings/tinymce/add', 'title' => t('Add new TinyMCE profile'));
01a85ffd
MW
445 menu_set_location($breadcrumb);
446 $output = tinymce_profile_form($edit);
447 break;
448
449 case 'edit':
450 drupal_set_title(t('Edit tinymce profile'));
277d4328 451 $output = tinymce_profile_form(tinymce_profile_load(urldecode(arg(4))));
01a85ffd
MW
452 break;
453
454 case 'delete':
277d4328 455 tinymce_profile_delete(urldecode(arg(4)));
01a85ffd 456 drupal_set_message(t('Deleted profile'));
277d4328 457 drupal_goto('admin/settings/tinymce');
01a85ffd
MW
458 break;
459
460 case t('Create profile');
461 case t('Update profile');
462 if (tinymce_profile_validate($edit)) {
463 tinymce_profile_save($edit);
0cc5775a 464 $edit['old_name'] ? drupal_set_message(t('Your TinyMCE profile has been updated.')) : drupal_set_message(t('Your TinyMCE profile has been created.'));
277d4328 465 drupal_goto('admin/settings/tinymce');
01a85ffd
MW
466 }
467 else {
468 $output = tinymce_profile_form($edit);
469 }
470 break;
471
01a85ffd 472 default:
0cc5775a 473 drupal_set_title(t('TinyMCE settings'));
01a85ffd
MW
474 //Check if TinyMCE is installed.
475 $tinymce_loc = drupal_get_path('module', 'tinymce') .'/tinymce/';
476 if (!is_dir($tinymce_loc)) {
401a6487 477 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');
01a85ffd
MW
478 }
479 $output = tinymce_profile_overview();
480 }
481
0cc5775a 482 return $output;
01a85ffd
MW
483}
484
485/**
486 * Return an array of initial tinymce config options from the current role.
487 */
488function tinymce_config($profile) {
9670911b 489 global $user;
5f3fa2a4 490
a59a8ef6 491 // Drupal theme path.
7248584b
TS
492 $themepath = path_to_theme() . '/';
493 $host = base_path();
01a85ffd 494
195b5d64 495 $settings = $profile->settings;
01a85ffd
MW
496
497 // Build a default list of TinyMCE settings.
9670911b
MW
498
499 // Is tinymce on by default?
0cc5775a 500 $status = tinymce_user_get_status($user, $profile);
5f3fa2a4 501
0cc5775a
TS
502 $init['mode'] = $status == 'true' ? 'exact' : 'none';
503 $init['theme'] = $settings['theme'] ? $settings['theme'] : 'advanced';
2e3c467c 504 $init['relative_urls'] = 'false';
7248584b 505 $init['document_base_url'] = "$host";
1da6d2bb 506 $init['language'] = $settings['language'] ? $settings['language'] : 'en';
0cc5775a 507 $init['safari_warning'] = $settings['safari_message'] ? $settings['safari_message'] : 'false';
ef6204c6 508 $init['entity_encoding'] = 'raw';
76a1692d 509 $init['verify_html'] = $settings['verify_html'] ? $settings['verify_html'] : 'false';
76a1692d 510 $init['preformatted'] = $settings['preformatted'] ? $settings['preformatted'] : 'false';
5f3fa2a4
KR
511 $init['convert_fonts_to_spans'] = $settings['convert_fonts_to_spans'] ? $settings['convert_fonts_to_spans'] : 'false';
512 $init['remove_linebreaks'] = $settings['remove_linebreaks'] ? $settings['remove_linebreaks'] : 'true';
513 $init['apply_source_formatting'] = $settings['apply_source_formatting'] ? $settings['apply_source_formatting'] : 'true';
401a6487
NR
514 $init['theme_advanced_resize_horizontal'] = 'false';
515 $init['theme_advanced_resizing_use_cookie'] = 'false';
5f3fa2a4 516
0cc5775a
TS
517
518 $tinymce_mod_path = drupal_get_path('module', 'tinymce');
519 if (is_dir($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/imagemanager/') && user_access('access tinymce imagemanager')) {
520 // we probably need more security than this
521 $init['file_browser_callback'] = "mcImageManager.filebrowserCallBack";
522 }
523 if (is_dir($tinymce_mod_path . '/tinymce/jscripts/tiny_mce/plugins/filemanager/') && user_access('access tinymce filemanager')) {
524 // we probably need more security than this
525 $init['file_browser_callback'] = "mcImageManager.filebrowserCallBack";
526 }
5f3fa2a4 527
93c073b0 528 if ($init['theme'] == 'advanced') {
a59a8ef6 529 $init['plugins'] = array();
76a1692d
MW
530 $init['theme_advanced_toolbar_location'] = $settings['toolbar_loc'] ? $settings['toolbar_loc'] : 'bottom';
531 $init['theme_advanced_toolbar_align'] = $settings['toolbar_align'] ? $settings['toolbar_align'] : 'left';
23044442
MW
532 $init['theme_advanced_path_location'] = $settings['path_loc'] ? $settings['path_loc'] : 'bottom';
533 $init['theme_advanced_resizing'] = $settings['resizing'] ? $settings['resizing'] : 'true';
76a1692d 534 $init['theme_advanced_blockformats'] = $settings['block_formats'] ? $settings['block_formats'] : 'p,address,pre,h1,h2,h3,h4,h5,h6';
a59a8ef6 535
5120a0c6 536 if (is_array($settings['buttons'])) {
a59a8ef6
MW
537 // This gives us the $plugins variable.
538 $plugins = _tinymce_get_buttons();
539
540 // Find the enabled buttons and the mce row they belong on. Also map the
541 // plugin metadata for each button.
542 $plugin_tracker = array();
543 foreach ($plugins as $rname => $rplugin) { // Plugin name
544 foreach ($rplugin as $mce_key => $mce_value) { // TinyMCE key
545 foreach ($mce_value as $k => $v) { // Buttons
5120a0c6 546 if ($settings['buttons'][$rname . '-' . $v]) {
c6bfd92a
TS
547 // Font isn't a true plugin, rather it's buttons made available by the advanced theme
548 if (!in_array($rname, $plugin_tracker) && $rname != 'font') $plugin_tracker[] = $rname;
a59a8ef6
MW
549 $init[$mce_key][] = $v;
550 }
551 }
552 }
17e0f529
TS
553 // Some advanced plugins only have an $rname and no buttons
554 if ($settings['buttons'][$rname]) {
555 if (!in_array($rname, $plugin_tracker)) $plugin_tracker[] = $rname;
556 }
a59a8ef6
MW
557 }
558
559 // Add the rest of the TinyMCE config options to the $init array for each button.
560 if (is_array($plugin_tracker)) {
561 foreach ($plugin_tracker as $pname) {
562 if ($pname != 'default') $init['plugins'][] = $pname;
563 foreach ($plugins[$pname] as $mce_key => $mce_value) {
17e0f529
TS
564 // Don't overwrite buttons or extended_valid_elements
565 if ($mce_key == 'extended_valid_elements') {
566 // $mce_value is an array for extended_valid_elements so just grab the first element in the array (never more than one)
567 $init[$mce_key][] = $mce_value[0];
568 }
569 else if (!strstr($mce_key, 'theme_advanced_buttons')) {
a59a8ef6
MW
570 $init[$mce_key] = $mce_value;
571 }
572 }
573 }
574 }
575
576 // Cleanup
577 foreach ($init as $mce_key => $mce_value) {
578 if (is_array($mce_value)) $mce_value = array_unique($mce_value);
579 $init[$mce_key] = $mce_value;
580 }
581
582 // Shuffle buttons around so that row 1 always has the most buttons,
583 // followed by row 2, etc. Note: These rows need to be set to NULL otherwise
584 // TinyMCE loads it's own buttons inherited from the theme.
585 if (!$init['theme_advanced_buttons1']) $init['theme_advanced_buttons1'] = array();
586 if (!$init['theme_advanced_buttons2']) $init['theme_advanced_buttons2'] = array();
587 if (!$init['theme_advanced_buttons3']) $init['theme_advanced_buttons3'] = array();
588
589 $min_btns = 5; // Minimum number of buttons per row.
d5f8e20a 590 $num1 = count($init['theme_advanced_buttons1']);
a59a8ef6
MW
591 $num2 = count($init['theme_advanced_buttons2']);
592 $num3 = count($init['theme_advanced_buttons3']);
593
594 if ($num3 < $min_btns) {
595 $init['theme_advanced_buttons2'] = array_merge($init['theme_advanced_buttons2'], $init['theme_advanced_buttons3']);
596 $init['theme_advanced_buttons3'] = array();
d5f8e20a 597 $num2 = count($init['theme_advanced_buttons2']);
a59a8ef6
MW
598 }
599 if ($num2 < $min_btns) {
600 $init['theme_advanced_buttons1'] = array_merge($init['theme_advanced_buttons1'], $init['theme_advanced_buttons2']);
d5f8e20a
TS
601 // Squish the rows together, since row 2 is empty
602 $init['theme_advanced_buttons2'] = $init['theme_advanced_buttons3'];
603 $init['theme_advanced_buttons3'] = array();
604 $num1 = count($init['theme_advanced_buttons1']);
a59a8ef6 605 }
d5f8e20a
TS
606 if ($num1 < $min_btns) {
607 $init['theme_advanced_buttons1'] = array_merge($init['theme_advanced_buttons1'], $init['theme_advanced_buttons2']);
608 // Squish the rows together, since row 2 is empty
609 $init['theme_advanced_buttons2'] = $init['theme_advanced_buttons3'];
610 $init['theme_advanced_buttons3'] = array();
611 }
612
a59a8ef6 613 }
93c073b0 614 }
01a85ffd 615
ad6e88a9 616 if ($settings['css_classes']) $init['theme_advanced_styles'] = $settings['css_classes'];
01a85ffd
MW
617
618 if ($settings['css_setting'] == 'theme') {
26444876 619 $css = $themepath . 'style.css';
01a85ffd 620 if (file_exists($css)) {
26444876 621 $init['content_css'] = $host . $css;
01a85ffd 622 }
9a6185a0 623 }
26444876
JR
624 else if ($settings['css_setting'] == 'self') {
625 $init['content_css'] = str_replace(array('%h', '%t'), array($host, $themepath), $settings['css_path']);
626 }
a59a8ef6 627
01a85ffd
MW
628 return $init;
629}
630
6f760c55 631/**
01a85ffd
MW
632 * Remove a profile from the database.
633 */
634function tinymce_profile_delete($name) {
195b5d64
MW
635 db_query("DELETE FROM {tinymce_settings} WHERE name = '%s'", $name);
636 db_query("DELETE FROM {tinymce_role} WHERE name = '%s'", $name);
01a85ffd
MW
637}
638
639/**
640 * Return an HTML form for profile configuration.
641 */
401a6487 642function tinymce_profile_form_build($edit) {
d8e137a6 643 $edit = (object) $edit;
01a85ffd
MW
644
645 // Only display the roles that currently don't have a tinymce profile. One
646 // profile per role.
4048ba98 647 $orig_roles = user_roles(FALSE, 'access tinymce');
01a85ffd 648 $roles = $orig_roles;
277d4328 649 if (arg(3) == 'add') {
195b5d64 650 $result = db_query('SELECT DISTINCT(rid) FROM {tinymce_role}');
01a85ffd 651 while ($data = db_fetch_object($result)) {
0cc5775a
TS
652 if (!in_array($data->rid, array_keys((array) $edit->rids)) && !form_get_errors()){
653 unset($roles[$data->rid]);
654 }
01a85ffd 655 }
5120a0c6 656 if (!$orig_roles) {
401a6487 657 drupal_set_message(t('You must <a href="!access-control-url">assign</a> at least one role with the \'access tinymce\' permission before creating a profile.', array('!access-control-url' => url('admin/user/access'))), 'error');
5120a0c6
MW
658 }
659 else if (!$roles) {
4048ba98 660 drupal_set_message(t('You will not be allowed to create a new profile since all user roles have already been assigned profiles. Either remove an existing tinymce profile from at least one role or assign another role the \'access tinymce\' permission.'), 'error');
01a85ffd
MW
661 }
662 else if (count($orig_roles) != count($roles)) {
663 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.'));
664 }
665 $btn = t('Create profile');
666 }
667 else {
a48b5273 668 $form['old_name'] = array('#type' => 'hidden', '#value' => $edit->name);
01a85ffd
MW
669 $btn = t('Update profile');
670 }
671
0cc5775a 672 $form['basic'] = array(
5f3fa2a4
KR
673 '#type' => 'fieldset',
674 '#title' => t('Basic setup'),
675 '#collapsible' => TRUE,
0cc5775a
TS
676 '#collapsed' => TRUE
677 );
5f3fa2a4 678
0cc5775a 679 $form['basic']['name'] = array(
5f3fa2a4
KR
680 '#type' => 'textfield',
681 '#title' => t('Profile name'),
682 '#default_value' => $edit->name,
683 '#size' => 40,
684 '#maxlength' => 128,
685 '#description' => t('Enter a name for this profile. This name is only visible within the tinymce administration page.'),
0cc5775a
TS
686 '#required' => TRUE
687 );
5f3fa2a4 688
0cc5775a 689 $form['basic']['rids'] = array(
5f3fa2a4
KR
690 '#type' => 'checkboxes',
691 '#title' => t('Roles allowed to use this profile'),
692 '#default_value' => array_keys((array) $edit->rids),
693 '#options' => $roles,
694 '#description' => t('Check at least one role. Only roles with \'access tinymce\' permission will be shown here.'),
0cc5775a
TS
695 '#required' => TRUE
696 );
5f3fa2a4 697
0cc5775a 698 $form['basic']['default'] = array(
5f3fa2a4 699 '#type' => 'select',
0cc5775a 700 '#title' => t('Default state'),
5f3fa2a4
KR
701 '#default_value' => $edit->settings['default'] ? $edit->settings['default'] : 'false',
702 '#options' => array('false' => t('disabled'), 'true' => t('enabled')),
0cc5775a
TS
703 '#description' => t('Default editor state for users in this profile. Users will be able to override this state if the next option is enabled.'),
704 );
5f3fa2a4 705
0cc5775a 706 $form['basic']['user_choose'] = array(
5f3fa2a4 707 '#type' => 'select',
0cc5775a 708 '#title' => t('Allow users to choose default'),
5f3fa2a4
KR
709 '#default_value' => $edit->settings['user_choose'] ? $edit->settings['user_choose'] : 'false',
710 '#options' => array('false' => t('false'), 'true' => t('true')),
0cc5775a
TS
711 '#description' => t('If allowed, users will be able to choose their own TinyMCE default state by visiting their profile page.'),
712 );
5f3fa2a4 713
bd27043d 714 $form['basic']['show_toggle'] = array(
5f3fa2a4 715 '#type' => 'select',
bd27043d 716 '#title' => t('Show disable/enable rich text editor toggle'),
5f3fa2a4
KR
717 '#default_value' => $edit->settings['show_toggle'] ? $edit->settings['show_toggle'] : 'true',
718 '#options' => array('false' => t('false'), 'true' => t('true')),
bd27043d
TS
719 '#description' => t('Whether or not to show the disable/enable rich text editor toggle below the textarea. If false, editor defaults to the global default or user default (see above).'),
720 );
5f3fa2a4 721
32dcf62b
MW
722 // This line upgrades previous versions of TinyMCE for user who previously selected a theme other than advanced.
723 if ($edit->settings['theme'] != 'advanced') $edit->settings['theme'] = 'advanced';
5f3fa2a4 724
0cc5775a 725 $form['basic']['theme'] = array(
5f3fa2a4 726 '#type' => 'hidden',
0cc5775a
TS
727 '#value' => $edit->settings['theme'] ? $edit->settings['theme'] : 'advanced'
728 );
5f3fa2a4 729
0cc5775a 730 $form['basic']['language'] = array(
5f3fa2a4
KR
731 '#type' => 'select',
732 '#title' => t('Language'),
733 '#default_value' => $edit->settings['language'] ? $edit->settings['language'] : 'en',
734 '#options' => drupal_map_assoc(array('ar', 'ca', 'cs', 'cy', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fr', 'fr_ca', 'he', 'hu', 'is', 'it', 'ja', 'ko', 'nb', 'nl', 'nn', 'pl', 'pt', 'pt_br', 'ru', 'ru_KOI8-R', 'ru_UTF-8', 'si', 'sk', 'sv', 'th', 'zh_cn', 'zh_tw', 'zh_tw_utf8')),
0cc5775a
TS
735 '#description' => t('The language for the TinyMCE interface. Language codes based on the <a href="http://www.loc.gov/standards/iso639-2/englangn.html">ISO-639-2</a> format.')
736 );
5f3fa2a4 737
0cc5775a 738 $form['basic']['safari_message'] = array(
5f3fa2a4 739 '#type' => 'select',
0cc5775a 740 '#title' => t('Safari browser warning'),
5f3fa2a4
KR
741 '#default_value' => $edit->settings['safari_message'] ? $edit->settings['safari_message'] : 'false',
742 '#options' => array('false' => t('false'), 'true' => t('true')),
0cc5775a
TS
743 '#description' => t('TinyMCE support for the Safari web browser is experimental and a warning message is displayed when that browser is detected. You can disable this message here.')
744 );
c3fb581d 745
0cc5775a 746 $form['visibility'] = array(
5f3fa2a4
KR
747 '#type' => 'fieldset',
748 '#title' => t('Visibility'),
749 '#collapsible' => TRUE,
0cc5775a
TS
750 '#collapsed' => TRUE
751 );
5f3fa2a4 752
d6185d4c
TS
753 $access = user_access('use PHP for block visibility');
754
755 // If the visibility is set to PHP mode but the user doesn't have this block permission, don't allow them to edit nor see this PHP code
756 if ($edit->settings['access'] == 2 && !$access) {
757 $form['visibility'] = array();
0cc5775a 758 $form['visibility']['access'] = array(
5f3fa2a4 759 '#type' => 'value',
0cc5775a
TS
760 '#value' => 2
761 );
762 $form['visibility']['access_pages'] = array(
5f3fa2a4 763 '#type' => 'value',
0cc5775a
TS
764 '#value' => $edit->settings['access_pages']
765 );
d6185d4c
TS
766 }
767 else {
768 $options = array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.'));
401a6487 769 $description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are '!blog' for the blog page and !blog-wildcard for every personal blog. !front is the front page.", array('!blog' => theme('placeholder', 'blog'), '!blog-wildcard' => theme('placeholder', 'blog/*'), '!front' => theme('placeholder', '<front>')));
d8e137a6 770
d6185d4c
TS
771 if ($access) {
772 $options[] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
401a6487 773 $description .= t('If the PHP-mode is chosen, enter PHP code between !php. Note that executing incorrect PHP-code can break your Drupal site.', array('!php' => theme('placeholder', '<?php ?>')));
d6185d4c 774 }
0cc5775a 775 $form['visibility']['access'] = array(
5f3fa2a4
KR
776 '#type' => 'radios',
777 '#title' => t('Show tinymce on specific pages'),
778 '#default_value' => isset($edit->settings['access']) ? $edit->settings['access'] : 1,
0cc5775a
TS
779 '#options' => $options
780 );
781 $form['visibility']['access_pages'] = array(
5f3fa2a4
KR
782 '#type' => 'textarea',
783 '#title' => t('Pages'),
784 '#default_value' => isset($edit->settings['access_pages']) ? $edit->settings['access_pages'] : tinymce_help('admin/settings/tinymce#pages'),
0cc5775a
TS
785 '#description' => $description
786 );
d6185d4c 787 }
d8e137a6 788
0cc5775a 789 $form['buttons'] = array(
5f3fa2a4
KR
790 '#type' => 'fieldset',
791 '#title' => t('Buttons and plugins'),
792 '#collapsible' => TRUE,
793 '#collapsed' => TRUE,
794 '#tree' => TRUE,
0cc5775a
TS
795 '#theme' => 'tinymce_profile_form_buttons'
796 );
d8e137a6 797
a59a8ef6
MW
798 $metadata = _tinymce_get_buttons(FALSE);
799 // Generate the button list.
800 foreach($metadata as $name => $meta) {
801 if (is_array($meta['buttons'])) {
802 foreach ($meta['buttons'] as $button) {
803 if ($name != 'default') {
804 $img_src = drupal_get_path('module', 'tinymce'). "/tinymce/jscripts/tiny_mce/plugins/$name/images/$name.gif";
d8e137a6 805
5120a0c6
MW
806 //correct for plugins that have more than one button
807 if (!file_exists($img_src)) {
808 $img_src = drupal_get_path('module', 'tinymce'). "/tinymce/jscripts/tiny_mce/plugins/$name/images/$button.gif";
809 }
a59a8ef6
MW
810 }
811 else {
812 $img_src = drupal_get_path('module', 'tinymce'). "/tinymce/jscripts/tiny_mce/themes/advanced/images/$button.gif";
813 }
d8e137a6 814
71e75abb 815 $b = file_exists($img_src) ? '<img src="'. base_path() . $img_src .'" title="'. $button .'" style="border: 1px solid grey; vertical-align: middle;" />' : $button;
a59a8ef6
MW
816
817 if ($name == 'default') {
818 $title = $b;
819 }
820 else {
821 $title = $metadata[$name]['longname'] ? $metadata[$name]['longname'] : $name;
822 if ($metadata[$name]['infourl']) {
823 $title = '<a href="'. $metadata[$name]['infourl'] .'" target="_blank">'. $title .'</a>';
824 }
5120a0c6 825 $title = $b . ' &#8211; '. $title;
a59a8ef6 826 }
5120a0c6 827 $form_value = $edit->settings['buttons'][$name . '-' . $button];
475be68a 828 $form['buttons'][$name . '-' . $button] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => $form_value);
a59a8ef6
MW
829 }
830 }
831 else {
832 $title = $metadata[$name]['longname'] ? $metadata[$name]['longname'] : $name;
833 if ($metadata[$name]['infourl']) {
834 $title = '<a href="'. $metadata[$name]['infourl'] .'" target="_blank">'. $title .'</a>';
835 }
5120a0c6 836 $form_value = $edit->settings['buttons'][$name];
475be68a 837 $form['buttons'][$name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => $form_value);
a59a8ef6
MW
838 }
839 }
5120a0c6 840
0cc5775a 841 $form['appearance'] = array(
5f3fa2a4
KR
842 '#type' => 'fieldset',
843 '#title' => t('Editor appearance'),
844 '#collapsible' => TRUE,
0cc5775a
TS
845 '#collapsed' => TRUE
846 );
5f3fa2a4 847
0cc5775a 848 $form['appearance']['toolbar_loc'] = array(
5f3fa2a4
KR
849 '#type' => 'select',
850 '#title' => t('Toolbar location'),
851 '#default_value' => $edit->settings['toolbar_loc'],
852 '#options' => array('bottom' => t('bottom'), 'top' => t('top')),
0cc5775a
TS
853 '#description' => t('Show toolbar at the top or bottom of the editor area?')
854 );
5f3fa2a4 855
0cc5775a 856 $form['appearance']['toolbar_align'] = array(
5f3fa2a4
KR
857 '#type' => 'select',
858 '#title' => t('Toolbar alignment'),
859 '#default_value' => $edit->settings['toolbar_align'],
860 '#options' => array('center' => t('center'), 'left' => t('left'), 'right' => t('right')),
0cc5775a
TS
861 '#description' => t('Align tool icons left, center, or right within the toolbar.')
862 );
5f3fa2a4 863
0cc5775a 864 $form['appearance']['path_loc'] = array(
5f3fa2a4
KR
865 '#type' => 'select',
866 '#title' => t('Path location'),
867 '#default_value' => $edit->settings['path_loc'] ? $edit->settings['path_loc'] : 'bottom',
868 '#options' => array('none' => t('none'), 'top' => t('top'), 'bottom' => t('bottom')),
0cc5775a
TS
869 '#description' => t('Path to html elements (i.e. "body>table>tr>td"). Show at top, bottom, or not at all.')
870 );
5f3fa2a4 871
0cc5775a 872 $form['appearance']['resizing'] = array(
5f3fa2a4
KR
873 '#type' => 'select',
874 '#title' => t('Enable resizing button'),
60b54b51 875 '#default_value' => isset($edit->settings['resizing']) ? $edit->settings['resizing'] : 'true',
5f3fa2a4 876 '#options' => array('false' => t('false'), 'true' => t('true')),
0cc5775a
TS
877 '#description' => t(' This option gives you the ability to enable/disable the resizing button. If enabled the <strong>Path location toolbar</strong> must be set to "top" or "bottom" in order to display the resize icon.')
878 );
5f3fa2a4 879
0cc5775a 880 $form['appearance']['block_formats'] = array(
5f3fa2a4
KR
881 '#type' => 'textfield',
882 '#title' => t('Block formats'),
883 '#default_value' => $edit->settings['block_formats'] ? $edit->settings['block_formats'] : 'p,address,pre,h1,h2,h3,h4,h5,h6',
884 '#size' => 40,
885 '#maxlength' => 250,
0cc5775a
TS
886 '#description' => t('Comma separated list of HTML block formats. You can only remove elements, not add.')
887 );
d8e137a6 888
0cc5775a 889 $form['output'] = array(
5f3fa2a4
KR
890 '#type' => 'fieldset',
891 '#title' => t('Cleanup and output'),
892 '#collapsible' => TRUE,
0cc5775a
TS
893 '#collapsed' => TRUE
894 );
5f3fa2a4 895
0cc5775a 896 $form['output']['verify_html'] = array(
5f3fa2a4
KR
897 '#type' => 'select',
898 '#title' => t('Verify HTML'),
899 '#default_value' => $edit->settings['verify_html'],
900 '#options' => array('false' => t('false'), 'true' => t('true')),
0cc5775a
TS
901 '#description' => 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.')
902 );
5f3fa2a4 903
0cc5775a 904 $form['output']['preformatted'] = array(
5f3fa2a4
KR
905 '#type' => 'select',
906 '#title' => t('Preformatted'),
907 '#default_value' => $edit->settings['preformatted'],
908 '#options' => array('false' => t('false'), 'true' => t('true')),
0cc5775a
TS
909 '#description' => 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.')
910 );
5f3fa2a4
KR
911
912 $form['output']['convert_fonts_to_spans'] = array(
913 '#type' => 'select',
914 '#title' => t('Convert &lt;font&gt; tags to styles'),
915 '#default_value' => $edit->settings['convert_fonts_to_spans'],
916 '#options' => array('true' => t('true'), 'false' => t('false')),
0cc5775a
TS
917 '#description' => t('If you set this option to true, font size, font family, font color and font background color will be replaced by inline styles.')
918 );
a48b5273 919
5f3fa2a4
KR
920 $form['output']['remove_linebreaks'] = array(
921 '#type' => 'select',
922 '#title' => t('Remove linebreaks'),
923 '#default_value' => $edit->settings['remove_linebreaks'],
924 '#options' => array('true' => 'true', 'false' => 'false'),
925 '#description' => t('Set this option to false to prevent TinyMCE from removing linebreaks from existing nodes. True avoids conflicts with some filters.')
926 );
927
928 $form['output']['apply_source_formatting'] = array(
929 '#type' => 'select',
930 '#title' => t('Apply source formatting'),
931 '#default_value' => $edit->settings['apply_source_formatting'],
932 '#options' => array('true' => 'true', 'false' => 'false'),
933 '#description' => t('This option makes TinyMCE apply source formatting. Set this to true for a cleaner HTML source. Choose false to avoid conflicts with some filters.')
934 );
935
0cc5775a 936 $form['css'] = array(
5f3fa2a4
KR
937 '#type' => 'fieldset',
938 '#title' => t('CSS'),
939 '#collapsible' => TRUE,
0cc5775a
TS
940 '#collapsed' => TRUE
941 );
5f3fa2a4 942
0cc5775a 943 $form['css']['css_setting'] = array(
5f3fa2a4
KR
944 '#type' => 'select',
945 '#title' => t('Editor CSS'),
946 '#default_value' => $edit->settings['css_setting'] ? $edit->settings['css_setting'] : 'theme',
947 '#options' => array('theme' => t('use theme css'), 'self' => t('define css'), 'none' => t('tinyMCE default')),
0cc5775a
TS
948 '#description' => t('Defines the CSS to be used in the editor area.<br />use theme css - load style.css from current site theme.<br/>define css - enter path for css file below.<br />tinyMCE default - uses default CSS from editor.')
949 );
5f3fa2a4 950
0cc5775a 951 $form['css']['css_path'] = array(
5f3fa2a4
KR
952 '#type' => 'textfield',
953 '#title' => t('CSS path'),
954 '#default_value' => $edit->settings['css_path'],
955 '#size' => 40,
956 '#maxlength' => 255,
957 '#description' => t('Enter path to CSS file (<em>example: "css/editor.css"</em>) or a list of css files seperated by a comma (<em>example: /themes/garland/style.css,http://domain.com/customMCE.css</em>).<br />Macros: %h (host name: http://www.example.com/), %t (path to theme: theme/yourtheme/)<br />Be sure to select "define css" above.')
0cc5775a 958 );
5f3fa2a4 959
0cc5775a 960 $form['css']['css_classes'] = array(
5f3fa2a4
KR
961 '#type' => 'textfield',
962 '#title' => t('CSS classes'),
963 '#default_value' => $edit->settings['css_classes'],
964 '#size' => 40,
965 '#maxlength' => 255,
0cc5775a
TS
966 '#description' => 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 (note: no trailing \';\')<br />Leave blank to automatically import list of CSS classes from style sheet.')
967 );
a48b5273 968
0cc5775a 969 $form['submit'] = array(
5f3fa2a4 970 '#type' => 'submit',
0cc5775a
TS
971 '#value' => $btn
972 );
d8e137a6 973
401a6487
NR
974 return $form;
975}
976
977/**
978 * Return an HTML form for profile configuration.
979 */
980function tinymce_profile_form($edit) {
981
982 $output .= drupal_get_form('tinymce_profile_form_build', $edit);
a48b5273
MW
983
984 return $output;
985}
986
987/**
988 * Layout for the buttons in the tinymce profile form
989 */
990function theme_tinymce_profile_form_buttons($form) {
991 $buttons = array();
d8e137a6 992
a48b5273
MW
993 // Flatten forms array
994 foreach (element_children($form) as $key) {
401a6487 995 $buttons[] = drupal_render($form[$key]);
a48b5273 996 }
a59a8ef6 997
5120a0c6
MW
998 //split checkboxes into rows with 3 columns
999 $total = count($buttons);
1000 $rows = array();
1001 for ($i = 0; $i < $total; $i++) {
1002 $row = array();
1003 $row[] = array('data' => $buttons[$i]);
1004 $row[] = array('data' => $buttons[++$i]);
1005 $row[] = array('data' => $buttons[++$i]);
1006 $rows[] = $row;
a59a8ef6 1007 }
5120a0c6
MW
1008
1009 $output = theme('table', array(), $rows, array('width' => '100%'));
a59a8ef6 1010
a48b5273 1011 return $output;
01a85ffd
MW
1012}
1013
1014/**
76a1692d 1015 * Load all profiles. Just load one profile if $name is passed in.
01a85ffd
MW
1016 */
1017function tinymce_profile_load($name = '') {
1018 static $profiles = array();
1019
1020 if (!$profiles) {
65badaba 1021 $roles = user_roles();
01a85ffd
MW
1022 $result = db_query('SELECT * FROM {tinymce_settings}');
1023 while ($data = db_fetch_object($result)) {
1024 $data->settings = unserialize($data->settings);
195b5d64 1025 $result2 = db_query("SELECT rid FROM {tinymce_role} WHERE name = '%s'", $data->name);
01a85ffd 1026 $role = array();
195b5d64
MW
1027 while ($r = db_fetch_object($result2)) {
1028 $role[$r->rid] = $roles[$r->rid];
01a85ffd
MW
1029 }
1030 $data->rids = $role;
93c073b0 1031
01a85ffd
MW
1032 $profiles[$data->name] = $data;
1033 }
1034 }
93c073b0
MW
1035
1036 return ($name ? $profiles[$name] : $profiles);
01a85ffd
MW
1037}
1038
1039/**
1040 * Controller for tinymce profiles.
1041 */
1042function tinymce_profile_overview() {
1043 $output = '';
01a85ffd
MW
1044
1045 $profiles = tinymce_profile_load();
1046 if ($profiles) {
65badaba 1047 $roles = user_roles();
01a85ffd
MW
1048 $header = array(t('Profile'), t('Roles'), t('Operations'));
1049 foreach ($profiles as $p) {
277d4328 1050 $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 1051 }
0cc5775a 1052 $output .= theme('table', $header, $rows);
401a6487 1053 $output .= t('<p><a href="!create-profile-url">Create new profile</a></p>', array('!create-profile-url' => url('admin/settings/tinymce/add')));
01a85ffd
MW
1054 }
1055 else {
401a6487 1056 drupal_set_message(t('No profiles found. Click here to <a href="!create-profile-url">create a new profile</a>.', array('!create-profile-url' => url('admin/settings/tinymce/add'))));
01a85ffd
MW
1057 }
1058
a48b5273 1059 return $output;
01a85ffd
MW
1060}
1061
1062/**
1063 * Save a profile to the database.
1064 */
1065function tinymce_profile_save($edit) {
1066 db_query("DELETE FROM {tinymce_settings} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
195b5d64 1067 db_query("DELETE FROM {tinymce_role} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
a48b5273
MW
1068 db_query("INSERT INTO {tinymce_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], serialize($edit));
1069 foreach ($edit['rids'] as $rid => $value) {
e297a3c0 1070 db_query("INSERT INTO {tinymce_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid);
195b5d64 1071 }
0cc5775a
TS
1072
1073 // if users can't set their own defaults, make sure to remove $user->tinymce_status so their default doesn't override the main default
1074 if ($edit['user_choose'] == 'false') {
1075 global $user;
1076 user_save($user, array('tinymce_status' => NULL));
1077 }
01a85ffd
MW
1078}
1079
1080/**
1081 * Profile validation.
1082 */
1083function tinymce_profile_validate($edit) {
1084 $errors = array();
1085
1086 if (!$edit['name']) {
195b5d64 1087 $errors['name'] = t('You must give a profile name.');
01a85ffd
MW
1088 }
1089
1090 if (!$edit['rids']) {
1091 $errors['rids'] = t('You must select at least one role.');
1092 }
1093
1094 foreach ($errors as $name => $message) {
1095 form_set_error($name, $message);
1096 }
1097
1098 return count($errors) == 0;
1099}
1100
1101/********************************************************************
1102 * Module Functions :: Private
1103 ********************************************************************/
1104
1105/**
1106 * Determine if TinyMCE has permission to be used on the current page.
6f760c55
MW
1107 *
1108 * @return
1109 * TRUE if can render, FALSE if not allowed.
1110 */
01a85ffd 1111function _tinymce_page_match($edit) {
c3fb581d
TS
1112 $page_match = FALSE;
1113
ea749313
TS
1114 // Kill TinyMCE if we're editing a textarea with PHP in it!
1115 // PHP input formats are #2 in the filters table.
923da23a 1116 if (is_numeric(arg(1)) && arg(2) == 'edit') {
ea749313
TS
1117 $node = node_load(arg(1));
1118 if ($node->format == 2) {
1119 return FALSE;
6f760c55
MW
1120 }
1121 }
1122
c3fb581d
TS
1123 if ($edit->settings['access_pages']) {
1124 // If the PHP option wasn't selected
1125 if ($edit->settings['access'] < 2) {
6f760c55 1126 $path = drupal_get_path_alias($_GET['q']);
c3fb581d
TS
1127 $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($edit->settings['access_pages'], '/')) .')$/';
1128 $page_match = !($edit->settings['access'] xor preg_match($regexp, $path));
1129 }
1130 else {
1131 $page_match = drupal_eval($edit->settings['access_pages']);
6f760c55 1132 }
6f760c55 1133 }
c3fb581d
TS
1134 // No pages were specified to block so show on all
1135 else {
1136 $page_match = TRUE;
1137 }
d8e137a6 1138
c3fb581d 1139 return $page_match;
6f760c55 1140}
0cc5775a
TS
1141
1142function tinymce_user_get_profile($account) {
1143 $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($account->roles))));
1144 if ($profile_name){
1145 return tinymce_profile_load($profile_name);
1146 }
1147 else {
1148 return FALSE;
1149 }
1150}
1151
1152function tinymce_user_get_status($user, $profile){
1153 $settings = $profile->settings;
1154
1155 if ($settings['user_choose']) {
1156 $status = isset($user->tinymce_status) ? $user->tinymce_status : (isset($settings['default']) ? $settings['default'] : 'false');
1157 }
1158 else {
1159 $status = isset($settings['default']) ? $settings['default'] : 'false';
1160 }
1161
1162 return $status;
1163}