4 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
5 * Copyright (C) 2003-2008 Frederico Caldeira Knabben
9 * Licensed under the terms of any of the following licenses at your
12 * - GNU General Public License Version 2 or later (the "GPL")
13 * http://www.gnu.org/licenses/gpl.html
15 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
16 * http://www.gnu.org/licenses/lgpl.html
18 * - Mozilla Public License Version 1.1 or later (the "MPL")
19 * http://www.mozilla.org/MPL/MPL-1.1.html
24 * FCKeditor Module for Drupal 6.x
26 * This module allows Drupal to replace textarea fields with FCKeditor.
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.
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
37 define('FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME', 'DrupalBasic') ;
40 * Implementation of hook_help
42 function fckeditor_help($path, $arg) {
44 case
'admin/settings/help#description':
45 $output = t("Enables the usage of FCKeditor (WYSIWYG editor) instead of plain text fields.");
47 case
'admin/settings/fckeditor':
48 if (!empty($arg[3]) && in_array($arg[3], array("addg", "editg"))) {
49 $output = t("<p>The Global Profile allows you to define settings that are common for all profiles. Values defined in other profiles will be appended to the global configuration. This way you can avoid repeating some of the settings that are usually the same in each profile.</p>");
52 else if (!empty($arg[3]) && in_array($arg[3], array("add", "edit"))) {
53 $output = t("<p>Note: FCKeditor is highly configurable. The most commonly used features are listed below. If you want to take a look at all available settings, open <code>!fckconfig</code> and then customize <code>!fckeditor_config</code> to your needs. This is also the only way to define new toolbar sets. It is advised to not edit <code>fckconfig.js</code> because you may overwrite it accidentally when you update the editor.</p>", array('!fckconfig' => drupal_get_path('module', 'fckeditor') .
"/fckeditor/fckconfig.js", '!fckeditor_config' => drupal_get_path('module', 'fckeditor') .
"/fckeditor.config.js"));
56 else if (!empty($arg[3]) && in_array($arg[3], array("delete", "deleteg"))) {
59 $output = t("<p>The FCKeditor module allows Drupal to replace textarea fields with a rich text or <acronym title=\"What You See Is What You Get\">WYSIWYG</acronym> editor. This editor brings many of the powerful functionalities of known desktop editors like Word to the web. It's relatively lightweight and doesn't require any kind of installation on the client computer.</p><p>More information about the editor is located at the !fckeditorlink. A small user guide is located at !userguidelink.</p>",
61 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net'),
62 '!userguidelink' => l(t('FCKeditor userguide'), 'http://docs.fckeditor.net/FCKeditor/Users_Guide'))
64 $output .
= t('<p>Profiles can be defined based on user roles. A FCKeditor profile can define which pages receive this FCKeditor capability, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor functions. It is possible also to define the Global Profile that will hold values that will be appended to all other profiles.</p><p>Lastly, only users with the <code>!access1</code> !permission will be able to use FCKeditor. </p>', array('!permission' => l(t('permission'), 'admin/user/permissions'), '!access1' => t('access fckeditor')));
66 case
'admin/help#fckeditor':
67 $output = t("<p>The FCKeditor module allows Drupal to replace textarea fields with a rich text or <acronym title=\"What You See Is What You Get\">WYSIWYG</acronym> editor. This editor brings many of the powerful functionalities of known desktop editors like Word to the web. It's relatively lightweight and doesn't require any kind of installation on the client computer.</p><p>More information is located at the !fckeditorlink. A small user guide is located at !userguidelink.</p>",
69 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net'),
70 '!userguidelink' => l(t('FCKeditor userguide'), 'http://docs.fckeditor.net/FCKeditor/Users_Guide'))
72 $output .
= t('<h3>Configuration</h3><ol><li>Go to the !fckeditorlink and download the latest version of FCKeditor. Then uncompress the contents of the "fckeditor" directory of the downloaded file to %fckeditordir.</li><li>Enable the module as usual from Drupal\'s admin pages.</li><li>Grant permissions for use of FCKeditor in <code>!path2</code><br/>Note: to enable the file browser, read also the <i>How to enable the file browser</i> section.</li><li>Under <code>!path1</code>, adjust the fckeditor profiles. In each profile you can choose which textareas will be replaced by FCKeditor, select default toolbar and configure some more advanced settings.</li><li>For the Rich Text Editing to work you also need to configure your !filterlink for the users that may access Rich Text Editing. Either grant those users Full HTML access or use the following: <br/><code>!filter</code>. </li><li>To have a better control over line breaks, you may disable <code>Line break converter</code> in the chosen filter (recommended).</li><li>Modify the fckeditor.config.js file to custom your needs (optional).<br />You may copy the needed configuration lines from the default FCKeditor configuration settings (!fckconfig), the lines in fckeditor.config.js will override most settings.</li></ol>',
74 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net/download'),
75 '%fckeditordir' => base_path() .
drupal_get_path('module', 'fckeditor') .
'/fckeditor/',
76 '!path1' => l(t('Administer > Site configuration > FCKeditor'), 'admin/settings/fckeditor'),
77 '!path2' => l(t('Administer > User Management > Permissions'), 'admin/user/permissions'),
78 '!filter' => htmlentities('<a> <p> <span> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area>
79 <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <tr> <td> <em>
80 <b> <u> <i> <strong> <font> <del> <ins> <sub> <sup> <quote> <blockquote>
81 <pre> <address> <code> <cite> <embed> <object> <param> <strike> <caption>'),
82 '!fckconfig' => base_path() .
drupal_get_path('module', 'fckeditor') .
'/fckeditor/fckconfig.js',
83 '!moduledir' => base_path() .
drupal_get_path('module', 'fckeditor') .
'/fckeditor',
84 '!filterlink' => l(t('filters'), 'admin/settings/filters'))
86 $output .
= t('<h3>Installation troubleshooting</h3><p>If your FCKeditor does not show you must check if all files are extracted correctly. The directory %fckeditordir should have the following files: <code>fckeditor.js, fckconfig.js, fckstyles.xml, fcktemplates.xml</code> and a directory named <code>editor</code>.</p>',
88 '%fckeditordir' => base_path() .
drupal_get_path('module', 'fckeditor') .
'/fckeditor/')
90 $output .
= t('The correct directory structure is as follows: <blockquote><pre>!structure</pre></blockquote>', array(
91 '!structure' => "modules\n fckeditor\n <em>fckeditor.module</em>\n fckeditor\n _samples\n editor\n <em>COPY_HERE.txt</em>\n <em>fckconfig.js</em>\n ..."
93 $output .
= t("<h3>Plugins: Teaser break and Pagebreak</h3><p>By default, FCKeditor module comes with two plugins that can handle teaser break (<!--break-->) and pagebreak (<!--pagebreak-->). You can enable any (or even both) of them.<ol><li>Open <code>!fckeditor.config.js</code> and uncomment these three lines: <pre>!code</pre></li><li>The second step is to add buttons to the toolbar (in the same file). The button names are: <code>DrupalBreak, DrupalPageBreak</code>. For example if you have a toolbar with an array of buttons defined as follows: <pre>!buttons1</pre> simply add those two buttons at the end of array: <pre>!buttons2</pre> (remember about single quotes).</li></ol></p>",
95 '!fckeditor.config.js' => base_path() .
drupal_get_path('module', 'fckeditor') .
'/fckeditor.config.js',
97 FCKConfig.PluginsPath = '../../plugins/' ;
98 FCKConfig.Plugins.Add( 'drupalbreak' ) ;
99 FCKConfig.Plugins.Add( 'drupalpagebreak' ) ;
101 '!buttons1' => "['Image','Flash','Table','Rule','SpecialChar']",
102 '!buttons2' => "['Image','Flash','Table','Rule','SpecialChar', 'DrupalBreak', 'DrupalPageBreak']",
104 $output .
= t('<h3>Uploading images and files</h3><p>There are three ways of uploading files: By using the built-in file browser, by using a module like !imce or using the core upload module.</p>',
106 '!imce' => l(t('IMCE'), 'http://drupal.org/project/imce')
109 // the rest is untranslated for the moment
110 $output .
= t("<h3>How to enable the file browser</h3><p>The editor gives the end user the flexibility to create a custom file browser that can be integrated on it. The included file browser allows users to view the content of a specific directory on the server and add new content to that directory (create folders and upload files).</p><p><ol><li>To enable file browsing you need to edit the connector configuration file in your fckeditor module directory, the file should be in:<blockquote><code>!config3</code> <br/> (FCKeditor 2.5+)<br/><br/> or <br/><br/><code>!config1</code><br/> and <br/><code>!config2</code> <br/> (FCKeditor 2.3.x - 2.4.x)</blockquote></p><p>In this file(s) you will need to enable the file browser by adding one line that includes file with the special authentication function for Drupal (<code>filemanager.config.php</code>). Add this code: <blockquote><code>!code1</code><br/> (FCKeditor 2.5+)</blockquote> or <blockquote><code>!code2</code> <br/> (FCKeditor 2.3.x - 2.4.x)</blockquote> straight below this line: <blockquote><code>!code3</code></blockquote> The config.php file also holds some other important settings, please take a look at it and adjust it to your needs (optional).</p></li>",
111 array('!config1' => base_path() .
drupal_get_path('module', 'fckeditor') .
"/fckeditor/editor/filemanager/browser/default/connectors/php/config.php",
112 '!config2' => base_path() .
drupal_get_path('module', 'fckeditor') .
"/fckeditor/editor/filemanager/upload/php/config.php",
113 '!config3' => base_path() .
drupal_get_path('module', 'fckeditor') .
"/fckeditor/editor/filemanager/connectors/php/config.php",
114 '!filesdir' => file_directory_path(),
115 '!code1' => 'require_once "../../../../../filemanager.config.php";', //2.5
116 '!code2' => 'require_once "'.
str_replace("\\", "\\\\", dirname(__FILE__
) . DIRECTORY_SEPARATOR .
'filemanager.config.php"'), //2.4
117 '!code3' => "\$Config['UserFilesAbsolutePath'] = '' ;",
120 $output .
= t("<li>As of Drupal 5.2, additional step is required: locate file named <code>settings.php</code> inside your drupal directory (usually <code>sites/default/settings.php</code>) and set <strong><code>$cookie_domain</code></strong> variable to the appropiate domain (remember to uncomment that line). If you not do this, FCKeditor will claim that file browser is disabled</li>");
121 $output .
= t('<li>Enabling file uploads is <strong>a security risk</strong>. That\'s why you have to grant a !link to enable the file browser to certain groups (assign the "!allowupload" permissions).</li>', array('!link' => l(t('separate permission'), 'admin/user/permissions'), "!allowupload" => t("allow fckeditor file uploads")));
122 $output .
= t('<li>Lastly, adjust the !fb for each !profile.</li></ol>', array('!fb' => t('File browser settings'), '!profile' => l(t('profile'), 'admin/settings/fckeditor')));
123 $output .
= t("<h3>Modules: Image Assist</h3><p>Image Assist can be integrated with FCKeditor. To do this, simply copy the <code>!iaf1</code> file to <code>!iaf2</code>.</p>", array("!iaf1" => drupal_get_path('module', 'fckeditor') .
"/img_assist_fckeditor.js", "!iaf2" => drupal_get_path('module', 'img_assist') .
"/img_assist_fckeditor.js"));
127 return !empty($output) ?
$output : "";
131 * Implementation of hook_perm
132 * Administer -> User management -> Permissions
134 function fckeditor_perm() {
135 return array('administer fckeditor', 'access fckeditor', 'allow fckeditor file uploads');
140 * Implementation of textarea
141 * Replace textarea with FCKeditor using callback function (fckeditor_process_textarea)
143 function fckeditor_elements() {
145 $type['textfield'] = array(
147 'fckeditor_process_input'
150 if (user_access('access fckeditor')) {
151 // only roles with permission get the fckeditor
152 if (fckeditor_is_compatible_client()) {
153 // it would be useless to dig deeper if we're not able or allowed to
154 $type['textarea'] = array(
156 'fckeditor_process_textarea'
165 * Allow more than 255 chars in Allowed HTML tags textfield
168 function fckeditor_process_input($element) {
169 if ($element['#id']=='edit-allowed-html-1') {
170 $element['#maxlength'] = max($element['#maxlength'], 1024);
176 * Add link to FCKeditor configuration in "Administer -> Site configuration" section
179 function fckeditor_menu() {
183 $items['fckeditor/xss'] = array(
184 'title' => 'XSS Filter',
185 'description' => 'XSS Filter.',
186 'page callback' => 'fckeditor_filter_xss',
187 'access arguments' => array('access fckeditor'),
188 'type' => MENU_CALLBACK
,
191 $items['admin/settings/fckeditor'] = array(
192 'title' => 'FCKeditor',
193 'description' => 'Configure the rich editor.',
194 'page callback' => 'fckeditor_admin',
195 'access arguments' => array('administer fckeditor'),
196 'type' => MENU_NORMAL_ITEM
,
203 * AJAX callback - XSS filter
205 function fckeditor_filter_xss() {
206 if (!isset($_POST['text']) || !is_string($_POST['text'])) {
210 $text = strtr($_POST['text'], array('<!--' => '__COMMENT__START__', '-->' => '__COMMENT__END__'));
211 preg_match_all("|</?([a-z][a-z0-9]*)(?:\b[^>]*)>|i", $text, $matches);
212 $tags = array_unique($matches[1]);
214 $secure_text = filter_xss($text, $tags);
215 $secure_text = strtr($secure_text, array('__COMMENT__START__' => '<!--', '__COMMENT__END__' => '-->'));
221 //Remove a profile from the database.
222 function fckeditor_profile_delete($name) {
223 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s'", $name);
224 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s'", $name);
228 * Profile validation.
230 function fckeditor_profile_validate($edit) {
233 //include mode and all other fields are empty, invalid
234 if ($edit['excl_mode'] == 1 && !$edit['excl_fields'] && !$edit['excl_paths']) {
235 $errors['excl_mode'] = t('Include mode selected, but no fields/paths given. Enter at least one path or field where FCKeditor should appear.');
238 if (!preg_match("/^\d+$/", trim($edit['min_rows']))) {
239 $errors['min_rows'] = t('Minimum rows must be a valid number');
242 if ($edit['default'] == 't' && $edit['popup'] == 't') {
243 $errors['popup'] = t('If FCKeditor is enabled by default, popup window must be disabled.');
246 if ($edit['show_toggle'] == 't' && $edit['popup'] == 't') {
247 $errors['popup'] = t('If toggle is enabled, popup window must be disabled.');
250 if (!$edit['name']) {
251 $errors['name'] = t('You must give a profile name.');
254 if (!preg_match("/^\d+%?$/", $edit['width'])) {
255 $errors['width'] = t('Enter valid width. Ex: 400 or 100%');
258 if (!empty($edit['css_path'])) {
259 if ($edit['css_mode'] != 'self') {
260 $errors['css_path'] = t('CSS path is not empty. Please set the "Editor CSS" option to "define css" mode.');
262 else if (false
!== strpos($edit['css_path'], '"')) {
263 $errors['css_path'] = t('Double quotes are not allowed in CSS path.');
265 else if (substr($edit['css_path'], 0, 1) == "'" && substr($edit['css_path'], -1) == "'") {
266 $errors['css_path'] = t('Enter valid path, do not surround it with quotes.');
270 if (!empty($edit['styles_path'])) {
271 if ($edit['css_style'] != 'self') {
272 $errors['styles_path'] = t('Path to predefined styles is not empty. Please set the "Predefined styles" option to "define path to fckstyles.xml" mode.');
274 else if (false
!== strpos($edit['styles_path'], '"')) {
275 $errors['styles_path'] = t('Double quotes are not allowed in path.');
277 else if (substr($edit['styles_path'], 0, 1) == "'" && substr($edit['styles_path'], -1) == "'") {
278 $errors['styles_path'] = t('Enter valid path, do not surround it with quotes.');
282 if (!empty($edit['font_format'])) {
283 if (!preg_match("/^((p|div|pre|address|h1|h2|h3|h4|h5|h6);)*(p|div|pre|address|h1|h2|h3|h4|h5|h6)$/", $edit['font_format'])) {
284 $errors['font_format'] = t('Enter valid, semicolon separated, list of HTML font formats (no semicolon at the end of list expected).');
289 $fields = preg_split("/[\s,]+/", strip_tags($edit['excl_fields']));
290 foreach ($fields as
$field) {
291 if ($field && !preg_match("/^[a-z]+(\-[[:alnum:]]+)+$/i", $field)) {
292 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
297 $fields = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_fields']));
298 foreach ($fields as
$field) {
299 if ($field && !preg_match("/^[a-z]+(\-[[:alnum:]]+)+$/i", $field)) {
300 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
306 $paths = preg_split("/[\s,]+/", strip_tags($edit['excl_paths']));
307 foreach ($paths as
$path) {
308 if ($path && !preg_match("|^[_a-z0-9-\*/]*$|i", $path)) {
309 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
314 $paths = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_paths']));
315 foreach ($paths as
$path) {
316 if ($path && !preg_match("|^[_a-z0-9-\*/]*$|i", $path)) {
317 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
322 if (variable_get('file_downloads', '') !== FILE_DOWNLOADS_PRIVATE
) {
323 if ($edit['UserFilesAbsolutePath'] && !$edit['UserFilesPath']) {
324 $errors['UserFilesPath'] = t("Path to uploaded files is required.");
326 if ($edit['UserFilesPath'] && !$edit['UserFilesAbsolutePath']) {
327 $errors['UserFilesPath'] = t("Absolute path to uploaded files is required.");
331 foreach ($errors as
$name => $message) {
332 form_set_error($name, $message);
335 return count($errors) == 0;
339 * Global profile validation.
341 function fckeditor_global_profile_validate($edit) {
344 //include mode and all other fields are empty, invalid
345 if ($edit['excl_mode'] == 1 && !$edit['excl_fields'] && !$edit['excl_paths']) {
346 $errors['excl_mode'] = t('Include mode selected, but no fields/paths given. Enter at least one path or field where FCKeditor should appear.');
350 $fields = preg_split("/[\s,]+/", strip_tags($edit['excl_fields']));
351 foreach ($fields as
$field) {
352 if ($field && !preg_match("/^[a-z]+(\-[[:alnum:]]+)+$/i", $field)) {
353 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
358 $fields = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_fields']));
359 foreach ($fields as
$field) {
360 if ($field && !preg_match("/^[a-z]+(\-[[:alnum:]]+)+$/i", $field)) {
361 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
367 $paths = preg_split("/[\s,]+/", strip_tags($edit['excl_paths']));
368 foreach ($paths as
$path) {
369 if ($path && !preg_match("|^[_a-z0-9-\*/]*$|i", $path)) {
370 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
375 $paths = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_paths']));
376 foreach ($paths as
$path) {
377 if ($path && !preg_match("|^[_a-z0-9-\*/]*$|i", $path)) {
378 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
383 foreach ($errors as
$name => $message) {
384 form_set_error($name, $message);
387 return count($errors) == 0;
391 * Controller for FCKeditor administrative settings.
393 function fckeditor_admin($arg = NULL
) {
395 $module_drupal_path = drupal_get_path('module', 'fckeditor');
396 $fckconfig_file = $module_drupal_path .
'/fckeditor/fckconfig.js';
397 if (!file_exists($fckconfig_file)) {
398 drupal_set_message(t('checking for %filename', array('%filename' => $fckconfig_file)));
400 t('The FCKeditor component is not installed correctly. Please go to the !fckeditorlink to download the latest version. After that you must extract the files to %modulepath and make sure that the directory %modulesubdir and the file %modulefile exist. Refer to the !readme for more information.',
402 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net/download'),
403 '!readme' => l('readme.txt', 'admin/help/fckeditor'),
404 '%modulepath' => base_path() .
$module_drupal_path .
'/fckeditor/',
405 '%modulesubdir' => base_path() .
$module_drupal_path .
'/fckeditor/editor',
406 '%modulefile' => base_path() .
$module_drupal_path .
'/fckeditor/fckeditor.js')),
412 $op = isset($_POST['op']) ?
$_POST['op'] : "";
414 $op = $arg && !$op ?
$arg : $op;
418 $output = fckeditor_profile_form($edit);
422 $output = fckeditor_global_profile_form($edit);
426 drupal_set_title(t('Edit FCKeditor profile'));
427 $output = fckeditor_profile_form(fckeditor_profile_load(urldecode(arg(4))));
431 drupal_set_title(t('Edit FCKeditor profile'));
432 $output = fckeditor_global_profile_form(fckeditor_profile_load("FCKeditor Global Profile"));
436 $output = fckeditor_ask_delete_confirmation(TRUE
);
440 $output = fckeditor_ask_delete_confirmation(FALSE
, urldecode(arg(4)));
443 case
'deleteconfirmed':
444 fckeditor_profile_delete(urldecode(arg(4)));
445 drupal_set_message(t('Deleted profile'));
446 drupal_goto('admin/settings/fckeditor');
449 case
'deletegconfirmed':
450 fckeditor_profile_delete("FCKeditor Global Profile");
451 drupal_set_message(t('Deleted Global profile'));
452 drupal_goto('admin/settings/fckeditor');
455 case
t('Create profile');
456 case
t('Update profile');
457 if (fckeditor_profile_validate($edit)) {
458 fckeditor_profile_save($edit);
459 !empty($edit['old_name']) ?
drupal_set_message(t('Your FCKeditor profile has been updated.')) : drupal_set_message(t('Your FCKeditor profile has been created.'));
460 drupal_goto('admin/settings/fckeditor');
463 $output = fckeditor_profile_form($edit);
467 case
t('Create global profile');
468 case
t('Update global profile');
469 if (fckeditor_global_profile_validate($edit)) {
470 $edit['name'] = 'FCKeditor Global Profile';
471 fckeditor_global_profile_save($edit);
472 drupal_set_message(t('FCKeditor global profile has been saved.'));
473 drupal_goto('admin/settings/fckeditor');
476 $output = fckeditor_global_profile_form($edit);
481 drupal_set_title(t('FCKeditor settings'));
482 //Check if FCKeditor is installed.
483 $fckeditor_loc = drupal_get_path('module', 'fckeditor') .
'/fckeditor/';
484 if (!is_dir($fckeditor_loc)) {
485 drupal_set_message(t('Could not find the FCKeditor engine installed at <strong>!fckeditor-directory</strong>. Please !download, uncompress it and copy the folder into !fckeditor-path.', array('!fckeditor-path' => drupal_get_path('module', 'fckeditor'), '!fckeditor-directory' => $fckeditor_loc, '!download' => l(t("download FCKeditor"), "http://www.fckeditor.net/download"))), 'error');
488 $access_fckeditor_roles = user_roles(FALSE
, 'access fckeditor');
489 if (!$access_fckeditor_roles) {
490 drupal_set_message(t('There is currently no role with the <strong>!access</strong> permission. Visit !acl administration section.',
491 array("!access" => t("access fckeditor"), "!acl" => l(t("Permissions"), "admin/user/permissions"))), "warning");
494 $result = db_query_range("SELECT name FROM {fckeditor_settings} WHERE name<>'FCKeditor Global Profile'", 0, 1);
495 $has_profiles = FALSE
;
496 //find profile other than Global
497 if ($obj = db_fetch_object($result)) {
498 $has_profiles = TRUE
;
501 //find roles with profiles
502 $result = db_query("SELECT rid FROM {fckeditor_role}");
504 while ($obj = db_fetch_object($result)) {
507 $rids = array_unique($rids);
508 if (!$has_profiles) {
509 drupal_set_message(t("No FCKeditor profiles found. At this moment, nobody is able to use FCKeditor. Create new profile below."), "error");
512 //not all roles with access fckeditor has their FCKeditor profile assigned
513 $diff = array_diff(array_keys($access_fckeditor_roles), $rids);
516 foreach ($diff as
$rid) {
517 $list .
= "<li>".
$access_fckeditor_roles[$rid] .
"</li>";
520 drupal_set_message(t("Not all roles with <strong>!access</strong> permission are associated with FCKeditor profiles. As a result, users having the following roles may be unable to use FCKeditor: !list Create new or edit FCKeditor profiles below and in the <strong>Basic setup</strong> section, check "Roles allowed to use this profile".", array("!access" => l(t("access fckeditor"), "admin/user/permissions"), "!list" => $list)), "warning");
525 $output = fckeditor_profile_overview();
532 * Save a profile to the database.
533 * @todo add more entries to array in the user_save line
535 function fckeditor_profile_save($edit) {
536 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s' or name = '%s'", $edit['name'], empty($edit['old_name']) ?
"" : $edit['old_name']);
537 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s' or name = '%s'", $edit['name'], empty($edit['old_name']) ?
"" : $edit['old_name']);
538 db_query("INSERT INTO {fckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], serialize($edit));
539 if (!empty($edit['rids']))
540 foreach ($edit['rids'] as
$rid => $value) {
541 db_query("INSERT INTO {fckeditor_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid);
544 // if users can't set their own defaults, make sure to remove $user->fckeditor_status so their default doesn't override the main default
545 if (!empty($edit['user_choose']) && $edit['user_choose'] == 'false') {
547 user_save($user, array('fckeditor_status' => NULL
));
551 function fckeditor_global_profile_save($edit) {
552 if (isset($edit['rank'])) {
553 $edit['rank'] = explode('>', str_replace(' ', '', $edit['rank']));
556 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s' or name = '%s'", $edit['name'], empty($edit['old_name']) ?
"" : $edit['old_name']);
557 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s' or name = '%s'", $edit['name'], empty($edit['old_name']) ?
"" : $edit['old_name']);
558 db_query("INSERT INTO {fckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], serialize($edit));
562 * Controller for fckeditor profiles.
564 function fckeditor_profile_overview() {
567 $profiles = fckeditor_profile_load();
569 $roles = user_roles();
570 $access_fckeditor_roles = user_roles(FALSE
, 'access fckeditor');
571 $header = array(t('Profile'), t('Roles'), t('Operations'));
572 foreach ($profiles as
$p) {
574 if ($p->name
!== "FCKeditor Global Profile") {
575 foreach ($p->rids as
$rid => $name) {
576 if (!isset($access_fckeditor_roles[$rid])) {
580 $rows[] = array(array('data' => $p->name
, 'valign' => 'top'), array('data' => implode("<br />\n", $rids)), array('data' => l(t('edit'), 'admin/settings/fckeditor/edit/'.
urlencode($p->name
)) .
' '.
l(t('delete'), 'admin/settings/fckeditor/delete/'.
urlencode($p->name
)), 'valign' => 'top'));
583 $output .
= "<h3>".
t("Profiles") .
"</h3>";
584 $output .
= theme('table', $header, $rows);
585 $output .
= '<p>'.
l(t('Create new profile'), 'admin/settings/fckeditor/add') .
'</p>';
588 drupal_set_message(t('No profiles found. Click here to !create.', array('!create' => l(t("create a new profile"), 'admin/settings/fckeditor/add'))));
592 if (!isset($profiles['FCKeditor Global Profile'])) {
593 drupal_set_message(t('Global Profile not found. Click here to !create.', array('!create' => l(t("create the global profile"), 'admin/settings/fckeditor/addg'))));
596 $output .
= "<h3>".
t("Global Settings") .
"</h3>";
597 $rows[] = array(array('data' => t('FCKeditor Global Profile'), 'valign' => 'top'), array('data' => l(t('edit'), 'admin/settings/fckeditor/editg') .
" ".
l(t('delete'), 'admin/settings/fckeditor/deleteg'), 'valign' => 'top'));
598 $output .
= theme('table', array(t('Profile'), t('Operations')), $rows);
605 * Load all profiles. Just load one profile if $name is passed in.
607 function fckeditor_profile_load($name = '') {
608 static
$profiles = array();
611 $roles = user_roles();
612 $result = db_query('SELECT * FROM {fckeditor_settings}');
613 while ($data = db_fetch_object($result)) {
614 $data->settings
= unserialize($data->settings
);
615 $result2 = db_query("SELECT rid FROM {fckeditor_role} WHERE name = '%s'", $data->name
);
617 while ($r = db_fetch_object($result2)) {
618 $role[$r->rid
] = $roles[$r->rid
];
622 $profiles[$data->name
] = $data;
626 return ($name ?
$profiles[$name] : $profiles);
630 * @param int $excl_mode 1/include, exclude otherwise
631 * @param string $excl_fields fields (HTML IDs)
632 * @param string $excl_paths paths (drupal paths)
633 * @param string $element_id current ID
634 * @param string $get_q current path
637 * returns true if FCKeditor is enabled
639 function fckeditor_is_enabled($excl_mode, $excl_fields, $excl_paths, $element_id, $get_q) {
640 $arr_excl_fields = preg_split("/[\s,]+/", strip_tags($excl_fields));
641 $field_found = fckeditor_idsearch($element_id, $arr_excl_fields);
643 $path = drupal_get_path_alias($get_q);
644 $regexp = '/^('.
preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'.
preg_quote(variable_get('site_frontpage', 'node'), '/') .
'\2'), preg_quote($excl_paths, '/')) .
')$/';
645 $path_found = preg_match($regexp, $path);
647 $found = $field_found || $path_found;
649 $result = ($excl_mode == 1) ?
$found : !$found;
654 * This function create the HTML objects required for the FCKeditor
657 * A fully populated form elment to add the editor to
659 * The same $element with extra FCKeditor markup and initialization
661 function fckeditor_process_textarea($element) {
662 static
$is_running = FALSE
;
664 static
$id2id = array();
665 static
$processed_elements = array();
666 global $user, $fckeditor_simple_toolbar_ids;
668 $processed = in_array($element['#id'], $processed_elements);
670 //hack for module developers that want to disable FCKeditor on their textareas
671 if (key_exists('#wysiwyg', $element) && !$element['#wysiwyg']) {
675 //skip this one, surely nobody wants WYSIWYG here
676 switch ($element['#id']) {
677 case
'edit-excl-list':
678 case
'edit-simple-incl-list':
679 case
'edit-simple-incl-paths':
680 case
'edit-simple-incl-fields':
682 case
'edit-excl-fields':
683 case
'edit-excl-paths':
685 case
'edit-teaser-js':
690 if (isset($element['#attributes']['disabled']) && $element['#attributes']['disabled'] == 'disabled') {
694 $profile = fckeditor_user_get_profile($user);
700 $conf = $profile->settings
;
702 if ($conf['allow_user_conf']=='t') {
703 foreach (array('default', 'show_toggle', 'popup', 'skin', 'toolbar', 'expand', 'width', 'lang', 'auto_lang') as
$setting) {
704 $conf[$setting] = fckeditor_user_get_setting($user, $profile, $setting);
707 if ($conf["popup"]=="t" && $conf["show_toggle"]=="t") {
708 $conf["show_toggle"]="f";
711 if (!isset($conf['xss'])) {
714 if (!isset($conf['xss_t'])) {
718 $themepath = path_to_theme() .
'/';
721 $enabled = fckeditor_is_enabled(empty($conf['excl_mode']) ?
"" : $conf['excl_mode'], empty($conf['excl_fields']) ?
"" : $conf['excl_fields'], empty($conf['excl_paths']) ?
"" : $conf['excl_paths'], $element['#id'], $_GET['q']);
723 $global_profile = fckeditor_profile_load("FCKeditor Global Profile");
724 $global_conf = $global_profile->settings
;
726 $enabled = fckeditor_is_enabled(empty($global_conf['excl_mode']) ?
"" : $global_conf['excl_mode'], empty($global_conf['excl_fields']) ?
"" : $global_conf['excl_fields'], empty($global_conf['excl_paths']) ?
"" : $global_conf['excl_paths'], $element['#id'], $_GET['q']);
729 if (!isset($element['#suffix'])) {
730 $element['#suffix'] = "";
733 if ((($element['#rows'] > $conf['min_rows']) || ($conf['min_rows'] <= 1 && empty($element['#rows']))) && $enabled) {
734 // only replace textarea when it has enough rows and it is enabled
736 // Set resizable to false to avoid drupal.js resizable function from taking control of the textarea
737 if ($conf["popup"]=="f") {
738 $element['#resizable'] = FALSE
;
741 //it's not a problem when adding new content
742 if ($conf['xss'] && arg(1) != "add") {
743 //let FCKeditor know when perform XSS checks
744 if ($conf['xss_t'] == 1) {
745 $xss_class = 'filterxss1';
748 $xss_class = 'filterxss2';
751 if (!isset($element['#attributes']['class'])) {
752 $element['#attributes']['class'] = '';
756 if ($conf['xss'] == 2) {
757 $element['#attributes']['class'] .
= ' '.
$xss_class;
760 //check for HTML filter
761 $menuitem = menu_get_item();
762 if (!empty($menuitem['map'][1])) {
763 if (is_object($menuitem['map'][1]) && in_array($menuitem['map'][1]->format
, fckeditor_html_filter_formats())) {
764 $element['#attributes']['class'] .
= ' '.
$xss_class;
767 else if (arg(0) == 'comment' && arg(1) == 'edit' && is_numeric(arg(2))) {
768 $comment = _comment_load(arg(2));
770 if (in_array($comment->format
, fckeditor_html_filter_formats())) {
771 $element['#attributes']['class'] .
= ' '.
$xss_class;
774 //force XSS check if we don't have an information about input format
776 $element['#attributes']['class'] .
= ' '.
$xss_class;
780 $xss_check = ((isset($xss_class) && $xss_class)) ?
1 : 0;
782 if (in_array($element['#id'], $processed_elements)) {
783 $js_id = $id2id[$element['#id']];
786 $js_id = 'oFCK_'.
$num++;
787 $id2id[$element['#id']] = $js_id;
789 $fckeditor_on = ($conf['default']=='t') ?
1 : 0 ;
792 if (isset($element['#post']['teaser_js'])) {
793 $content .
= $element['#post']['teaser_js'] .
"<!--break-->";
795 $content .
= $element['#value'];
796 $wysiwyg_link = "<div id=\"fck_{$js_id}\"><textarea id=\"{$js_id}\">".
htmlspecialchars($content) .
"</textarea></div>\n";
797 $wysiwyg_link .
= "<a href=\"javascript:Toggle('{$js_id}','{$element['#id']}','".
str_replace("'", "\\'", t("Switch to plain text editor")) .
"','".
str_replace("'", "\\'", t("Switch to rich text editor")) .
"',".
$xss_check .
");\" id=\"switch_{$js_id}\" ".
($fckeditor_on?
"style=\"display:none\"":"") .
">";
798 $wysiwyg_link .
= $fckeditor_on ?
t("Switch to plain text editor") : t("Switch to rich text editor");
799 $wysiwyg_link .
= "</a>";
800 if ($conf['show_toggle'] == 't' && !$processed) {
801 drupal_add_js('if (Drupal.jsEnabled) {$(document).ready(function() {CreateToggle("'.
$element['#id'].
'","'.
$js_id.
'", '.
$fckeditor_on.
');});}', 'inline');
803 //settings are saved as strings, not booleans
804 if ($conf['show_toggle'] == 't') {
805 // Make sure to append to #suffix so it isn't completely overwritten
806 $element['#suffix'] .
= $wysiwyg_link;
808 // setting some variables
809 $module_drupal_path = drupal_get_path('module', 'fckeditor');
810 $module_full_path = $host .
$module_drupal_path;
811 // get the default drupal files path
812 $files_path = $host .
file_directory_path();
813 // module_drupal_path:
814 // 'modules/fckeditor' (length=17)
816 // '/drupal5/modules/fckeditor' (length=26)
818 // '/drupal5/files' (length=14)
819 // configured in settings
820 $width = $conf['width'];
822 // sensible default for small toolbars
823 $height = $element['#rows'] * 14 + 140;
826 drupal_add_js($module_drupal_path .
'/fckeditor/fckeditor.js');
827 drupal_add_js($module_drupal_path .
'/fckeditor.utils.js?'.@
filemtime($module_drupal_path.
"/fckeditor.utils.js"));
831 $toolbar = $conf['toolbar'];
832 //$height += 100; // for larger toolbars
834 $force_simple_toolbar = fckeditor_is_enabled(1, empty($conf['simple_incl_fields']) ?
"" : $conf['simple_incl_fields'], empty($conf['simple_incl_paths']) ?
"" : $conf['simple_incl_paths'], $element['#id'], $_GET['q']);
835 if (!$force_simple_toolbar) {
836 $force_simple_toolbar = fckeditor_is_enabled(1, empty($global_conf['simple_incl_fields']) ?
"" : $global_conf['simple_incl_fields'], empty($global_conf['simple_incl_paths']) ?
"" : $global_conf['simple_incl_paths'], $element['#id'], $_GET['q']);
838 if ($force_simple_toolbar) {
839 $toolbar = FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME
;
841 $textarea_id = $conf['show_toggle'] == 't' ?
$js_id : $element['#id'];
842 $js = $js_id .
" = new FCKeditor( '".
$textarea_id .
"' );
843 ".
$js_id .
".BasePath = '".
$module_full_path .
"/fckeditor/';
844 ".
$js_id .
".Config['CustomConfigurationsPath'] = \"".
$module_full_path .
"/fckeditor.config.js?".@
filemtime($module_drupal_path.
"/fckeditor.config.js").
"\";
845 ".
$js_id .
".Config['TextareaID'] = \"".
$element['#id'] .
"\";";
847 //if ($conf['appearance_conf'] == 'f') {
848 $js .
= "\n".
$js_id .
".ToolbarSet = \"".
$toolbar .
"\";
849 ".
$js_id .
".Config['SkinPath'] = ".
$js_id .
".BasePath + \"editor/skins/".
$conf['skin'] .
"/\";
850 ".
$js_id .
".Config['DefaultLanguage'] = \"".
$conf['lang'] .
"\";
851 ".
$js_id .
".Config['AutoDetectLanguage'] = ".
($conf['auto_lang']=="t"?
"true":"false") .
";
852 ".
$js_id .
".Height = \"".
$height .
"\";
853 ".
$js_id .
".Config['ToolbarStartExpanded'] = ".
($conf['expand']=="t"?
"true":"false") .
";
854 ".
$js_id .
".Width = \"".
$width .
"\";\n";
856 //if ($conf['output_conf'] == 'f') {
857 $js .
= "\n".
$js_id .
".Config['EnterMode'] = '".
$conf['enter_mode'] .
"';
858 ".
$js_id .
".Config['ShiftEnterMode'] = \"".
$conf['shift_enter_mode'] .
"\";
859 ".
$js_id .
".Config['FontFormats'] = \"".
str_replace(",", ";", $conf['font_format']) .
"\";
860 ".
$js_id .
".Config['FormatSource'] = ".
($conf['format_source']=="t"?
"true":"false") .
";
861 ".
$js_id .
".Config['FormatOutput'] = ".
($conf['format_output']=="t"?
"true":"false") .
";\n";
864 if (function_exists('img_assist_perm')) { //#275158
865 drupal_add_js("var fckImgAssistPath = '".
base_path() .
drupal_get_path('module', 'img_assist') .
"';", 'inline');
867 // add code for filebrowser for users that have access
868 if (user_access('allow fckeditor file uploads')==1) {
869 $filebrowser = $conf['filebrowser'];
870 if ($filebrowser == 'imce' && !module_exists('imce')) {
871 $filebrowser = 'none';
873 $quickupload = $conf['quickupload'] == 't';
875 // load variables used by both quick upload and filebrowser
876 // and assure that the $_SESSION variables are loaded
877 if ($quickupload || $filebrowser == 'builtin') {
879 $connector_path = $module_drupal_path .
"/fckeditor/editor/filemanager/connectors/php/connector.php";
880 if (file_exists($connector_path)) {
881 //FCKeditor 2.5 and above
882 $connector_path = $module_full_path .
"/fckeditor/editor/filemanager/connectors/php/connector.php";
886 $connector_path = "connectors/php/connector.php";
888 $upload_path = $module_drupal_path .
"/fckeditor/editor/filemanager/connectors/php/upload.php";
889 if (file_exists($upload_path)) {
890 //FCKeditor 2.5 and above
891 $upload_path = $module_full_path .
"/fckeditor/editor/filemanager/connectors/php/upload.php";
895 $upload_path = "/fckeditor/editor/filemanager/upload/php/upload.php";
898 if (!empty($profile->settings
['UserFilesPath'])) $_SESSION['FCKeditor']['UserFilesPath'] = strtr($profile->settings
['UserFilesPath'], array("%f" => file_directory_path(), "%u" => $user->uid
, "%b" => $host));
899 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']));
900 if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE
) {
901 $_SESSION['FCKeditor']['UserFilesPath'] = url('system/files') .
'/';
902 $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = realpath(file_directory_path()) . DIRECTORY_SEPARATOR
;
907 $js .
= $js_id .
".Config['LinkUpload'] = true;\n";
908 $js .
= $js_id .
".Config['ImageUpload'] = true;\n";
909 $js .
= $js_id .
".Config['FlashUpload'] = true;\n";
910 $js .
= $js_id .
".Config['LinkUploadURL'] = '".
$upload_path .
"';\n";
911 $js .
= $js_id .
".Config['ImageUploadURL'] = '".
$upload_path .
"?Type=Image';\n";
912 $js .
= $js_id .
".Config['FlashUploadURL'] = '".
$upload_path .
"?Type=Flash';\n";
915 $js .
= $js_id .
".Config['LinkUpload'] = false;\n";
916 $js .
= $js_id .
".Config['ImageUpload'] = false;\n";
917 $js .
= $js_id .
".Config['FlashUpload'] = false;\n";
920 switch ($filebrowser) {
922 $js .
= $js_id .
".Config['LinkBrowser']= true;\n";
923 $js .
= $js_id .
".Config['ImageBrowser']= true;\n";
924 $js .
= $js_id .
".Config['FlashBrowser']= true;\n";
925 $js .
= $js_id .
".Config['LinkBrowserURL']= '".
$host .
"?q=imce&app=FCKEditor|url@txtUrl';\n";
926 $js .
= $js_id .
".Config['ImageBrowserURL']= '".
$host .
"?q=imce&app=FCKEditor|url@txtUrl|width@txtWidth|height@txtHeight';\n";
927 $js .
= $js_id .
".Config['FlashBrowserURL']= '".
$host .
"?q=imce&app=FCKEditor|url@txtUrl';\n";
930 $js .
= $js_id .
".Config['LinkBrowser'] = true;\n";
931 $js .
= $js_id .
".Config['ImageBrowser'] = true;\n";
932 $js .
= $js_id .
".Config['FlashBrowser'] = true;\n";
933 $js .
= $js_id .
".Config['LinkBrowserURL'] = '".
$module_full_path .
"/fckeditor/editor/filemanager/browser/default/browser.html?Connector=".
$connector_path .
"&ServerPath=".
$files_path .
"';\n";
934 $js .
= $js_id .
".Config['ImageBrowserURL'] = '".
$module_full_path .
"/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=".
$connector_path .
"&ServerPath=".
$files_path .
"';\n";
935 $js .
= $js_id .
".Config['FlashBrowserURL'] = '".
$module_full_path .
"/fckeditor/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=".
$connector_path .
"&ServerPath=".
$files_path .
"';\n";
939 $js .
= $js_id .
".Config['LinkBrowser'] = false;\n";
940 $js .
= $js_id .
".Config['ImageBrowser'] = false;\n";
941 $js .
= $js_id .
".Config['FlashBrowser'] = false;\n";
946 $js .
= $js_id .
".Config['LinkBrowser'] = false;\n";
947 $js .
= $js_id .
".Config['ImageBrowser'] = false;\n";
948 $js .
= $js_id .
".Config['FlashBrowser'] = false;\n";
949 $js .
= $js_id .
".Config['LinkUpload'] = false;\n";
950 $js .
= $js_id .
".Config['ImageUpload'] = false;\n";
951 $js .
= $js_id .
".Config['FlashUpload'] = false;\n";
954 if (!empty($conf['js_conf'])) {
955 $lines = preg_split("/[\n\r]+/", $conf['js_conf']);
956 foreach ($lines as
$l)
957 if ($l && strlen($l) > 5) {
958 $eqpos = strpos($l, "=");
959 if (false
!== $eqpos) {
960 $option = str_replace("FCKConfig.", "", substr($l, 0, $eqpos));
961 $js .
= "\n".
$js_id .
".Config['".
trim($option) .
"'] =".
substr($l, $eqpos + 1);
966 // add custom xml stylesheet if it exists
967 if (!empty($conf['css_style']) && $conf['css_style'] == 'theme') {
968 if (file_exists($themepath .
'/fckstyles.xml')) {
969 $styles_xml_path = $host .
$themepath .
'/fckstyles.xml';
970 $js .
= $js_id .
".Config['StylesXmlPath'] = \"".
$styles_xml_path .
"\";\n";
973 else if (!empty($conf['css_style']) && $conf['css_style'] == 'self') {
974 $conf['styles_path'] = str_replace("%h%t", "%t", $conf['styles_path']);
975 $js .
= $js_id .
".Config['StylesXmlPath'] = \"".
str_replace(array('%h', '%t', '%m'), array($host, $host .
$themepath, $module_drupal_path), $conf['styles_path']) .
"\";\n";
977 // add custom stylesheet if configured
978 // lets hope it exists but we'll leave that to the site admin
979 if ($conf['css_mode'] == 'theme') {
980 $css = $themepath .
'style.css';
981 if (file_exists($css)) {
982 $js .
= $js_id .
".Config['EditorAreaCSS'] = \"".
$host .
$css .
",".
$module_full_path .
"/fckeditor.css\";";
985 else if ($conf['css_mode'] == 'self') {
986 $conf['css_path'] = str_replace("%h%t", "%t", $conf['css_path']);
987 $js .
= $js_id .
".Config['EditorAreaCSS'] = \"".
str_replace(array('%h', '%t'), array($host, $host .
$themepath), $conf['css_path']) .
",".
$module_full_path .
"/fckeditor.css\";";
991 drupal_add_js('var '.
$js_id .
';if (Drupal.jsEnabled) {$(document).ready(function() {'.
$js .
'});}', 'inline');
994 if ($conf['popup']=="t") {
995 // Add the script file with the popup open function.
997 drupal_add_js($module_drupal_path .
'/fckeditor.popup.js');
999 $element['#suffix'] .
= " <span class=\"fckeditor_popuplink\">(<a href=\"#\" onclick=\"FCKeditor_OpenPopup('".
$module_full_path .
"/fckeditor.popup.html?var=".
$js_id .
"&el=".
$element['#id'] .
"');return false;\">".
t('Open rich editor') .
"</a>)</span>";
1002 // if no popup mode, add the editor initialization to the footer
1003 // this obviously needs print($closure) in page.tpl.php
1004 if ($fckeditor_on && !$processed) {
1005 drupal_add_js('if (Drupal.jsEnabled) {$(document).ready(function() {if (typeof ('.
$js_id .
') != "undefined") {
1006 if ($("#edit-teaser-js").size() && $("#edit-teaser-js").val().length){
1007 $("#edit-body").val($("#edit-teaser-js").val() + "<!--break-->" + $("#edit-body").val());
1009 window.setTimeout("FCKeditorReplaceTextarea(\''.
$textarea_id .
'\','.
$js_id .
','.
$xss_check .
');",100);}});}', 'inline', 'footer');
1014 // display the field id for administrators
1015 if (user_access('administer fckeditor')) {
1016 $element['#suffix'] .
= '<div class="textarea-identifier description">'.
t('The ID for !excluding this element is: !id - the path is: !path', array(
1017 '!excluding' => l(t("excluding or including"), 'admin/settings/fckeditor'),
1018 '!id' => $element['#id'],
1019 '!path' => $_GET['q'],
1023 $processed_elements[] = $element['#id'];
1029 * Implementation of hook_user().
1031 function fckeditor_user($type, &$edit, &$user, $category = NULL
) {
1032 if ($type == 'form' && $category == 'account' && user_access('access fckeditor')) {
1033 $profile = fckeditor_user_get_profile($user);
1034 $toolbar_options = fckeditor_load_toolbar_options();
1035 $skin_options = fckeditor_load_skin_options();
1036 $lang_options = fckeditor_load_lang_options();
1038 // because the settings are saved as strings we need to test for the string 'true'
1039 if ($profile->settings
['allow_user_conf'] == 't') {
1040 $form['fckeditor'] = array(
1041 '#type' => 'fieldset',
1042 '#title' => t('Rich Text Editor settings'),
1044 '#collapsible' => TRUE
,
1045 '#collapsed' => TRUE
1048 $form['fckeditor']['fckeditor_default'] = array(
1049 '#type' => 'select',
1050 '#title' => t('Default state'),
1051 '#default_value' => isset($user->fckeditor_default
) ?
$user->fckeditor_default
: (isset($profile->settings
['default']) ?
$profile->settings
['default'] : 'f'),
1052 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
1053 '#description' => t('Should rich-text editing be enabled or disabled by default in textarea fields? If disabled, rich text editor may still be enabled using toggle or popup window.'),
1056 $form['fckeditor']['fckeditor_show_toggle'] = array(
1057 '#type' => 'select',
1058 '#title' => t('Show disable/enable rich text editor toggle'),
1059 '#default_value' => isset($user->fckeditor_show_toggle
) ?
$user->fckeditor_show_toggle
: (isset($profile->settings
['show_toggle']) ?
$profile->settings
['show_toggle'] : 't'),
1060 '#options' => array('t' => t('true'), 'f' => t('false')),
1061 '#description' => t('Whether or not to show the disable/enable rich text editor toggle below the textarea. Works only if FCKeditor is not running a popup window (see below).'),
1064 $form['fckeditor']['fckeditor_popup'] = array(
1065 '#type' => 'select',
1066 '#title' => t('Use FCKeditor in a popup window'),
1067 '#default_value' => isset($user->fckeditor_popup
) ?
$user->fckeditor_popup
: (isset($profile->settings
['popup']) ?
$profile->settings
['popup'] : 'f'),
1068 '#options' => array('f' => t('false'), 't' => t('true')),
1069 '#description' => t('If this option is enabled a link to a popup window will be used instead of a textarea replace.'),
1072 $form['fckeditor']['fckeditor_skin'] = array(
1073 '#type' => 'select',
1074 '#title' => t('Skin'),
1075 '#default_value' => isset($user->fckeditor_skin
) ?
$user->fckeditor_skin
: (isset($profile->settings
['skin']) ?
$profile->settings
['skin'] : 'default'),
1076 '#options' => $skin_options,
1077 '#description' => t('Choose a FCKeditor skin.'),
1080 $form['fckeditor']['fckeditor_toolbar'] = array(
1081 '#type' => 'select',
1082 '#title' => t('Toolbar'),
1083 '#default_value' => isset($user->fckeditor_toolbar
) ?
$user->fckeditor_toolbar
: (isset($profile->settings
['toolbar']) ?
$profile->settings
['toolbar'] : 'default'),
1084 '#options' => $toolbar_options,
1085 '#description' => t('Choose a FCKeditor toolbar set.'),
1088 $form['fckeditor']['fckeditor_expand'] = array(
1089 '#type' => 'select',
1090 '#title' => t('Start the toolbar expanded'),
1091 '#default_value' => isset($user->fckeditor_expand
) ?
$user->fckeditor_expand
: (isset($profile->settings
['expand']) ?
$profile->settings
['expand'] : 't'),
1092 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
1093 '#description' => t('The toolbar start expanded or collapsed.'),
1096 $form['fckeditor']['fckeditor_width'] = array(
1097 '#type' => 'textfield',
1098 '#title' => t('Width'),
1099 '#default_value' => isset($user->fckeditor_width
) ?
$user->fckeditor_width
: (isset($profile->settings
['width']) ?
$profile->settings
['width'] : '100%'),
1100 '#description' => t("Width in pixels or percent. Ex: 400 or 100%"),
1102 '#maxlength' => 128,
1105 $form['fckeditor']['fckeditor_lang'] = array(
1106 '#type' => 'select',
1107 '#title' => t('Language'),
1108 '#default_value' => isset($user->fckeditor_lang
) ?
$user->fckeditor_lang
: (isset($profile->settings
['lang']) ?
$profile->settings
['lang'] : 'en'),
1109 '#options' => $lang_options,
1110 '#description' => t('The language for the FCKeditor interface.')
1113 $form['fckeditor']['fckeditor_auto_lang'] = array(
1114 '#type' => 'select',
1115 '#title' => t('Auto-detect language'),
1116 '#default_value' => isset($user->fckeditor_auto_lang
) ?
$user->fckeditor_auto_lang
: (isset($profile->settings
['auto_lang']) ?
$profile->settings
['auto_lang'] : 't'),
1117 '#options' => array('t' => t('true'), 'f' => t('false')),
1118 '#description' => t('Use auto detect user language feature.')
1121 return array('fckeditor' => $form);
1125 if ($type == 'validate') {
1126 if (isset($edit['fckeditor_default'], $edit['fckeditor_popup']) && $edit['fckeditor_default'] == 't' && $edit['fckeditor_popup'] == 't') {
1127 form_set_error('fckeditor_popup', t('If FCKeditor is enabled by default, popup window must be disabled.'));
1130 if (isset($edit['fckeditor_show_toggle'], $edit['fckeditor_popup']) && $edit['fckeditor_show_toggle'] == 't' && $edit['fckeditor_popup'] == 't') {
1131 form_set_error('fckeditor_popup', t('If toggle is enabled, popup window must be disabled.'));
1134 if (isset($edit['fckeditor_width']) && !preg_match('/^\d+%?$/', $edit['fckeditor_width'])) {
1135 form_set_error('fckeditor_width', t('Enter valid width. Example: 400 or 100%.'));
1141 * Return an HTML form for profile configuration.
1143 function fckeditor_profile_form($edit) {
1145 $output = drupal_get_form('fckeditor_profile_form_build', $edit);
1151 * Return an HTML form for global profile configuration.
1153 function fckeditor_global_profile_form($edit) {
1155 $output = drupal_get_form('fckeditor_global_profile_form_build', $edit);
1160 function fckeditor_load_toolbar_options() {
1162 $module_drupal_path = drupal_get_path('module', 'fckeditor');
1163 $fckconfig_js = $module_drupal_path .
'/fckeditor/fckconfig.js';
1164 $fckeditor_config_js = $module_drupal_path .
'/fckeditor.config.js';
1165 if (file_exists($fckconfig_js) && is_readable($fckconfig_js)) {
1166 $fp = @
fopen($fckconfig_js, "r");
1168 while (!feof($fp)) {
1169 $line = fgets($fp, 1024);
1170 if (preg_match("/FCKConfig\.ToolbarSets\[(\"|')(.*?)\\1\]/i", $line, $matches)) {
1171 $arr[$matches[2]] = ucfirst($matches[2]);
1177 if (file_exists($fckeditor_config_js) && is_readable($fckeditor_config_js)) {
1178 $fp = @
fopen($fckeditor_config_js, "r");
1180 while (!feof($fp)) {
1181 $line = fgets($fp, 1024);
1182 if (preg_match("/FCKConfig\.ToolbarSets\[(\"|')(.*?)\\1\]/i", $line, $matches)) {
1183 $arr[$matches[2]] = ucfirst($matches[2]);
1190 //oops, we have no information about toolbars, let's use hardcoded array
1194 'Default' => 'Default',
1203 * Get an array of input formats that include HTML filter
1207 function fckeditor_html_filter_formats() {
1210 if (isset($return)) {
1215 $r = db_query("SELECT format FROM {filters} WHERE module = 'filter' AND delta = 0");
1216 while ($row = db_fetch_object($r)) {
1217 $return[] = $row->format
;
1220 //Let other filter modules that call filter_xss() add more formats
1221 //that should be considered as implementing HTML filter by FCKeditor
1222 foreach (module_implements('implements_filter_xss') as
$name) {
1223 $function = $name .
'_implements_filter_xss';
1224 $result = $function();
1225 if (isset($result) && is_array($result)) {
1226 $return = array_merge($return, $result);
1228 else if (isset($result)) {
1229 $return[] = $result;
1236 function fckeditor_load_skin_options() {
1238 $module_drupal_path = drupal_get_path('module', 'fckeditor');
1239 $skin_dir = $module_drupal_path .
'/fckeditor/editor/skins';
1240 if (is_dir($skin_dir)) {
1241 $dh = @
opendir($skin_dir);
1242 if (FALSE
!== $dh) {
1243 while (($file = readdir($dh)) !== FALSE
) {
1244 if (in_array($file, array(".", "..", "CVS", ".svn"))) {
1247 if (is_dir($skin_dir . DIRECTORY_SEPARATOR .
$file)) {
1248 $arr[$file] = ucfirst($file);
1255 //oops, we have no information about skins, let's use only default
1258 'default' => 'Default',
1266 function fckeditor_load_lang_options() {
1268 $module_drupal_path = drupal_get_path('module', 'fckeditor');
1269 $lang_dir = $module_drupal_path .
'/fckeditor/editor/lang';
1270 if (is_dir($lang_dir)) {
1271 $dh = @
opendir($lang_dir);
1272 if (false
!== $dh ) {
1273 while (($file = readdir($dh)) !== FALSE
) {
1274 if (in_array($file, array(".", "..", "CVS", ".svn"))) {
1277 if (is_file($lang_dir . DIRECTORY_SEPARATOR .
$file) && preg_match("/^(.*?)\.js$/", $file, $matches)) {
1278 $lang = $matches[1];
1279 $arr[$lang] = strtoupper($lang);
1286 //oops, we have no information about languages, let's use those available in FCKeditor 2.4.3
1289 'af' => 'Afrikaans',
1291 'bg' => 'Bulgarian',
1292 'bn' => 'Bengali/Bangla',
1300 'en-au' => 'English (Australia)',
1301 'en-ca' => 'English (Canadian)',
1302 'en-uk' => 'English (United Kingdom)',
1303 'eo' => 'Esperanto',
1315 'hu' => 'Hungarian',
1320 'lt' => 'Lithuanian',
1322 'mn' => 'Mongolian',
1324 'nb' => 'Norwegian Bokmal',
1326 'no' => 'Norwegian',
1328 'pt' => 'Portuguese (Portugal)',
1329 'pt-br' => 'Portuguese (Brazil)',
1333 'sl' => 'Slovenian',
1334 'sr' => 'Serbian (Cyrillic)',
1335 'sr-latn' => 'Serbian (Latin)',
1339 'uk' => 'Ukrainian',
1340 'vi' => 'Vietnamese',
1341 'zh' => 'Chinese Traditional',
1342 'zh-cn' => 'Chinese Simplified',
1352 * sort roles according to precedence settings. previously sorted roles are followed by latest added roles.
1354 function fckeditor_sorted_roles() {
1356 if (isset($order)) {
1360 $roles = user_roles(0, 'access fckeditor');
1362 $result = db_query("SELECT settings FROM {fckeditor_settings} WHERE name='FCKeditor Global Profile'");
1363 $data = db_fetch_object($result);
1364 if (!empty($data->settings
)) {
1365 $settings = unserialize($data->settings
);
1366 if (isset($settings['rank']) && !empty($settings['rank']))
1367 foreach ($settings['rank'] as
$rid) {
1368 if (isset($roles[$rid])) {
1369 $order[$rid] = $roles[$rid];
1370 unset($roles[$rid]);
1374 krsort($roles);//sort the remaining unsorted roles by id, descending.
1379 function fckeditor_global_profile_form_build($sth, $edit) {
1380 $edit = (object) $edit;
1382 if (arg(3) == 'addg') {
1383 drupal_set_breadcrumb(array(l(t('administer'), 'admin'), l(t('fckeditor'), 'admin/settings/fckeditor'), l(t('Add new FCKeditor Global Profile'), 'admin/settings/fckeditor/addg')));
1385 $result = db_query("SELECT DISTINCT(rid) FROM {fckeditor_role} WHERE name='FCKeditor Global Profile'");
1386 $data = db_fetch_object($result);
1388 if (!empty($data->rid
)) {
1389 drupal_set_message(t("Global profile already exist. Only one global profile is allowed."), "error");
1393 $btn = t('Create global profile');
1396 $form['old_name'] = array('#type' => 'hidden', '#value' => $edit->name
);
1397 $btn = t('Update global profile');
1400 $form['common'] = array(
1401 '#type' => 'fieldset',
1402 '#title' => t('Main setup'),
1403 '#collapsible' => TRUE
,
1404 '#collapsed' => TRUE
1407 $roles = fckeditor_sorted_roles();
1408 $rids = $rtext = array();
1409 foreach ($roles as
$rid => $name) {
1411 $rtext[] = '<strong>'.
$rid .
' - </strong>'.
$name;
1413 $form['common']['rank'] = array('#type' => 'textfield',
1414 '#title' => t('Role precedence'),
1415 '#default_value' => implode('>', $rids),
1416 '#description' => t('A user having <strong>multiple roles</strong> gets the permissions of the highest one. Sort role IDs according to their <strong>precedence from higher to lower</strong> by putting > in between.<br />'),
1419 $form['common']['rank']['#description'] .
= t('Here is the id-name pairs of roles having access to FCKeditor:') .
'<div>'.
implode('<br />', $rtext) .
'</div>';
1422 $form['common']['rank']['#description'] .
= t('You haven\'t assigned the <code>!access1</code> !permissions yet.', array('!access1' => t('access fckeditor'), '!permissions' => l(t('permissions'), 'admin/user/permissions')));
1425 $form['fckeditor_exclude_settings'] = array(
1426 '#type' => 'fieldset',
1427 '#title' => t('Visibility settings'),
1428 '#collapsible' => TRUE
,
1429 '#collapsed' => TRUE
,
1432 $form['fckeditor_exclude_settings']['excl_mode'] = array(
1433 '#type' => 'select',
1434 '#title' => t('Use inclusion or exclusion mode'),
1435 '#default_value' => (empty($edit->settings
['excl_mode']) || in_array($edit->settings
['excl_mode'], array(0, 2))) ?
0 : 1,
1436 '#options' => array('0' => t('exclude'), '1' => t('include')),
1437 '#description' => t('Choose the way of disabling/enabling FCKeditor on selected fields/paths (see below). Use exclude to disable FCKeditor on selected fields/paths. Use include if you want to load FCKeditor only on selected paths/fields.'),
1440 * get excluded fields - so we can have normal textareas too
1441 * split the phrase by any number of commas or space characters,
1442 * which include " ", \r, \t, \n and \f
1444 $form['fckeditor_exclude_settings']['excl_fields'] = array(
1445 '#type' => 'textarea',
1446 '#title' => t('Fields to exclude/include'),
1449 '#prefix' => '<div style="margin-left:20px">',
1450 '#suffix' => '</div>',
1451 '#default_value' => !empty($edit->settings
['excl_fields']) ?
$edit->settings
['excl_fields'] : '',
1452 '#description' => t("Enter names (HTML ID's) of fields that may or may not have an FCKeditor, depending on the chosen option for the inclusion/exclusion mode.<br />You may separate the different entries by commas, spaces or newlines."),
1456 * get excluded paths - so we can have normal textareas too
1457 * split the phrase by any number of commas or space characters,
1458 * which include " ", \r, \t, \n and \f
1460 $form['fckeditor_exclude_settings']['excl_paths'] = array(
1461 '#type' => 'textarea',
1462 '#title' => t('Paths to exclude/include'),
1463 '#prefix' => '<div style="margin-left:20px">',
1464 '#suffix' => '</div>',
1467 '#default_value' => !empty($edit->settings
['excl_paths']) ?
$edit->settings
['excl_paths'] : '',
1468 '#description' => t("Enter drupal paths here, depending on the chosen option for the inclusion/exclusion mode.<br />Paths may be used the same way as in the drupal blocks configuration.<br />You may separate the different entries by commas, spaces or newlines. <br />You may also use * as a wildcard character (for example <code>comment/*</code>)."),
1471 $form['fckeditor_exclude_settings']['simple_incl_fields'] = array(
1472 '#type' => 'textarea',
1473 '#title' => t('Force simplified toolbar on the following fields'),
1476 '#default_value' => !empty($edit->settings
['simple_incl_fields']) ?
$edit->settings
['simple_incl_fields'] : '',
1477 '#description' => t("Enter names (HTML ID's) of fields that should have the simplified toolbar.<br />If you don't want to use this feature, simply leave this field empty.<br />You may separate the different entries by commas, spaces or newlines."),
1480 $form['fckeditor_exclude_settings']['simple_incl_paths'] = array(
1481 '#type' => 'textarea',
1482 '#title' => t('Force simplified toolbar on the following paths'),
1485 '#default_value' => !empty($edit->settings
['simple_incl_paths']) ?
$edit->settings
['simple_incl_paths'] : '',
1486 '#description' => t("Enter drupal paths that should have the simplified toolbar.<br />If you don't want to use this feature, simply leave this field empty.<br />Paths may be used the same way as in the drupal blocks configuration.<br />You may separate the different entries by commas, spaces or newlines.<br />You may also use * as a wildcard character (for example <code>comment/*</code>)."),
1489 $form['submit'] = array(
1490 '#type' => 'submit',
1498 * Return an HTML form for profile configuration.
1500 function fckeditor_profile_form_build($sth, $edit) {
1501 $edit = (object) $edit;
1503 $toolbar_options = fckeditor_load_toolbar_options();
1504 $skin_options = fckeditor_load_skin_options();
1505 $lang_options = fckeditor_load_lang_options();
1507 // Only display the roles that currently don't have a fckeditor profile. One
1508 // profile per role.
1509 $orig_roles = user_roles(FALSE
, 'access fckeditor');
1510 $roles = $orig_roles;
1512 if (!empty($edit->rids
) && !user_roles(false
, 'access fckeditor')) {
1513 drupal_set_message(t('You haven\'t assigned <code>!access1</code> !permissions yet.<br/>It is recommended to assign the <code>!access1</code> !permissions before updating FCKeditor profiles.',
1515 '!access1' => t('access fckeditor'),
1516 '!permissions' => l(t('permissions'), 'admin/user/permissions'))), 'warning');
1519 if (arg(3) == 'add') {
1520 drupal_set_breadcrumb(array(l(t('administer'), 'admin'), l(t('fckeditor'), 'admin/settings/fckeditor'), l(t('Add new FCKeditor profile'), 'admin/settings/fckeditor/add')));
1522 $result = db_query('SELECT DISTINCT(rid) FROM {fckeditor_role}');
1523 while ($data = db_fetch_object($result)) {
1524 if ((empty($edit->rids
) || !in_array($data->rid
, array_keys((array) $edit->rids
))) && !form_get_errors()) {
1525 unset($roles[$data->rid
]);
1528 if (count($orig_roles) != count($roles)) {
1529 drupal_set_message(t('Not all user roles are shown since they already have fckeditor profiles. You must first unassign profiles in order to add them to a new one.'));
1531 $btn = t('Create profile');
1534 $form['old_name'] = array('#type' => 'hidden', '#value' => $edit->name
);
1535 $btn = t('Update profile');
1538 $form['basic'] = array(
1539 '#type' => 'fieldset',
1540 '#title' => t('Basic setup'),
1541 '#collapsible' => TRUE
,
1542 '#collapsed' => TRUE
1545 $form['basic']['name'] = array(
1546 '#type' => 'textfield',
1547 '#title' => t('Profile name'),
1548 '#default_value' => !empty($edit->name
) ?
$edit->name
: "",
1550 '#maxlength' => 128,
1551 '#description' => t('Enter a name for this profile. This name is only visible within the fckeditor administration page.'),
1555 $form['basic']['rids'] = array(
1556 '#type' => 'checkboxes',
1557 '#title' => t('Roles allowed to use this profile'),
1558 '#default_value' => !empty($edit->rids
) ?
array_keys((array) $edit->rids
) : array(),
1559 '#options' => $roles,
1560 '#description' => t('Only roles with \'!access1\' permission will be shown here. If no role is available, make sure that you have assigned the \'!access1\' !permission.', array('!access1' => t('access fckeditor'), '!permission' => l(t("permission"), "admin/user/permissions"))),
1564 $form['basic']['allow_user_conf'] = array(
1565 '#type' => 'select',
1566 '#title' => t('Allow users to customize FCKeditor appearance'),
1567 '#default_value' => !empty($edit->settings
['allow_user_conf']) ?
$edit->settings
['allow_user_conf'] : 'f',
1568 '#options' => array('f' => t('false'), 't' => t('true')),
1569 '#description' => t('If allowed, users will be able to override <code>Editor appearance</code> by visiting their profile page.'),
1572 $form['security'] = array(
1573 '#type' => 'fieldset',
1574 '#title' => t('Security'),
1575 '#description' => t('Because Drupal stores content in an unmodified form, it is necessary to perform additional security checks before passing any unsafe value to FCKeditor. Without XSS filters, when you decide to edit an article which contains malformed data, any malicious code will be executed by your browser. You don\'t need to turn those filters on for users that are editing only their own content. However, unless you trust all your users, it is strongly advised to enable XSS filters for all accounts that can edit other\'s nodes (e.g. administrators, moderators).'),
1576 '#collapsible' => TRUE
,
1577 '#collapsed' => TRUE
1580 $form['security']['xss'] = array(
1581 '#type' => 'radios',
1582 '#title' => t('XSS filter'),
1583 '#default_value' => isset($edit->settings
['xss']) ?
$edit->settings
['xss'] : '1',
1584 '#options' => array(
1585 '2' => t('Enable XSS filter on all textareas replaced by FCKeditor'),
1586 '1' => t('Enable XSS filter only on textareas associated with HTML filter'),
1587 '0' => t('Disable XSS filter'),
1589 '#description' => t('Choose on which textareas FCKeditor should call a XSS filter before displaying it. Note that original user\'s data will be altered to protect you against hacking attempts. If you decide to disable XSS filter completely, it is advised to disable FCKeditor by default and manually check if HTML code is secure before switching to FCKeditor.'),
1592 $form['security']['xss_t'] = array(
1593 '#type' => 'radios',
1594 '#title' => t('XSS filter settings'),
1595 '#default_value' => isset($edit->settings
['xss_t']) ?
$edit->settings
['xss_t'] : '1',
1596 '#options' => array(
1597 '2' => t('Always run XSS filter when FCKeditor is loaded for the first time.'),
1598 '1' => t('Run XSS filter only when FCKeditor starts automatically.'),
1600 '#description' => t('Applies only if XSS filter is enabled above. If you decide to run XSS filter when FCKeditor starts automatically, you\'ll not be protected when toggling manually from plain textarea to FCKeditor or when using FCKeditor in a popup mode. You may choose this option if you can detect XSS by yourself just by looking at the HTML code.'),
1603 $form['fckeditor_exclude_settings'] = array(
1604 '#type' => 'fieldset',
1605 '#title' => t('Visibility settings'),
1606 '#collapsible' => TRUE
,
1607 '#collapsed' => TRUE
,
1610 $form['fckeditor_exclude_settings']['min_rows'] = array(
1611 '#type' => 'textfield',
1612 '#title' => t('Minimum rows'),
1613 '#default_value' => !empty($edit->settings
['min_rows']) ?
$edit->settings
['min_rows'] : '5',
1614 '#description' => t("FCKeditor will be triggered if the textarea has more rows than entered here. Enter '1' if you do not want to use this feature."),
1617 $form['fckeditor_exclude_settings']['excl_mode'] = array(
1618 '#type' => 'select',
1619 '#title' => t('Use inclusion or exclusion mode'),
1620 '#default_value' => (empty($edit->settings
['excl_mode']) || in_array($edit->settings
['excl_mode'], array(0, 2))) ?
0 : 1,
1621 '#options' => array('0' => t('exclude'), '1' => t('include')),
1622 '#description' => t('Choose the way of disabling/enabling FCKeditor on selected fields/paths (see below). Use exclude to disable FCKeditor on selected fields/paths. Use include if you want to load FCKeditor only on selected paths/fields.'),
1626 * get excluded fields - so we can have normal textareas too
1627 * split the phrase by any number of commas or space characters,
1628 * which include " ", \r, \t, \n and \f
1630 $form['fckeditor_exclude_settings']['excl_fields'] = array(
1631 '#type' => 'textarea',
1632 '#title' => t('Fields to exclude/include'),
1635 '#prefix' => '<div style="margin-left:20px">',
1636 '#suffix' => '</div>',
1637 '#default_value' => !empty($edit->settings
['excl_fields']) ?
$edit->settings
['excl_fields'] : '',
1638 '#description' => t("Enter names (HTML ID's) of fields that may or may not have an FCKeditor, depending on the chosen option for the inclusion/exclusion mode.<br />You may separate the different entries by commas, spaces or newlines."),
1642 * get excluded paths - so we can have normal textareas too
1643 * split the phrase by any number of commas or space characters,
1644 * which include " ", \r, \t, \n and \f
1646 $form['fckeditor_exclude_settings']['excl_paths'] = array(
1647 '#type' => 'textarea',
1648 '#title' => t('Paths to exclude/include'),
1649 '#prefix' => '<div style="margin-left:20px">',
1650 '#suffix' => '</div>',
1653 '#default_value' => !empty($edit->settings
['excl_paths']) ?
$edit->settings
['excl_paths'] : '',
1654 '#description' => t("Enter drupal paths here, depending on the chosen option for the inclusion/exclusion mode.<br />Paths may be used the same way as in the drupal blocks configuration.<br />You may separate the different entries by commas, spaces or newlines. <br />You may also use * as a wildcard character (for example <code>comment/*</code>)."),
1657 $form['fckeditor_exclude_settings']['simple_incl_fields'] = array(
1658 '#type' => 'textarea',
1659 '#title' => t('Force simplified toolbar on the following fields'),
1662 //'#prefix' => t('Here you can define where FCKeditor should force the <code>!simple</code> toolbar.<br/>Useful for smaller textareas where we usually don\'t use very complicated HTML code, like in signatures.', array('!simple' => FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME)),
1663 '#default_value' => !empty($edit->settings
['simple_incl_fields']) ?
$edit->settings
['simple_incl_fields'] : '',
1664 '#description' => t("Enter names (HTML ID's) of fields that should have the simplified toolbar.<br />If you don't want to use this feature, simply leave this field empty.<br />You may separate the different entries by commas, spaces or newlines."),
1667 $form['fckeditor_exclude_settings']['simple_incl_paths'] = array(
1668 '#type' => 'textarea',
1669 '#title' => t('Force simplified toolbar on the following paths'),
1672 //'#prefix' => t('Here you can define where FCKeditor should force the <code>!simple</code> toolbar.<br/>Useful for smaller textareas where we usually don\'t use very complicated HTML code, like in signatures.', array('!simple' => FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME)),
1673 '#default_value' => !empty($edit->settings
['simple_incl_paths']) ?
$edit->settings
['simple_incl_paths'] : '',
1674 '#description' => t("Enter drupal paths that should have the simplified toolbar.<br />If you don't want to use this feature, simply leave this field empty.<br />Paths may be used the same way as in the drupal blocks configuration.<br />You may separate the different entries by commas, spaces or newlines.<br />You may also use * as a wildcard character (for example <code>comment/*</code>)."),
1677 $form['appearance'] = array(
1678 '#type' => 'fieldset',
1679 '#title' => t('Editor appearance'),
1680 '#collapsible' => TRUE
,
1681 '#collapsed' => TRUE
,
1684 $form['appearance']['default'] = array(
1685 '#type' => 'select',
1686 '#title' => t('Default state'),
1687 '#default_value' => !empty($edit->settings
['default']) ?
$edit->settings
['default'] : 't',
1688 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
1689 '#description' => t('Default editor state. If disabled, rich text editor may still be enabled using toggle or popup window.'),
1692 $form['appearance']['show_toggle'] = array(
1693 '#type' => 'select',
1694 '#title' => t('Show disable/enable rich text editor toggle'),
1695 '#default_value' => !empty($edit->settings
['show_toggle']) ?
$edit->settings
['show_toggle'] : 't',
1696 '#options' => array('t' => t('true'), 'f' => t('false')),
1697 '#description' => t('Whether or not to show the disable/enable rich text editor toggle below the textarea. Works only if FCKeditor is not running in a popup window (see below).'),
1700 $form['appearance']['popup'] = array(
1701 '#type' => 'select',
1702 '#title' => t('Use FCKeditor in a popup window'),
1703 '#default_value' => !empty($edit->settings
['popup']) ?
$edit->settings
['popup'] : 'f',
1704 '#options' => array('f' => t('false'), 't' => t('true')),
1705 '#description' => t('If this option is enabled a link to a popup window will be used instead of a textarea replace.'),
1708 $form['appearance']['skin'] = array(
1709 '#type' => 'select',
1710 '#title' => t('Skin'),
1711 '#default_value' => !empty($edit->settings
['skin']) ?
$edit->settings
['skin'] : 'default',
1712 '#options' => $skin_options,
1713 '#description' => t('Choose a default skin.'),
1716 $form['appearance']['toolbar'] = array(
1717 '#type' => 'select',
1718 '#title' => t('Toolbar'),
1719 '#default_value' => !empty($edit->settings
['toolbar']) ?
$edit->settings
['toolbar'] : 'default',
1720 '#options' => $toolbar_options,
1721 '#description' => t('Choose a default toolbar set. To define new toolbar, edit <code>fckeditor.config.js</code> located in !module_path.', array('!module_path' => drupal_get_path('module', 'fckeditor'))),
1724 $form['appearance']['expand'] = array(
1725 '#type' => 'select',
1726 '#title' => t('Start the toolbar expanded'),
1727 '#default_value' => !empty($edit->settings
['expand']) ?
$edit->settings
['expand'] : 't',
1728 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
1729 '#description' => t('The toolbar start expanded or collapsed.'),
1732 $form['appearance']['width'] = array(
1733 '#type' => 'textfield',
1734 '#title' => t('Width'),
1735 '#default_value' => !empty($edit->settings
['width']) ?
$edit->settings
['width'] : '100%',
1736 '#description' => t("Width in pixels or percent. Ex: 400 or 100%"),
1738 '#maxlength' => 128,
1741 $form['appearance']['lang'] = array(
1742 '#type' => 'select',
1743 '#title' => t('Language'),
1744 '#default_value' => !empty($edit->settings
['lang']) ?
$edit->settings
['lang'] : 'en',
1745 '#options' => $lang_options,
1746 '#description' => t('The language for the FCKeditor interface.')
1749 $form['appearance']['auto_lang'] = array(
1750 '#type' => 'select',
1751 '#title' => t('Auto-detect language'),
1752 '#default_value' => !empty($edit->settings
['auto_lang']) ?
$edit->settings
['auto_lang'] : 't',
1753 '#options' => array('t' => t('true'), 'f' => t('false')),
1754 '#description' => t('Use auto detect user language feature.')
1758 $form['appearance']['appearance_conf'] = array(
1759 '#type' => 'select',
1760 '#title' => t('Ignore this section, use default settings defined in config files'),
1761 '#default_value' => $edit->settings['appearance_conf'] ? $edit->settings['appearance_conf'] : 'f',
1762 '#options' => array('f' => t('false'), 't' => t('true')),
1763 '#description' => t('Although it is less handy, defining settings only in config files (<code>fckconfig.js</code> and <code>fckeditor.config.js</code>) will slightly leverage your traffic and improve load time of your site. <br/>Warning: if set to true, all changes made in <code>Editor appearance</code> will have no affect on FCKeditor\'s behaviour.'),
1767 $form['output'] = array(
1768 '#type' => 'fieldset',
1769 '#title' => t('Cleanup and output'),
1770 '#collapsible' => TRUE
,
1771 '#collapsed' => TRUE
,
1774 $form['output']['enter_mode'] = array(
1775 '#type' => 'select',
1776 '#title' => t('Enter mode'),
1777 '#default_value' => !empty($edit->settings
['enter_mode']) ?
$edit->settings
['enter_mode'] : 'p',
1778 '#options' => array('p' => '<p>', 'br' => '<br>', 'div' => '<div>'),
1779 '#description' => t('Set which tag FCKeditor should use when [Enter] key is pressed.')
1782 $form['output']['shift_enter_mode'] = array(
1783 '#type' => 'select',
1784 '#title' => t('Shift + Enter mode'),
1785 '#default_value' => !empty($edit->settings
['shift_enter_mode']) ?
$edit->settings
['shift_enter_mode'] : 'br',
1786 '#options' => array('p' => '<p>', 'br' => '<br>', 'div' => '<div>'),
1787 '#description' => t('Set which tag FCKeditor should use when [Shift] + [Enter] is pressed.')
1790 $form['output']['font_format'] = array(
1791 '#type' => 'textfield',
1792 '#title' => t('Font formats'),
1793 '#default_value' => !empty($edit->settings
['font_format']) ?
$edit->settings
['font_format'] : 'p;div;pre;address;h1;h2;h3;h4;h5;h6',
1795 '#maxlength' => 250,
1796 '#description' => t('Semicolon separated list of HTML font formats. Allowed values are: p;div;pre;address;h1;h2;h3;h4;h5;h6'),
1799 $form['output']['format_source'] = array(
1800 '#type' => 'select',
1801 '#title' => t('Apply source formatting'),
1802 '#default_value' => !empty($edit->settings
['format_source']) ?
$edit->settings
['format_source'] : 't',
1803 '#options' => array('t' => t('true'), 'f' => ('false')),
1804 '#description' => t('When set to "true" the editor will format the XHTML when switching from WYSIWYG view to Source view, by inserting line breaks on some tags endings and indenting paragraphs, tables and lists.'),
1807 $form['output']['format_output'] = array(
1808 '#type' => 'select',
1809 '#title' => t('Format output'),
1810 '#default_value' => !empty($edit->settings
['format_output']) ?
$edit->settings
['format_output'] : 't',
1811 '#options' => array('t' => t('true'), 'f' => t('false')),
1812 '#description' => t('When set to "true" the editor will format the XHTML output by inserting line breaks on some tags endings and indenting paragraphs, tables and lists.'),
1816 $form['output']['output_conf'] = array(
1817 '#type' => 'select',
1818 '#title' => t('Ignore this section, use default settings defined in config files'),
1819 '#default_value' => $edit->settings['output_conf'] ? $edit->settings['output_conf'] : 'f',
1820 '#options' => array('f' => t('false'), 't' => t('true')),
1821 '#description' => t('Although it is less handy, defining settings only in config files (<code>fckconfig.js</code> and <code>fckeditor.config.js</code>) will slightly leverage your traffic and improve load time of your site. <br/>Warning: if set to true, all changes made in <code>Cleanup and output</code> will have no affect on FCKeditor\'s behaviour.'),
1825 $form['css'] = array(
1826 '#type' => 'fieldset',
1827 '#title' => t('CSS'),
1828 '#collapsible' => TRUE
,
1829 '#collapsed' => TRUE
1832 $form['css']['css_mode'] = array(
1833 '#type' => 'select',
1834 '#title' => t('Editor CSS'),
1835 '#default_value' => !empty($edit->settings
['css_mode']) ?
$edit->settings
['css_mode'] : 'theme',
1836 '#options' => array('theme' => t('use theme css'), 'self' => t('define css'), 'none' => t('FCKeditor default')),
1837 '#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 />FCKeditor default - uses default CSS from editor.')
1840 $form['css']['css_path'] = array(
1841 '#type' => 'textfield',
1842 '#title' => t('CSS path'),
1843 '#default_value' => !empty($edit->settings
['css_path']) ?
$edit->settings
['css_path'] : "",
1845 '#maxlength' => 255,
1846 '#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://example.com/style.css</em>).<br />Macros: %h (host name: !host), %t (path to theme: !theme)<br />Be sure to select "define css" above.', array('!host' => base_path(), '!theme' => base_path() .
path_to_theme() .
'/'))
1849 $form['css']['css_style'] = array(
1850 '#type' => 'select',
1851 '#title' => t('Predefined styles'),
1852 '#default_value' => !empty($edit->settings
['css_style']) ?
$edit->settings
['css_style'] : 'theme',
1853 '#options' => array('theme' => t('use theme fckstyles.xml'), 'self' => t('define path to fckstyles.xml'), 'default' => t('FCKeditor default')),
1854 '#description' => t('Define the location of <code>fckstyles.xml</code> file. It is used by the "Style" dropdown list available in the Default toolbar.<br />Copy !fckstyles.xml inside your theme directory (<code>!theme</code>) and adjust it to your needs.', array('!fckstyles.xml' => drupal_get_path('module', 'fckeditor') .
'/fckeditor/fckstyles.xml', '!theme' => path_to_theme() .
'/fckstyles.xml'))
1857 $form['css']['styles_path'] = array(
1858 '#type' => 'textfield',
1859 '#title' => t('Predefined styles path'),
1860 '#default_value' => !empty($edit->settings
['styles_path']) ?
$edit->settings
['styles_path'] : "",
1862 '#maxlength' => 255,
1863 '#description' => t('Enter path to XML file with predefined styles (<em>example: /fckstyles.xml</em>).<br />Macros: %h (host name: !host), %t (path to theme: !theme), %m (path to FCKeditor module: !module)<br />Be sure to select "define path to fckstyles.xml" above.', array('!host' => base_path(), '!theme' => base_path() .
path_to_theme() .
'/', '!module' => drupal_get_path('module', 'fckeditor')))
1866 $form['fckeditor_upload_settings'] = array(
1867 '#type' => 'fieldset',
1868 '#title' => t('File browser settings'),
1869 '#collapsible' => TRUE
,
1870 '#collapsed' => TRUE
,
1871 '#description' => t('Set file browser settings. A file browser will allow you to explore the files contained on the server and embed them as links, images or flash movies. Besides the built-in FCKeditor file browser, you can also use a contributed module like !imce. The quick upload setting controls whether images, flash movies and files can be uploaded using the Upload tab of the respective dialogs. Please note that these options require manual configuration, check !readme for more information.<br />',
1873 '!imce' => l(t('IMCE'), 'http://drupal.org/project/imce'),
1874 '!readme' => l('readme.txt', 'admin/help/fckeditor'),
1879 $filebrowsers = array(
1880 'none' => t('None'),
1881 'builtin' => t('Built-in filebrowser'),
1884 if (module_exists('imce')) {
1885 $filebrowsers['imce'] = t('IMCE');
1888 $form['fckeditor_upload_settings']['filebrowser'] = array(
1889 '#type' => 'select',
1890 '#options' => $filebrowsers,
1891 '#title' => t('File browser type'),
1892 '#default_value' => !empty($edit->settings
['filebrowser']) ?
$edit->settings
['filebrowser'] : 'none',
1893 '#description' => t('Select the file browser that you would like to use to upload files, images and flash movies.'),
1896 $form['fckeditor_upload_settings']['quickupload'] = array(
1897 '#type' => 'select',
1898 '#options' => array('f' => t('false'), 't' => t('true')),
1899 '#title' => t('Allow quick uploads'),
1900 '#default_value' => !empty($edit->settings
['quickupload']) ?
$edit->settings
['quickupload'] : 'f',
1901 '#description' => t('The quick upload functionality can be disabled and enabled independently of the file browser. It will always use the settings below.'),
1904 $current_user_files_path = empty($edit->settings
['UserFilesPath']) ?
"" : strtr($edit->settings
['UserFilesPath'], array("%f" => file_directory_path(), "%u" => "UID", "%b" => base_path()));
1905 $current_user_files_absolute_path = empty($edit->settings
['UserFilesAbsolutePath']) ?
"" : strtr($edit->settings
['UserFilesAbsolutePath'], array("%f" => file_directory_path(), "%u" => "UID", "%b" => base_path(), "%d" => $_SERVER['DOCUMENT_ROOT']));
1907 $form['fckeditor_upload_settings']['UserFilesPath'] = array(
1908 '#type' => 'textfield',
1909 '#title' => t('Path to uploaded files'),
1910 '#default_value' => !empty($edit->settings
['UserFilesPath']) ?
$edit->settings
['UserFilesPath'] : "%b%f/",
1912 '#maxlength' => 255,
1913 '#description' => t('Path to uploaded files relative to the document root.<br />Available wildcard characters:<br/><strong>%b</strong> - base URL path of the Drupal installation (!base).<br/><strong>%f</strong> - Drupal file system path where the files are stored (!files).<br /><strong>%u</strong> - User ID.<br />Current path: !path', array('!path' => $current_user_files_path, '!files' => file_directory_path(), '!base' => base_path())),
1916 $form['fckeditor_upload_settings']['UserFilesAbsolutePath'] = array(
1917 '#type' => 'textfield',
1918 '#title' => t('Absolute path to uploaded files'),
1919 '#default_value' => !empty($edit->settings
['UserFilesAbsolutePath']) ?
$edit->settings
['UserFilesAbsolutePath'] : "%d%b%f/",
1921 '#maxlength' => 255,
1922 '#description' => t('The path to the local directory (in the server) which points to the path defined above. If empty, FCKeditor will try to discover the right path.<br />Available wildcard characters:<br/><strong>%d</strong> - server path to document root (!root).<br /><strong>%b</strong> - base URL path of the Drupal installation (!base).<br/><strong>%f</strong> - Drupal file system path where the files are stored (!files).<br /><strong>%u</strong> - User ID.<br />Current path: !path', array('!path' => $current_user_files_absolute_path, '!files' => file_directory_path(), '!base' => base_path(), '!root' => $_SERVER['DOCUMENT_ROOT'])),
1925 if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE
) {
1926 $form['fckeditor_upload_settings']['UserFilesPath']['#description'] = t('Setting relative path to uploaded files has been disabled because private downloads are enabled and this path is calculated automatically.');
1927 $form['fckeditor_upload_settings']['UserFilesPath']['#disabled'] = TRUE
;
1928 $form['fckeditor_upload_settings']['UserFilesAbsolutePath']['#description'] = t('Setting path to uploaded files has been disabled because private downloads are enabled and this path is calculated automatically.');
1929 $form['fckeditor_upload_settings']['UserFilesAbsolutePath']['#disabled'] = TRUE
;
1932 $form['advanced'] = array(
1933 '#type' => 'fieldset',
1934 '#title' => t('Advanced options'),
1935 '#collapsible' => TRUE
,
1936 '#collapsed' => TRUE
,
1938 $form['advanced']['js_conf'] = array(
1939 '#type' => 'textarea',
1940 '#title' => t('Custom javascript configuration'),
1941 '#default_value' => !empty($edit->settings
['js_conf']) ?
$edit->settings
['js_conf'] : "",
1944 '#description' => t('Warning: to change FCKeditor configuration globally, you should modify the config file: <code>!fckeditor_config</code>.<br/>Sometimes it is required to change the FCKeditor configuration for selected profile. Use this box to define settings that are uniqe for this profile.<br/>Available options are listed in the !docs.<br/>Warning: if you make something wrong here, FCKeditor may fail to load.<br/>For example to disable some advanced tabs in dialog windows in FCKeditor, add the following: !example',
1946 '!fckeditor_config' => drupal_get_path('module', 'fckeditor') .
"/fckeditor.config.js",
1947 '!docs' => l(t("FCKeditor documentation"), "http://docs.fckeditor.net/FCKeditor_2.x/Developers_Guide/Configuration/Configuration_Options"),
1948 "!example" => "<pre>LinkDlgHideTarget = true ;
1949 LinkDlgHideAdvanced = true ;
1950 ImageDlgHideLink = true ;
1951 ImageDlgHideAdvanced = true ;
1952 FlashDlgHideAdvanced = true ;</pre>")
1955 $form['submit'] = array(
1956 '#type' => 'submit',
1964 * Search the field id for matches in array of matches
1967 * A string representing a form field id
1969 * An $array with strings to match the $search parameter against
1972 * TRUE on match, FALSE on no match
1974 function fckeditor_idsearch($search, $array) {
1975 foreach ($array as
$key => $value) {
1976 if (!empty($value) && preg_match('/^'.
str_replace('*', '.*', addslashes($value)) .
'$/i', $search)) {
1977 // on any first match we know we're done here so return positive
1985 * Test if client can render the FCKeditor
1986 * Use built-in test method in fckeditor.php
1987 * If fckeditor.php is not found, return false (probably in such case fckeditor is not installed correctly)
1990 * TRUE if the browser is reasonably capable
1992 function fckeditor_is_compatible_client() {
1994 $fckeditor_main_file = drupal_get_path('module', 'fckeditor') .
'/fckeditor/fckeditor.php';
1995 if (file_exists($fckeditor_main_file)) {
1996 include_once
$fckeditor_main_file;
1997 if (function_exists('FCKeditor_IsCompatibleBrowser')) {
1998 return FCKeditor_IsCompatibleBrowser();
2001 $fck = new
FCKeditor("fake");
2002 return $fck->IsCompatible();
2009 function fckeditor_user_get_setting($user, $profile, $setting) {
2012 'show_toggle' => 't',
2014 'skin' => 'default',
2015 'toolbar' => 'default',
2021 $settings = $profile->settings
;
2023 if ($settings['allow_user_conf']) {
2024 $status = isset($user->{"fckeditor_".
$setting}) ?
$user->{"fckeditor_".
$setting} : (isset($settings[$setting]) ?
$settings[$setting] : $default[$setting]);
2027 $status = isset($settings[$setting]) ?
$settings[$setting] : $default[$setting];
2033 function fckeditor_user_get_profile($user) {
2034 static
$profile_name;
2036 // Since fckeditor_profile_load() makes a db hit, only call it when we're pretty sure
2037 // we're gonna render fckeditor.
2038 if (!isset($profile_name[$user->uid
])) {
2039 $sorted_roles = fckeditor_sorted_roles();
2040 foreach ($sorted_roles as
$rid => $name) {
2041 if (isset($user->roles
[$rid])) {
2046 if (isset($rid) && isset($user->roles
[$rid])) {
2047 $profile_name[$user->uid
] = db_result(db_query("SELECT s.name FROM {fckeditor_settings} s INNER JOIN {fckeditor_role} r ON r.name = s.name WHERE r.rid='%s'", $rid));
2049 else if ($user->uid
== "1") {
2050 $profile_name[$user->uid
] = db_result(db_query_range("SELECT s.name FROM {fckeditor_settings} s INNER JOIN {fckeditor_role} r ON r.name = s.name ORDER BY r.rid DESC", 1));
2054 if (isset($profile_name[$user->uid
]) && $profile_name[$user->uid
]) {
2055 $profile = fckeditor_profile_load($profile_name[$user->uid
]);
2062 function fckeditor_init() {
2063 drupal_add_css(drupal_get_path('module', 'fckeditor') .
'/fckeditor.css');
2066 function fckeditor_ask_delete_confirmation($is_global, $profile = "") {
2068 $delete_link = l(t('Yes, delete!'), 'admin/settings/fckeditor/deleteconfirmed/'.
urlencode($profile));
2069 $profile_name = t('!profile profile', array('!profile' => $profile));
2072 $delete_link = l(t('Yes, delete!'), 'admin/settings/fckeditor/deletegconfirmed');
2073 $profile_name = t('Global Profile');
2076 drupal_set_title(t('Confirm profile deletion'));
2077 drupal_set_message(t("You're about to delete the FCKeditor profile, read the question below carefully."), "warning");
2079 return t("<p>Are you sure that you want to delete the !profile?</p><p>!yes !no</p>",
2080 array('!profile' => $profile_name,
2081 '!yes' => $delete_link,
2082 '!no' => l(t('Cancel'), 'admin/settings/fckeditor', array('attributes' => array('style' => 'margin-left:40px'))),
2087 * Implementation of hook_file_download().
2088 * Support for private downloads.
2090 function fckeditor_file_download($file) {
2091 if (module_exists('imce') && variable_get('imce_settings_fck', 0)) {
2094 if (module_exists('upload')) {
2095 $result = db_query("SELECT f.* FROM {files} f WHERE filepath = '%s'", $file);
2096 if (db_fetch_object($result)) {
2100 //it is probably file uploaded with FCKeditor
2101 if ($path = file_create_path($file)) {
2102 $ctype = ($info = @
getimagesize($path)) ?
$info['mime'] : (function_exists('mime_content_type') ?
mime_content_type($path) : 'application/x-download');
2103 return array('Content-type: '.
$ctype);