#338923 Improve description of security setting
[project/fckeditor.git] / fckeditor.module
CommitLineData
04b827fa 1<?php
e44c2389 2// $Id$
8de1e54a 3/**
0c87a920 4 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
20c63aec 5 * Copyright (C) 2003-2008 Frederico Caldeira Knabben
ebc6fdec 6 *
0c87a920 7 * == BEGIN LICENSE ==
9b429add 8 *
0c87a920
WW
9 * Licensed under the terms of any of the following licenses at your
10 * choice:
f3d88ca0 11 *
0c87a920
WW
12 * - GNU General Public License Version 2 or later (the "GPL")
13 * http://www.gnu.org/licenses/gpl.html
9b429add 14 *
0c87a920
WW
15 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
16 * http://www.gnu.org/licenses/lgpl.html
ebc6fdec 17 *
0c87a920
WW
18 * - Mozilla Public License Version 1.1 or later (the "MPL")
19 * http://www.mozilla.org/MPL/MPL-1.1.html
ebc6fdec 20 *
0c87a920 21 * == END LICENSE ==
9b429add 22 *
0c87a920 23 * @file
20c63aec 24 * FCKeditor Module for Drupal 6.x
0c87a920
WW
25 *
26 * This module allows Drupal to replace textarea fields with FCKeditor.
04b827fa 27 *
0c87a920
WW
28 * This HTML text editor brings to the web many of the powerful functionalities
29 * of known desktop editors like Word. It's really lightweight and doesn't
30 * require any kind of installation on the client computer.
04b827fa
DS
31 */
32
0c87a920
WW
33/**
34 * The name of simplified toolbar which should be forced
35 * Be sure that this toolbar is defined in fckeditor.config.js or fckconfig.js
36 */
37define('FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME', 'DrupalBasic') ;
04b827fa 38
95e32685
WW
39global $_fckeditor_configuration;
40global $_fckeditor_js_ids;
c46c807b 41
95e32685
WW
42$_fckeditor_configuration = array();
43$_fckeditor_js_ids = array();
c46c807b 44
04b827fa 45/**
075c1a2d 46 * Implementation of hook_help().
af8e9eeb 47 *
1b120ffb
JS
48 * This function delegates execution to fckeditor_help_delegate() in fckeditor.help.inc to
49 * lower the amount of code in fckeditor.module
04b827fa 50 */
0c87a920 51function fckeditor_help($path, $arg) {
1b120ffb
JS
52 module_load_include('help.inc', 'fckeditor');
53 return module_invoke('fckeditor', 'help_delegate', $path, $arg);
54}
0c87a920 55
1b120ffb
JS
56/**
57 * Implementation of hook_user().
af8e9eeb 58 *
1b120ffb
JS
59 * This function delegates execution to fckeditor_user_delegate() in fckeditor.user.inc to
60 * lower the amount of code in fckeditor.module
61 */
62function fckeditor_user($type, $edit, &$user, $category = NULL) {
63 if (($type == 'form' && $category == 'account' && user_access('access fckeditor')) || $type == 'validate') {
64 module_load_include('user.inc', 'fckeditor');
65 return module_invoke('fckeditor', 'user_delegate', $type, $edit, $user, $category);
04b827fa 66 }
f60bb09c 67 return NULL;
04b827fa
DS
68}
69
b45d1789 70/*
f60bb09c
JS
71 * Run if there is old menu information in database
72 */
b45d1789 73function fckeditor_admin($arg = NULL) {
f1bbcab7 74 drupal_set_message(t('The FCKeditor component is not installed correctly. You should run the <a href="@update-php">database update script</a> immediately.', array('@update-php' => base_path() .'update.php')), 'error');
b45d1789
WW
75 return FALSE;
76}
77
04b827fa 78/**
075c1a2d 79 * Implementation of hook_perm().
20c63aec 80 * Administer -> User management -> Permissions
04b827fa
DS
81 */
82function fckeditor_perm() {
0c87a920 83 return array('administer fckeditor', 'access fckeditor', 'allow fckeditor file uploads');
04b827fa
DS
84}
85
04b827fa 86/**
075c1a2d 87 * Implementation of hook_elements().
0c87a920 88 * Replace textarea with FCKeditor using callback function (fckeditor_process_textarea)
04b827fa 89 */
f3d88ca0 90function fckeditor_elements() {
91 $type = array();
e794befa 92 $type['textfield'] = array(
0c87a920 93 '#process' => array(
1b120ffb
JS
94 'fckeditor_process_input'
95 ),
e794befa 96 );
0c87a920 97 if (user_access('access fckeditor')) {
f3d88ca0 98 // only roles with permission get the fckeditor
99 if (fckeditor_is_compatible_client()) {
100 // it would be useless to dig deeper if we're not able or allowed to
c46c807b 101 $type['textarea'] = array('#process' => array('fckeditor_process_textarea'));
da1cf0d0 102 $type['form'] = array('#after_build' => array('fckeditor_process_form'));
04b827fa
DS
103 }
104 }
f3d88ca0 105 return $type;
04b827fa
DS
106}
107
0c87a920 108/**
c46c807b
WW
109 * AJAX callback - XSS filter
110 */
111function fckeditor_filter_xss() {
5362261b
WW
112 $GLOBALS['devel_shutdown'] = FALSE;
113
c46c807b
WW
114 if (!isset($_POST['text']) || !is_string($_POST['text']) || !is_array($_POST['filters'])) {
115 exit;
116 }
da1cf0d0 117
c46c807b
WW
118 $text = $_POST['text'];
119 $text = strtr($text, array('<!--' => '__COMMENT__START__', '-->' => '__COMMENT__END__'));
da1cf0d0 120
c46c807b
WW
121 foreach ($_POST['filters'] as $module_delta) {
122 $module = strtok($module_delta, "/");
123 $delta = strtok("/");
124 $format = strtok("/");
5362261b
WW
125
126 if (!module_hook($module, 'filter')) {
127 continue;
128 }
129
c46c807b
WW
130 //built-in filter module, a special case where we would like to strip XSS and nothing more
131 if ($module == 'filter' && $delta == 0) {
132 preg_match_all("|</?([a-z][a-z0-9]*)(?:\b[^>]*)>|i", $text, $matches);
133 if ($matches[1]) {
134 $tags = array_unique($matches[1]);
135 $text = filter_xss($text, $tags);
136 }
137 }
138 else {
139 $text = module_invoke($module, 'filter', 'process', $delta, $format, $text);
140 }
141 }
da1cf0d0 142
c46c807b
WW
143 $text = strtr($text, array('__COMMENT__START__' => '<!--', '__COMMENT__END__' => '-->'));
144
145 echo $text;
146 exit;
147}
148
149function fckeditor_process_form(&$form) {
95e32685 150 global $_fckeditor_configuration, $_fckeditor_js_ids;
c46c807b
WW
151 static $processed_textareas = array();
152 static $found_textareas = array();
da1cf0d0 153
c46c807b
WW
154 //Skip if:
155 // - we're not editing an element
156 // - fckeditor is not enabled (configuration is empty)
95e32685 157 if (arg(1) == "add" || arg(1) == "reply" || !count($_fckeditor_configuration)) {
c46c807b 158 return $form;
da1cf0d0
WW
159 }
160
c46c807b 161 $fckeditor_filters = array();
da1cf0d0 162
c46c807b
WW
163 // Iterate over element children; resetting array keys to access last index.
164 if ($children = array_values(element_children($form))) {
165 foreach ($children as $index => $item) {
166 $element = &$form[$item];
167
95e32685 168 if (isset($element['#id']) && in_array($element['#id'], array_keys($_fckeditor_js_ids))) {
c46c807b
WW
169 $found_textareas[$element['#id']] = &$element;
170 }
da1cf0d0 171
c46c807b
WW
172 // filter_form() always uses the key 'format'. We need a type-agnostic
173 // match to prevent false positives. Also, there must have been at least
174 // one element on this level.
175 if ($item === 'format' && $index > 0) {
da1cf0d0 176
c46c807b
WW
177 // Make sure we either match a input format selector or input format
178 // guidelines (displayed if user has access to one input format only).
179 if ((isset($element['#type']) && $element['#type'] == 'fieldset') || isset($element['format']['guidelines'])) {
180 // The element before this element is the target form field.
181 $field = &$form[$children[$index - 1]];
182 $textarea_id = $field['#id'];
95e32685 183 $js_id = $_fckeditor_js_ids[$textarea_id];
da1cf0d0 184
c46c807b 185 array_push($processed_textareas, $js_id);
da1cf0d0 186
c46c807b 187 //search for checkxss1/2 class
95e32685 188 if (empty($field['#attributes']['class']) || strpos($field['#attributes']['class'], "checkxss") === FALSE) {
c46c807b
WW
189 continue;
190 }
191
192 // Determine the available input formats. The last child element is a
193 // link to "More information about formatting options". When only one
194 // input format is displayed, we also have to remove formatting
195 // guidelines, stored in the child 'format'.
da1cf0d0
WW
196 $formats = element_children($element);
197
c46c807b 198 foreach ($formats as $format_id) {
91651072 199 $format = !empty($element[$format_id]['#default_value']) ? $element[$format_id]['#default_value'] : $element[$format_id]['#value'];
c46c807b
WW
200 break;
201 }
da1cf0d0 202
c46c807b
WW
203 $enabled = filter_list_format($format);
204 $fckeditor_filters = array();
da1cf0d0 205
c46c807b
WW
206 //loop through all enabled filters
207 foreach ($enabled as $id => $filter) {
208 //but use only that one selected in FCKeditor profile
01a3fbad 209 if (in_array($id, array_keys($_fckeditor_configuration[$textarea_id]['filters'])) && $_fckeditor_configuration[$textarea_id]['filters'][$id]) {
c46c807b
WW
210 if (!isset($fckeditor_filters[$js_id])) {
211 $fckeditor_filters[$js_id] = array();
212 }
95e32685 213 $fckeditor_filters[$js_id][] = $id ."/". $format;
c46c807b
WW
214 }
215 }
da1cf0d0 216
c46c807b
WW
217 //No filters assigned, remove xss class
218 if (empty($fckeditor_filters[$js_id])) {
219 $field['#attributes']['class'] = preg_replace("/checkxss(1|2)/", "", $field['#attributes']['class']);
220 }
221 else {
222 $field['#attributes']['class'] = strtr($field['#attributes']['class'], array("checkxss1" => "filterxss1", "checkxss2" => "filterxss2"));
223 }
da1cf0d0 224
c46c807b
WW
225 array_pop($formats);
226 unset($formats['format']);
227 }
228 // If this element is 'format', do not recurse further.
229 continue;
230 }
231 // Recurse into children.
232 fckeditor_process_form($element);
233 }
234 }
da1cf0d0 235
c46c807b
WW
236 //We're in a form
237 if (isset($form['#action'])) {
238 //some textareas associated with FCKeditor has not been processed
95e32685 239 if (count($processed_textareas) < count($_fckeditor_js_ids)) {
c46c807b 240 //loop through all found textfields
383ecbc7 241 foreach (array_keys($found_textareas) as $id) {
95e32685 242 $element = &$found_textareas[$id];
c46c807b 243 //if not processed yet (checkxss class is before final processing)
01a3fbad 244 if (strpos($element['#attributes']['class'], "checkxss") !== FALSE && !in_array($_fckeditor_js_ids[$element['#id']], $processed_textareas) && !empty($_fckeditor_configuration[$id]['filters']) && array_sum($_fckeditor_configuration[$id]['filters'])) {
da1cf0d0 245 //assign default Filtered HTML to be safe on fields that do not have input format assigned, but only if at least one security filter is enabled in Security settings
95e32685 246 $js_id = $_fckeditor_js_ids[$element['#id']];
c46c807b
WW
247 $fckeditor_filters[$js_id][] = "filter/0/1";
248 $element['#attributes']['class'] = strtr($element['#attributes']['class'], array("checkxss1" => "filterxss1", "checkxss2" => "filterxss2"));
249 }
250 }
251 }
252 }
da1cf0d0 253
c46c807b
WW
254 if (!empty($fckeditor_filters)) {
255 drupal_add_js(array('fckeditor_filters' => $fckeditor_filters), 'setting');
256 }
da1cf0d0 257
c46c807b
WW
258 return $form;
259}
260
261/**
0c87a920 262 * Allow more than 255 chars in Allowed HTML tags textfield
0c87a920
WW
263 */
264function fckeditor_process_input($element) {
265 if ($element['#id']=='edit-allowed-html-1') {
266 $element['#maxlength'] = max($element['#maxlength'], 1024);
9b429add 267 }
0c87a920 268 return $element;
9b429add 269}
270
0c87a920 271/**
f60bb09c 272 * Implementation of hook_menu().
0c87a920
WW
273 */
274function fckeditor_menu() {
0c87a920 275 $items = array();
ebc6fdec 276
c46c807b
WW
277 $items['fckeditor/xss'] = array(
278 'title' => 'XSS Filter',
279 'description' => 'XSS Filter.',
280 'page callback' => 'fckeditor_filter_xss',
281 'access arguments' => array('access fckeditor'),
282 'type' => MENU_CALLBACK,
283 );
da1cf0d0 284
0c87a920 285 $items['admin/settings/fckeditor'] = array(
201b993d 286 'title' => 'FCKeditor settings',
287 'description' => 'Configure the rich text editor.',
288 'page callback' => 'fckeditor_admin_main',
289 'file' => 'fckeditor.admin.inc',
290 'access arguments' => array('administer fckeditor'),
291 'type' => MENU_NORMAL_ITEM,
f3d88ca0 292 );
af8e9eeb 293
1b120ffb 294 $items['admin/settings/fckeditor/add'] = array(
201b993d 295 'title' => 'Add new FCKeditor profile',
296 'description' => 'Configure the rich text editor.',
297 'page callback' => 'drupal_get_form',
298 'page arguments' => array('fckeditor_admin_profile_form'),
299 'file' => 'fckeditor.admin.inc',
300 'access arguments' => array('administer fckeditor'),
301 'type' => MENU_CALLBACK,
1b120ffb 302 );
af8e9eeb 303
4255581d 304 $items['admin/settings/fckeditor/clone/%fckeditor_profile'] = array(
201b993d 305 'title' => 'Clone FCKeditor profile',
306 'description' => 'Configure the rich text editor.',
307 'page callback' => 'drupal_get_form',
308 'page arguments' => array('fckeditor_admin_profile_clone_form', 4),
309 'file' => 'fckeditor.admin.inc',
310 'access arguments' => array('administer fckeditor'),
311 'type' => MENU_CALLBACK,
4255581d 312 );
af8e9eeb 313
1b120ffb 314 $items['admin/settings/fckeditor/edit/%fckeditor_profile'] = array(
201b993d 315 'title' => 'Edit FCKeditor profile',
316 'description' => 'Configure the rich text editor.',
317 'page callback' => 'drupal_get_form',
318 'page arguments' => array('fckeditor_admin_profile_form', 4),
319 'file' => 'fckeditor.admin.inc',
320 'access arguments' => array('administer fckeditor'),
321 'type' => MENU_CALLBACK,
1b120ffb 322 );
af8e9eeb 323
1b120ffb 324 $items['admin/settings/fckeditor/delete/%fckeditor_profile'] = array(
201b993d 325 'title' => 'Delete FCKeditor profile',
326 'description' => 'Configure the rich text editor.',
327 'page callback' => 'drupal_get_form',
328 'page arguments' => array('fckeditor_admin_profile_delete_form', 4),
329 'file' => 'fckeditor.admin.inc',
330 'access arguments' => array('administer fckeditor'),
331 'type' => MENU_CALLBACK,
1b120ffb 332 );
af8e9eeb 333
1b120ffb 334 $items['admin/settings/fckeditor/addg'] = array(
201b993d 335 'title' => 'Add FCKeditor Global profile',
336 'description' => 'Configure the rich text editor.',
337 'page callback' => 'drupal_get_form',
338 'page arguments' => array('fckeditor_admin_global_profile_form', 'add'),
339 'file' => 'fckeditor.admin.inc',
340 'access arguments' => array('administer fckeditor'),
341 'type' => MENU_CALLBACK,
1b120ffb 342 );
af8e9eeb 343
1b120ffb 344 $items['admin/settings/fckeditor/editg'] = array(
201b993d 345 'title' => 'Edit FCKeditor Global profile',
346 'description' => 'Configure the rich text editor.',
347 'page callback' => 'drupal_get_form',
348 'page arguments' => array('fckeditor_admin_global_profile_form', 'edit'),
349 'file' => 'fckeditor.admin.inc',
350 'access arguments' => array('administer fckeditor'),
351 'type' => MENU_CALLBACK,
1b120ffb 352 );
0c87a920 353
1b120ffb 354 return $items;
0c87a920
WW
355}
356
5d2db5be 357/**
1b120ffb 358 * Implementation of hook_init().
0c87a920 359 */
1b120ffb
JS
360function fckeditor_init() {
361 drupal_add_css(drupal_get_path('module', 'fckeditor') .'/fckeditor.css');
8de1e54a
WW
362}
363
0c87a920 364/**
da1cf0d0 365 * Implementation of hook_file_download().
1b120ffb 366 * Support for private downloads.
b94b689f 367 * FCKeditor does not implement any kind of potection on private files.
0c87a920 368 */
1b120ffb 369function fckeditor_file_download($file) {
b94b689f
WW
370 if ($path = file_create_path($file)) {
371 $result = db_query("SELECT f.* FROM {files} f WHERE filepath = '%s'", $path);
2ea49b21 372 if (db_fetch_object($result)) {
b94b689f 373 return NULL;
1b120ffb 374 }
da1cf0d0 375
b94b689f
WW
376 //No info in DB? Probably a file uploaded with FCKeditor
377 $global_profile = fckeditor_profile_load("FCKeditor Global Profile");
af8e9eeb 378
b94b689f
WW
379 //Assume that files inside of fckeditor directory belong to the FCKeditor. If private directory is set, let the decision about protection to the user.
380 $private_dir = isset($global_profile->settings['private_dir']) ? $global_profile->settings['private_dir'] : "/";
da1cf0d0 381
b94b689f
WW
382 //If path to the file points to the FCKeditor private directory, allow downloading
383 if (strpos($path, file_directory_path() ."/". trim($private_dir, "/\\")) === 0) {
384 $ctype = ($info = @getimagesize($path)) ? $info['mime'] : (function_exists('mime_content_type') ? mime_content_type($path) : 'application/x-download');
385 return array('Content-type: '. $ctype);
386 }
387 }
0c87a920
WW
388}
389
390/**
391 * Load all profiles. Just load one profile if $name is passed in.
392 */
393function fckeditor_profile_load($name = '') {
394 static $profiles = array();
395
396 if (!$profiles) {
4059f348 397 $result = db_query("SELECT * FROM {fckeditor_settings}");
075c1a2d 398 while (($data = db_fetch_object($result))) {
0c87a920 399 $data->settings = unserialize($data->settings);
1b120ffb 400 $data->rids = array();
af8e9eeb 401
0c87a920
WW
402 $profiles[$data->name] = $data;
403 }
af8e9eeb 404
1b120ffb 405 $roles = user_roles();
4059f348 406 $result = db_query("SELECT name, rid FROM {fckeditor_role}");
1b120ffb
JS
407 while (($data = db_fetch_object($result))) {
408 $profiles[$data->name]->rids[$data->rid] = $roles[$data->rid];
409 }
0c87a920 410 }
af8e9eeb 411
d9b9589c 412 return ($name ? (isset($profiles[urldecode($name)]) ? $profiles[urldecode($name)] : FALSE) : $profiles);
0c87a920
WW
413}
414
8de1e54a
WW
415/**
416 * @param int $excl_mode 1/include, exclude otherwise
c2652cc3 417 * @param string $excl_regex paths (drupal paths with ids attached)
8de1e54a
WW
418 * @param string $element_id current ID
419 * @param string $get_q current path
af8e9eeb 420 *
8de1e54a
WW
421 * @return boolean
422 * returns true if FCKeditor is enabled
423 */
c2652cc3
WW
424function fckeditor_is_enabled($excl_mode, $excl_regex, $element_id, $get_q) {
425 $front = variable_get('site_frontpage', 'node');
426 $excl_regex = str_replace('<front>', $front, $excl_regex);
0a856e81 427 $nodetype = fckeditor_get_nodetype($get_q);
8e2207fa 428 $element_id = str_replace('.', '\.', $element_id);
af8e9eeb 429
27c847ec 430 $match = !empty($excl_regex) && preg_match($excl_regex, $nodetype .'@'. $get_q .'.'. $element_id);
af8e9eeb 431
c2652cc3 432 return ($excl_mode == '0' xor $match);
0c87a920
WW
433}
434
435/**
9286dec5 436 * This function create the HTML objects required for the FCKeditor
e44c2389 437 *
438 * @param $element
439 * A fully populated form elment to add the editor to
440 * @return
441 * The same $element with extra FCKeditor markup and initialization
04b827fa 442 */
f3d88ca0 443function fckeditor_process_textarea($element) {
0c87a920
WW
444 static $is_running = FALSE;
445 static $num = 1;
95e32685 446 global $user, $language, $_fckeditor_configuration, $_fckeditor_js_ids;
27c847ec 447 $enabled = TRUE;
f3d88ca0 448
dec7b1d3 449 //hack for module developers that want to disable FCKeditor on their textareas
5c21faac 450 if (key_exists('#wysiwyg', $element) && !$element['#wysiwyg']) {
dec7b1d3
WW
451 return $element;
452 }
8de1e54a 453
a26718eb
JS
454 if (isset($element['#access']) && !$element['#access']) {
455 return $element;
456 }
457
dec7b1d3 458 //skip this one, surely nobody wants WYSIWYG here
0c87a920 459 switch ($element['#id']) {
0c87a920
WW
460 case 'edit-log':
461 return $element;
462 break;
463 }
8de1e54a 464
0c87a920 465 if (isset($element['#attributes']['disabled']) && $element['#attributes']['disabled'] == 'disabled') {
8de1e54a
WW
466 return $element;
467 }
d3cf16a0 468
af8e9eeb 469
44173850
WW
470 $global_profile = fckeditor_profile_load('FCKeditor Global Profile');
471 if ($global_profile) {
472 $global_conf = $global_profile->settings;
473 if ($global_conf) {
474 $enabled = fckeditor_is_enabled(empty($global_conf['excl_mode']) ? '0' : $global_conf['excl_mode'], empty($global_conf['excl_regex']) ? '' : $global_conf['excl_regex'], $element['#id'], $_GET['q']);
475 }
0c87a920
WW
476 }
477
44173850
WW
478 if ($enabled) {
479 $profile = fckeditor_user_get_profile($user, $element['#id']);
480 if ($profile) {
481 $conf = array();
482 $conf = $profile->settings;
483
484 if ($conf['allow_user_conf']=='t') {
485 foreach (array('default', 'show_toggle', 'popup', 'skin', 'toolbar', 'expand', 'width', 'lang', 'auto_lang') as $setting) {
486 $conf[$setting] = fckeditor_user_get_setting($user, $profile, $setting);
487 }
488 }
27c847ec
JS
489 if ($conf['popup'] == 't' && $conf['show_toggle'] == 't') {
490 $conf['show_toggle'] = 'f';
af8e9eeb 491 }
44173850
WW
492 }
493 else {
27c847ec 494 $enabled = FALSE;
0c87a920 495 }
0c87a920 496 }
da1cf0d0 497
c46c807b
WW
498 //old profile info, assume Filtered HTML is enabled
499 if (!isset($conf['ss'])) {
500 $conf['ss'] = 2;
501 $conf['filters']['filter/0'] = 1;
502 }
503 if (!isset($conf['filters'])) {
504 $conf['filters'] = array();
505 }
da1cf0d0 506
8de1e54a 507 $themepath = path_to_theme() .'/';
0c87a920
WW
508 $host = base_path();
509
3a55ac1f 510 if (!isset($element['#suffix'])) {
ef80606d 511 $element['#suffix'] = '';
3a55ac1f 512 }
af8e9eeb 513
ef80606d 514 // only replace textarea when it has enough rows and it is enabled
44173850 515 if ($enabled && (($element['#rows'] > $conf['min_rows']) || ($conf['min_rows'] <= 1 && empty($element['#rows'])))) {
ef80606d 516 $textarea_id = $element['#id'];
af8e9eeb 517
ef80606d
JS
518 if (!isset($element['#attributes'])) {
519 $element['#attributes'] = array();
e6589905 520 }
ef80606d
JS
521 if (!isset($element['#attributes']['class'])) {
522 $element['#attributes']['class'] = 'fckeditor';
f60bb09c
JS
523 }
524 else {
ef80606d
JS
525 $element['#attributes']['class'] .= ' fckeditor';
526 }
da1cf0d0 527
8de1e54a 528 $js_id = 'oFCK_'. $num++;
95e32685 529 $_fckeditor_js_ids[$element['#id']] = $js_id;
8de1e54a
WW
530 $fckeditor_on = ($conf['default']=='t') ? 1 : 0 ;
531
c46c807b
WW
532 $xss_check = 0;
533 //it's not a problem when adding new content/comment
534 if (arg(1) != "add" && arg(1) != "reply") {
95e32685 535 $_fckeditor_configuration[$element['#id']] = $conf;
da1cf0d0 536
c46c807b
WW
537 //let FCKeditor know when perform XSS checks auto/manual
538 if ($conf['ss'] == 1) {
539 $xss_class = 'checkxss1';
540 }
541 else {
542 $xss_class = 'checkxss2';
543 }
544
545 $element['#attributes']['class'] .= ' '. $xss_class;
546 $xss_check = 1;
547 }
da1cf0d0 548
0c87a920 549 //settings are saved as strings, not booleans
a38b3152 550 if ($conf['show_toggle'] == 't') {
ef80606d
JS
551 $content = '';
552 if (isset($element['#post']['teaser_js'])) {
553 $content .= $element['#post']['teaser_js'] .'<!--break-->';
554 }
555 $content .= $element['#value'];
556 $wysiwyg_link = '';
c46c807b 557 $wysiwyg_link .= "<a href=\"javascript:Toggle('{$textarea_id}','". str_replace("'", "\\'", t('Switch to plain text editor')) ."','". str_replace("'", "\\'", t('Switch to rich text editor')) ."',". $xss_check .");\" id=\"switch_{$textarea_id}\" ". ($fckeditor_on?"style=\"display:none\"":"") .">";
42225b39
WW
558 $wysiwyg_link .= $fckeditor_on ? t('Switch to plain text editor.') : t('Switch to rich text editor.');
559 $wysiwyg_link .= '</a>';
af8e9eeb 560
0c87a920
WW
561 // Make sure to append to #suffix so it isn't completely overwritten
562 $element['#suffix'] .= $wysiwyg_link;
563 }
f3d88ca0 564 // setting some variables
8de1e54a 565 $module_drupal_path = drupal_get_path('module', 'fckeditor');
29d8625e
WW
566 $module_full_path = $host . $module_drupal_path;
567 $editor_path = fckeditor_path(FALSE);
568 $editor_local_path = fckeditor_path(TRUE);
e2610d9c 569 // get the default drupal files path
29d8625e 570 $files_path = $host . file_directory_path();
0c87a920
WW
571 // module_drupal_path:
572 // 'modules/fckeditor' (length=17)
573 // module_full_path:
574 // '/drupal5/modules/fckeditor' (length=26)
575 // files_path:
576 // '/drupal5/files' (length=14)
f3d88ca0 577 // configured in settings
0c87a920 578 $width = $conf['width'];
f3d88ca0 579
580 // sensible default for small toolbars
c46c807b 581 $height = intval($element['#rows']) * 14 + 140;
f3d88ca0 582
0c87a920 583 if (!$is_running) {
8de1e54a 584 drupal_add_js($module_drupal_path .'/fckeditor.utils.js');
201b993d 585 /* In D6 drupal_add_js() can't add external JS, in D7 use drupal_add_js(...,'external') */
f60bb09c 586 drupal_set_html_head('<script type="text/javascript" src="'. $editor_path .'/fckeditor.js?I"></script>');
075c1a2d 587 $is_running = TRUE;
e44c2389 588 }
0c87a920
WW
589
590 $toolbar = $conf['toolbar'];
591 //$height += 100; // for larger toolbars
592
c2652cc3 593 $force_simple_toolbar = fckeditor_is_enabled('1', empty($conf['simple_incl_regex']) ? '' : $conf['simple_incl_regex'], $element['#id'], $_GET['q']);
8de1e54a 594 if (!$force_simple_toolbar) {
c2652cc3 595 $force_simple_toolbar = fckeditor_is_enabled('1', empty($global_conf['simple_incl_regex']) ? '' : $global_conf['simple_incl_regex'], $element['#id'], $_GET['q']);
8de1e54a
WW
596 }
597 if ($force_simple_toolbar) {
0c87a920 598 $toolbar = FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME;
f3d88ca0 599 }
af8e9eeb 600
ac9e6b9f
WW
601 if (!empty($conf['theme_config_js']) && $conf['theme_config_js'] == 't' && file_exists($themepath .'fckeditor.config.js')) {
602 $fckeditor_config_path = $host . $themepath .'fckeditor.config.js?'. @filemtime($themepath .'fckeditor.config.js');
603 }
604 else {
605 $fckeditor_config_path = $module_full_path ."/fckeditor.config.js?". @filemtime($module_drupal_path ."/fckeditor.config.js");
606 }
607
7254e6f4 608 $js = $js_id ." = new FCKeditor( '". $textarea_id ."' );
d065653a 609". $js_id .".defaultState = ". (($fckeditor_on && $conf['popup'] == 'f') ? 1 : 0) .";
8b081e6c 610". $js_id .".BasePath = '". $editor_path ."/';
c46c807b 611". $js_id .".DrupalId = '". $js_id ."';
8b081e6c 612". $js_id .".Config['PluginsPath'] = '". $module_full_path ."/plugins/';
ac9e6b9f 613". $js_id .".Config['CustomConfigurationsPath'] = \"". $fckeditor_config_path ."\";
8de1e54a 614". $js_id .".Config['TextareaID'] = \"". $element['#id'] ."\";";
0c87a920
WW
615
616 //if ($conf['appearance_conf'] == 'f') {
7254e6f4 617 $js .= "\n". $js_id .".ToolbarSet = \"". $toolbar ."\";
8de1e54a
WW
618". $js_id .".Config['SkinPath'] = ". $js_id .".BasePath + \"editor/skins/". $conf['skin'] ."/\";
619". $js_id .".Config['DefaultLanguage'] = \"". $conf['lang'] ."\";
620". $js_id .".Config['AutoDetectLanguage'] = ". ($conf['auto_lang']=="t"?"true":"false") .";
621". $js_id .".Height = \"". $height ."\";
622". $js_id .".Config['ToolbarStartExpanded'] = ". ($conf['expand']=="t"?"true":"false") .";
623". $js_id .".Width = \"". $width ."\";\n";
0c87a920
WW
624 //}
625 //if ($conf['output_conf'] == 'f') {
7254e6f4 626 $js .= "\n". $js_id .".Config['EnterMode'] = '". $conf['enter_mode'] ."';
8de1e54a
WW
627". $js_id .".Config['ShiftEnterMode'] = \"". $conf['shift_enter_mode'] ."\";
628". $js_id .".Config['FontFormats'] = \"". str_replace(",", ";", $conf['font_format']) ."\";
629". $js_id .".Config['FormatSource'] = ". ($conf['format_source']=="t"?"true":"false") .";
630". $js_id .".Config['FormatOutput'] = ". ($conf['format_output']=="t"?"true":"false") .";\n";
0c87a920 631 //}
af8e9eeb 632
05abb967
WW
633 if (defined('LANGUAGE_RTL') && $language->direction == LANGUAGE_RTL) {
634 $js .= $js_id .".Config['ContentLangDirection'] = 'rtl';\n";
635 }
636
af03ba76 637 if (function_exists('img_assist_perm')) { //#275158
7254e6f4 638 drupal_add_js("var fckImgAssistPath = '". base_path() . drupal_get_path('module', 'img_assist') ."';", 'inline');
af03ba76 639 }
e44c2389 640 // add code for filebrowser for users that have access
0c87a920 641 if (user_access('allow fckeditor file uploads')==1) {
c46c807b 642 $filebrowser = !empty($conf['filebrowser']) ? $conf['filebrowser'] : 'none';
6f7c3903
JS
643 if ($filebrowser == 'imce' && !module_exists('imce')) {
644 $filebrowser = 'none';
0c87a920 645 }
12ac377f
WW
646 if ($filebrowser == 'ib' && !module_exists('imagebrowser')) {
647 $filebrowser = 'none';
648 }
43e129e1
WW
649 if ($filebrowser == 'webfm' && !module_exists('webfm_popup')) {
650 $filebrowser = 'none';
651 }
c46c807b 652 $quickupload = (!empty($conf['quickupload']) && $conf['quickupload'] == 't');
af8e9eeb 653
6f7c3903
JS
654 // load variables used by both quick upload and filebrowser
655 // and assure that the $_SESSION variables are loaded
656 if ($quickupload || $filebrowser == 'builtin') {
29d8625e
WW
657 if (file_exists($editor_local_path ."/editor/filemanager/connectors/php/connector.php")) {
658 $connector_path = $editor_path ."/editor/filemanager/connectors/php/connector.php" ;
659 }
f60bb09c 660 elseif (file_exists($editor_local_path ."/editor/filemanager/upload/php/connector.php")) {
29d8625e
WW
661 $connector_path = $editor_path ."/editor/filemanager/upload/php/connector.php";
662 }
663
664 if (file_exists($editor_local_path ."/editor/filemanager/connectors/php/upload.php")) {
665 $upload_path = $editor_path ."/editor/filemanager/connectors/php/upload.php" ;
666 }
f60bb09c 667 elseif (file_exists($editor_local_path ."/editor/filemanager/upload/php/upload.php")) {
29d8625e
WW
668 $upload_path = $editor_path ."/editor/filemanager/upload/php/upload.php";
669 }
670
64e4e195
WW
671 if (!empty($profile->settings['UserFilesPath'])) $_SESSION['FCKeditor']['UserFilesPath'] = strtr($profile->settings['UserFilesPath'], array("%f" => file_directory_path(), "%u" => $user->uid, "%b" => $host, "%n" => $user->name));
672 if (!empty($profile->settings['UserFilesAbsolutePath'])) $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = strtr($profile->settings['UserFilesAbsolutePath'], array("%f" => file_directory_path(), "%u" => $user->uid, "%b" => base_path(), "%d" => $_SERVER['DOCUMENT_ROOT'], "%n" => $user->name));
45352a83 673 if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE) {
6484321d
JS
674 $private_dir = isset($global_profile->settings['private_dir']) ? trim($global_profile->settings['private_dir'], '\/') : '';
675 if (!empty($private_dir)) {
676 $private_dir = strtr($private_dir, array('%u' => $user->uid));
b94b689f
WW
677 $_SESSION['FCKeditor']['UserFilesPath'] = url('system/files') .'/'. $private_dir .'/';
678 $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = realpath(file_directory_path()) . DIRECTORY_SEPARATOR . $private_dir . DIRECTORY_SEPARATOR;
679 }
680 else {
681 $_SESSION['FCKeditor']['UserFilesPath'] = url('system/files') .'/';
682 $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = realpath(file_directory_path()) . DIRECTORY_SEPARATOR;
683 }
45352a83 684 }
0c87a920 685 }
af8e9eeb 686
6f7c3903 687 if ($quickupload) {
7254e6f4
WW
688 $js .= $js_id .".Config['LinkUpload'] = true;\n";
689 $js .= $js_id .".Config['ImageUpload'] = true;\n";
690 $js .= $js_id .".Config['FlashUpload'] = true;\n";
691 $js .= $js_id .".Config['LinkUploadURL'] = '". $upload_path ."';\n";
692 $js .= $js_id .".Config['ImageUploadURL'] = '". $upload_path ."?Type=Image';\n";
693 $js .= $js_id .".Config['FlashUploadURL'] = '". $upload_path ."?Type=Flash';\n";
075c1a2d
JS
694 }
695 else {
7254e6f4
WW
696 $js .= $js_id .".Config['LinkUpload'] = false;\n";
697 $js .= $js_id .".Config['ImageUpload'] = false;\n";
698 $js .= $js_id .".Config['FlashUpload'] = false;\n";
6f7c3903 699 }
af8e9eeb 700
075c1a2d 701 switch ($filebrowser) {
6f7c3903 702 case 'imce':
7254e6f4
WW
703 $js .= $js_id .".Config['LinkBrowser']= true;\n";
704 $js .= $js_id .".Config['ImageBrowser']= true;\n";
705 $js .= $js_id .".Config['FlashBrowser']= true;\n";
dc0840ab 706 $js .= $js_id .".Config['LinkBrowserURL']= '". $host ."index.php?q=imce&app=FCKEditor|url@txtLnkUrl,txtUrl';\n";
2b01c11b
WW
707 $js .= $js_id .".Config['ImageBrowserURL']= '". $host ."index.php?q=imce&app=FCKEditor|url@txtUrl|width@txtWidth|height@txtHeight';\n";
708 $js .= $js_id .".Config['FlashBrowserURL']= '". $host ."index.php?q=imce&app=FCKEditor|url@txtUrl';\n";
6f7c3903 709 break;
201b993d 710
43e129e1
WW
711 case 'webfm':
712 $js .= $js_id .".Config['LinkBrowser']= true;\n";
713 $js .= $js_id .".Config['ImageBrowser']= true;\n";
714 $js .= $js_id .".Config['FlashBrowser']= true;\n";
715 $js .= $js_id .".Config['ImageDlgHideLink']= true;\n";
716 $js .= $js_id .".Config['LinkBrowserURL']= '". $host ."index.php?q=webfm_popup&url=txtUrl';\n";
717 $js .= $js_id .".Config['ImageBrowserURL']= '". $host ."index.php?q=webfm_popup&url=txtUrl';\n";
718 $js .= $js_id .".Config['FlashBrowserURL']= '". $host ."index.php?q=webfm_popup&url=txtUrl';\n";
719 break;
720
6f7c3903 721 case 'builtin':
7254e6f4
WW
722 $js .= $js_id .".Config['LinkBrowser'] = true;\n";
723 $js .= $js_id .".Config['ImageBrowser'] = true;\n";
724 $js .= $js_id .".Config['FlashBrowser'] = true;\n";
725 $js .= $js_id .".Config['LinkBrowserURL'] = '". $editor_path ."/editor/filemanager/browser/default/browser.html?Connector=". $connector_path ."&ServerPath=". $files_path ."';\n";
726 $js .= $js_id .".Config['ImageBrowserURL'] = '". $editor_path ."/editor/filemanager/browser/default/browser.html?Type=Image&Connector=". $connector_path ."&ServerPath=". $files_path ."';\n";
727 $js .= $js_id .".Config['FlashBrowserURL'] = '". $editor_path ."/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=". $connector_path ."&ServerPath=". $files_path ."';\n";
6f7c3903 728 break;
201b993d 729
12ac377f
WW
730 case 'ib':
731 $js .= $js_id .".Config['ImageBrowser']= true;\n";
732 $js .= $js_id .".Config['LinkBrowser']= true;\n";
733 $js .= $js_id .".Config['FlashBrowser']= false;\n";
43e129e1
WW
734 $js .= $js_id .".Config['ImageBrowserURL']= '". $host ."index.php?q=imagebrowser/view/browser&app=FCKEditor';\n";
735 $js .= $js_id .".Config['LinkBrowserURL']= '". $host ."index.php?q=imagebrowser/view/browser&app=FCKEditor';\n";
12ac377f
WW
736 $js .= $js_id .".Config['ImageBrowserWindowWidth']= '680';";
737 $js .= $js_id .".Config['ImageBrowserWindowHeight'] = '439';";
738 $js .= $js_id .".Config['LinkBrowserWindowWidth']= '680';";
739 $js .= $js_id .".Config['LinkBrowserWindowHeight'] = '439';";
740 break;
741
6f7c3903
JS
742 default:
743 case 'none':
7254e6f4
WW
744 $js .= $js_id .".Config['LinkBrowser'] = false;\n";
745 $js .= $js_id .".Config['ImageBrowser'] = false;\n";
746 $js .= $js_id .".Config['FlashBrowser'] = false;\n";
6f7c3903
JS
747 break;
748 }
0c87a920
WW
749 }
750 else {
7254e6f4
WW
751 $js .= $js_id .".Config['LinkBrowser'] = false;\n";
752 $js .= $js_id .".Config['ImageBrowser'] = false;\n";
753 $js .= $js_id .".Config['FlashBrowser'] = false;\n";
754 $js .= $js_id .".Config['LinkUpload'] = false;\n";
755 $js .= $js_id .".Config['ImageUpload'] = false;\n";
756 $js .= $js_id .".Config['FlashUpload'] = false;\n";
8de1e54a 757 }
af8e9eeb 758
e9a59651 759 if (!empty($conf['js_conf'])) {
8de1e54a
WW
760 $lines = preg_split("/[\n\r]+/", $conf['js_conf']);
761 foreach ($lines as $l)
762 if ($l && strlen($l) > 5) {
763 $eqpos = strpos($l, "=");
075c1a2d 764 if (FALSE !== $eqpos) {
8de1e54a 765 $option = str_replace("FCKConfig.", "", substr($l, 0, $eqpos));
7254e6f4 766 $js .= "\n". $js_id .".Config['". trim($option) ."'] =". substr($l, $eqpos + 1);
8de1e54a
WW
767 }
768 }
92b2e6cf 769 }
e44c2389 770
0c87a920 771 // add custom xml stylesheet if it exists
e9a59651 772 if (!empty($conf['css_style']) && $conf['css_style'] == 'theme') {
746b1a35
WW
773 if (file_exists($themepath .'fckstyles.xml')) {
774 $styles_xml_path = $host . $themepath .'fckstyles.xml';
7254e6f4 775 $js .= $js_id .".Config['StylesXmlPath'] = \"". $styles_xml_path ."\";\n";
8de1e54a
WW
776 }
777 }
e9a59651 778 else if (!empty($conf['css_style']) && $conf['css_style'] == 'self') {
0ee41c0b 779 $conf['styles_path'] = str_replace("%h%t", "%t", $conf['styles_path']);
7254e6f4 780 $js .= $js_id .".Config['StylesXmlPath'] = \"". str_replace(array('%h', '%t', '%m'), array($host, $host . $themepath, $module_drupal_path), $conf['styles_path']) ."\";\n";
0c87a920 781 }
0c87a920
WW
782 // add custom stylesheet if configured
783 // lets hope it exists but we'll leave that to the site admin
23809d98
JS
784 $cssfiles = array($module_full_path .'/fckeditor.css');
785 switch ($conf['css_mode']) {
786 case 'theme':
021b9f79
WW
787 global $language, $theme, $theme_info, $base_theme_info;
788
789 $style_css = $themepath .'style.css';
790 if (!empty($theme_info->stylesheets)) {
cfc7bb33 791 $css_files = array();
021b9f79 792 $editorcss = "\"";
19e92d68 793 foreach ($base_theme_info as $base) { // Grab stylesheets from base theme
cfc7bb33
WW
794 foreach ($base->stylesheets as $type => $stylesheets) {
795 if ($type != "print") {
796 foreach ($stylesheets as $name => $path) {
19e92d68
WW
797 if (file_exists($path)) {
798 $css_files[$name] = $host . $path;
799 }
021b9f79
WW
800 }
801 }
802 }
803 }
19e92d68 804 if (!empty($theme_info->stylesheets)) { // Grab stylesheets from current theme
cfc7bb33
WW
805 foreach ($theme_info->stylesheets as $type => $stylesheets) {
806 if ($type != "print") {
807 foreach ($stylesheets as $name => $path) {
19e92d68
WW
808 if (file_exists($path)) {
809 $css_files[$name] = $host . $path;
810 }
400f8f63
WW
811 else if (!empty($css_files[$name])) {
812 unset($css_files[$name]);
813 }
cfc7bb33
WW
814 }
815 }
021b9f79
WW
816 }
817 }
cfc7bb33
WW
818 if (!empty($css_files)) {
819 $editorcss .= implode(",", $css_files) .",";
021b9f79
WW
820 }
821 // Grab stylesheets from color module
822 $color_paths = variable_get('color_'. $theme .'_stylesheets', array());
823 if (defined('LANGUAGE_RTL') && $language->direction == LANGUAGE_RTL) {
824 if (!empty($color_paths[1])) {
825 $editorcss .= $host . $color_paths[1] .",";
826 }
827 }
400f8f63
WW
828 else if (!empty($color_paths[0])) {
829 $editorcss .= $host . $color_paths[0] .",";
021b9f79
WW
830 }
831 $editorcss .= $module_full_path ."/fckeditor.css\";\n";
832 $js .= $js_id .".Config['EditorAreaCSS'] = ". $editorcss;
69bd70a8 833 }
021b9f79
WW
834 else if (file_exists($style_css)) {
835 $js .= $js_id .".Config['EditorAreaCSS'] = \"". $host . $style_css .",". $module_full_path ."/fckeditor.css\";";
23809d98 836 }
021b9f79
WW
837 else {
838 $js .= $js_id .".Config['EditorAreaCSS'] = \"". $module_full_path ."/fckeditor.css\";";
23809d98
JS
839 }
840 break;
201b993d 841
23809d98
JS
842 case 'self':
843 $conf['css_path'] = str_replace("%h%t", "%t", $conf['css_path']);
844 $cssfiles[] = str_replace(array('%h', '%t'), array($host, $host . $themepath), $conf['css_path']);
7254e6f4 845 $js .= $js_id .".Config['EditorAreaCSS'] = '". implode(',', $cssfiles) ."';\n";
6de0735a 846 break;
201b993d 847
6de0735a 848 case 'none':
7254e6f4 849 $js .= $js_id .".Config['EditorAreaCSS'] = ". $js_id .".BasePath + 'editor/css/fck_editorarea.css,' + '". implode(',', $cssfiles) ."';\n";
23809d98 850 break;
0c87a920 851 }
a9579640
WW
852 if ($num == 2) {
853 $js .= 'var fckInstances = {};';
854 }
7254e6f4 855 $js .= 'fckInstances[\''. $textarea_id .'\'] = '. $js_id .";\n";
af8e9eeb 856
ec1149f8 857 drupal_add_js('var '. $js_id .';if (Drupal.jsEnabled) {'. $js .'}', 'inline');
f3d88ca0 858
ef80606d 859 if ($conf['popup'] == 't') {
42225b39 860 $element['#suffix'] .= ' <span class="fckeditor_popuplink">(<a href="#" onclick="FCKeditor_OpenPopup(\''. $module_full_path .'/fckeditor.popup.html\', \''. $js_id .'\', \''. $element['#id'] .'\'); return false;">'. t('Open rich text editor') ."</a>)</span>";
0c87a920 861 }
f3d88ca0 862 }
9b429add 863
0c87a920 864 // display the field id for administrators
44173850 865 if (user_access('administer fckeditor') && (!isset($global_conf['show_fieldnamehint']) || $global_conf['show_fieldnamehint'] == 't')) {
1b120ffb 866 module_load_include('admin.inc', 'fckeditor');
af8e9eeb 867
42225b39 868 $element['#suffix'] .= '<div class="textarea-identifier description">'. t('The ID for <a href="!excluding">excluding or including</a> this element is %fieldname.', array('!excluding' => url('admin/settings/fckeditor'), '%fieldname' => fckeditor_rule_to_string(fckeditor_rule_create(fckeditor_get_nodetype($_GET['q']), $_GET['q'], $element['#id'])))) .'</div>';
0c87a920
WW
869 }
870
f3d88ca0 871 return $element;
04b827fa
DS
872}
873
23824481 874/**
8de1e54a
WW
875 * sort roles according to precedence settings. previously sorted roles are followed by latest added roles.
876 */
877function fckeditor_sorted_roles() {
878 static $order;
879 if (isset($order)) {
880 return $order;
881 }
882 $order = array();
883 $roles = user_roles(0, 'access fckeditor');
884
885 $result = db_query("SELECT settings FROM {fckeditor_settings} WHERE name='FCKeditor Global Profile'");
886 $data = db_fetch_object($result);
d7fbc905 887 if (!empty($data->settings)) {
8de1e54a
WW
888 $settings = unserialize($data->settings);
889 if (isset($settings['rank']) && !empty($settings['rank']))
890 foreach ($settings['rank'] as $rid) {
891 if (isset($roles[$rid])) {
892 $order[$rid] = $roles[$rid];
893 unset($roles[$rid]);
894 }
895 }
896 }
897 krsort($roles);//sort the remaining unsorted roles by id, descending.
898 $order += $roles;
899 return $order;
900}
901
0c87a920 902/**
e44c2389 903 * Test if client can render the FCKeditor
0c87a920
WW
904 * Use built-in test method in fckeditor.php
905 * If fckeditor.php is not found, return false (probably in such case fckeditor is not installed correctly)
e44c2389 906 *
907 * @return
908 * TRUE if the browser is reasonably capable
04b827fa
DS
909 */
910function fckeditor_is_compatible_client() {
29d8625e 911 $editor_local_path = fckeditor_path(TRUE);
d6fbb175
WW
912
913 $fckeditor_main_file = $editor_local_path .'/fckeditor.php';
914 if (!function_exists('version_compare') || version_compare(phpversion(), '5', '<')) {
915 $fckeditor_target_file = $editor_local_path .'/fckeditor_php4.php';
916 }
917 else {
918 $fckeditor_target_file = $editor_local_path .'/fckeditor_php5.php';
919 }
920
921 if (file_exists($fckeditor_target_file)) {
922 include_once $fckeditor_target_file;
923 //FCKeditor 2.6.1+
0c87a920
WW
924 if (function_exists('FCKeditor_IsCompatibleBrowser')) {
925 return FCKeditor_IsCompatibleBrowser();
926 }
81db85ca 927 else if (class_exists('FCKeditor')) {
d6fbb175
WW
928 //FCKeditor 2.5.1 up to 2.6 with definition of FCKeditor_IsCompatibleBrowser() in fckeditor.php
929 if (filesize($fckeditor_main_file) > 1500) {
930 include_once $fckeditor_main_file;
931 }
932 //FCKeditor 2.5.0 and earlier
1b120ffb 933 $fck = new FCKeditor('fake');
0c87a920
WW
934 return $fck->IsCompatible();
935 }
936 }
937
075c1a2d 938 return FALSE;
0c87a920
WW
939}
940
29d8625e 941/**
6dab511d 942 * Get an array of input formats that include HTML filter
5d2db5be
WW
943 *
944 * @return array
945 */
946function fckeditor_html_filter_formats() {
947 static $return;
da1cf0d0 948
5d2db5be
WW
949 if (isset($return)) {
950 return $return;
951 }
da1cf0d0 952
5d2db5be
WW
953 $return = array();
954 $r = db_query("SELECT format FROM {filters} WHERE module = 'filter' AND delta = 0");
955 while ($row = db_fetch_object($r)) {
956 $return[] = $row->format;
957 }
da1cf0d0 958
5d2db5be
WW
959 return $return;
960}
961
962/**
29d8625e
WW
963 * Read FCKeditor path from Global profile
964 *
965 * @return
966 * path to FCKeditor folder
967 */
29d8625e
WW
968function fckeditor_path($local = FALSE) {
969 static $fck_path;
970 static $fck_local_path;
971
972 if (!$fck_path) {
973 $mod_path = drupal_get_path('module', 'fckeditor');
974 $global_profile = fckeditor_profile_load('FCKeditor Global Profile');
975
976 //default: path to fckeditor subdirectory in the fckeditor module directory (starting from the document root)
977 //e.g. for http://example.com/drupal it will be /drupal/sites/all/modules/fckeditor/fckeditor
f60bb09c 978 $fck_path = base_path() . $mod_path .'/fckeditor';
af8e9eeb 979
29d8625e
WW
980 //default: path to fckeditor subdirectory in the fckeditor module directory (relative to index.php)
981 //e.g.: sites/all/modules/fckeditor/fckeditor
f60bb09c 982 $fck_local_path = $mod_path .'/fckeditor';
29d8625e
WW
983
984 if ($global_profile) {
985 $gs = $global_profile->settings;
af8e9eeb 986
f60bb09c 987 if (isset($gs['fckeditor_path'])) {
29d8625e
WW
988 $tmp_path = $gs['fckeditor_path'];
989 $tmp_path = strtr($tmp_path, array("%b" => base_path(), "%m" => base_path() . $mod_path));
990 $tmp_path = str_replace('\\', '/', $tmp_path);
991 $tmp_path = str_replace('//', '/', $tmp_path);
992 $tmp_path = rtrim($tmp_path, ' \/');
f60bb09c 993 if (substr($tmp_path, 0, 1) != '/') {
29d8625e
WW
994 $tmp_path = '/'. $tmp_path; //starts with '/'
995 }
996 $fck_path = $tmp_path;
af8e9eeb 997
29d8625e
WW
998 if (empty($gs['fckeditor_local_path'])) {
999 //fortunately wildcards are used, we can easily get the right server path
1000 if (false !== strpos($gs['fckeditor_path'], "%m")) {
1001 $gs['fckeditor_local_path'] = strtr($gs['fckeditor_path'], array("%m" => $mod_path));
1002 }
1003 if (false !== strpos($gs['fckeditor_path'], "%b")) {
1004 $gs['fckeditor_local_path'] = strtr($gs['fckeditor_path'], array("%b" => "."));
1005 }
1006 }
1007 }
1008
af8e9eeb 1009 //fckeditor_path is defined, but wildcards are not used, we need to try to find out where is
29d8625e
WW
1010 //the document root located and append fckeditor_path to it.
1011 if (!empty($gs['fckeditor_local_path'])) {
1012 $fck_local_path = $gs['fckeditor_local_path'];
1013 }
1014 else if (!empty($gs['fckeditor_path'])) {
1015 module_load_include('lib.inc', 'fckeditor');
1016 $local_path = fckeditor_resolve_url( $gs['fckeditor_path'] ."/" );
1017 if (FALSE !== $local_path) {
1018 $fck_local_path = $local_path;
1019 }
1020 }
af8e9eeb 1021 }
29d8625e
WW
1022 }
1023 if ($local) {
1024 return $fck_local_path;
1025 }
1026 else {
1027 return $fck_path;
1028 }
1029}
1030
8de1e54a 1031function fckeditor_user_get_setting($user, $profile, $setting) {
0c87a920 1032 $default = array(
201b993d 1033 'default' => 't',
1034 'show_toggle' => 't',
1035 'popup' => 'f',
1036 'skin' => 'default',
1037 'toolbar' => 'default',
1038 'expand' => 't',
1039 'width' => '100%',
1040 'lang' => 'en',
1041 'auto_lang' => 't',
0c87a920 1042 );
0c87a920 1043
a38b3152
JS
1044 if ($profile->settings['allow_user_conf']) {
1045 $status = isset($user->{'fckeditor_'. $setting}) ? $user->{'fckeditor_'. $setting} : (isset($profile->settings[$setting]) ? $profile->settings[$setting] : $default[$setting]);
04b827fa 1046 }
0c87a920 1047 else {
a38b3152 1048 $status = isset($profile->settings[$setting]) ? $profile->settings[$setting] : $default[$setting];
04b827fa 1049 }
0c87a920
WW
1050
1051 return $status;
1052}
1053
44173850
WW
1054function fckeditor_user_get_profile($user, $element_id = NULL) {
1055 $rids = array();
8bdf4d22
WW
1056
1057 // Since fckeditor_profile_load() makes a db hit, only call it when we're pretty sure
1058 // we're gonna render fckeditor.
27c847ec
JS
1059 $sorted_roles = fckeditor_sorted_roles();
1060 foreach (array_keys($sorted_roles) as $rid) {
1061 if (isset($user->roles[$rid])) {
1062 $rids[] = $rid;
8bdf4d22 1063 }
44173850 1064 }
8bdf4d22 1065
44173850 1066 if ($user->uid == 1 && !sizeof($rids)) {
0d50e82a
WW
1067 $r = db_fetch_object(db_query_range("SELECT r.rid FROM {fckeditor_role} r ORDER BY r.rid DESC", 1));
1068 $rids[] = $r->rid;
44173850
WW
1069 }
1070
1071 $profile_names = array();
1072 if (sizeof($rids)) {
1073 $result = db_query("SELECT r.rid, s.name FROM {fckeditor_settings} s INNER JOIN {fckeditor_role} r ON r.name = s.name WHERE r.rid IN (". implode(",", $rids) .")");
27c847ec 1074 while (($row = db_fetch_array($result))) {
44173850
WW
1075 if (!isset($profile_names[$row['rid']])) {
1076 $profile_names[$row['rid']] = array();
1077 }
1078 array_push($profile_names[$row['rid']], $row['name']);
8bdf4d22 1079 }
0c87a920 1080 }
d3cf16a0 1081
44173850
WW
1082 foreach ($rids as $rid) {
1083 if (!empty($profile_names[$rid])) {
1084 foreach ($profile_names[$rid] as $profile_name) {
1085 $profile = fckeditor_profile_load($profile_name);
1086
1087 $conf = $profile->settings;
1088 $enabled = fckeditor_is_enabled(empty($conf['excl_mode']) ? '0' : $conf['excl_mode'], empty($conf['excl_regex']) ? '' : $conf['excl_regex'], $element_id, $_GET['q']);
1089
1090 if ($enabled) {
1091 return $profile;
1092 }
1093 }
1094 }
0c87a920 1095 }
d3cf16a0 1096
075c1a2d 1097 return FALSE;
29d8625e 1098}
ed7a9537 1099
0a856e81 1100function fckeditor_get_nodetype($get_q) {
ed7a9537 1101 static $nodetype;
af8e9eeb 1102
ed7a9537
JS
1103 if (!isset($nodetype)) {
1104 $menuitem = menu_get_item();
1105 $nodetype = '*';
1106 if (!empty($menuitem['page_arguments'])) {
1107 foreach ($menuitem['page_arguments'] as $item) {
1108 if (!empty($item->nid) && !empty($item->type)) {
1109 // not 100% valid check if $item is a node
1110 $nodetype = $item->type;
1111 break;
1112 }
1113 }
1114 }
0a856e81
WW
1115
1116 if ($nodetype == '*') {
1117 $get_q = explode("/", $get_q, 3);
1118 if ($get_q[0] == "node" && $get_q[1] == "add" && !empty($get_q[2])) {
1119 $nodetype = $get_q[2];
1120 }
1121 }
ed7a9537 1122 }
af8e9eeb 1123
ed7a9537 1124 return $nodetype;
a892f30b 1125}