Removing translation directories
[project/fckeditor.git] / fckeditor.module
CommitLineData
04b827fa 1<?php
c01081e7 2/**
0c87a920
WW
3 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
4 * Copyright (C) 2003-2007 Frederico Caldeira Knabben
ebc6fdec 5 *
0c87a920 6 * == BEGIN LICENSE ==
9b429add 7 *
0c87a920
WW
8 * Licensed under the terms of any of the following licenses at your
9 * choice:
f3d88ca0 10 *
0c87a920
WW
11 * - GNU General Public License Version 2 or later (the "GPL")
12 * http://www.gnu.org/licenses/gpl.html
9b429add 13 *
0c87a920
WW
14 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
15 * http://www.gnu.org/licenses/lgpl.html
ebc6fdec 16 *
0c87a920
WW
17 * - Mozilla Public License Version 1.1 or later (the "MPL")
18 * http://www.mozilla.org/MPL/MPL-1.1.html
ebc6fdec 19 *
0c87a920 20 * == END LICENSE ==
9b429add 21 *
0c87a920
WW
22 * @file
23 * FCKeditor Module for Drupal 5.x
24 *
25 * This module allows Drupal to replace textarea fields with FCKeditor.
04b827fa 26 *
0c87a920
WW
27 * This HTML text editor brings to the web many of the powerful functionalities
28 * of known desktop editors like Word. It's really lightweight and doesn't
29 * require any kind of installation on the client computer.
04b827fa
DS
30 */
31
0c87a920
WW
32/**
33 * The name of simplified toolbar which should be forced
34 * Be sure that this toolbar is defined in fckeditor.config.js or fckconfig.js
35 */
36define('FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME', 'DrupalBasic') ;
04b827fa
DS
37
38/**
39 * Implementation of hook_help
40 */
0c87a920 41function fckeditor_help($path, $arg) {
c01081e7
WW
42 if (strpos($path, 'admin/settings/fckeditor/edit/') === 0 || $path == 'admin/settings/fckeditor/add') {
43 $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"));
44 }
45
0c87a920 46 switch ($path) {
9b429add 47 case 'admin/settings/help#description':
e44c2389 48 $output = t("Enables the usage of FCKeditor (WYSIWYG editor) instead of plain text fields.");
49 break;
c01081e7
WW
50 case 'admin/settings/fckeditor/addg':
51 case 'admin/settings/fckeditor/editg':
52 $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>");
0c87a920 53 break;
31a6dbc3 54 case 'admin/settings/fckeditor':
c01081e7 55 $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>",
0c87a920
WW
56 array(
57 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net'),
c01081e7 58 '!userguidelink' => l(t('FCKeditor userguide'), 'http://docs.fckeditor.net/FCKeditor/Users_Guide'))
0c87a920 59 );
c01081e7 60 $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')));
31a6dbc3 61 break;
e44c2389 62 case 'admin/help#fckeditor':
0c87a920
WW
63 $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>",
64 array(
65 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net'),
c01081e7 66 '!userguidelink' => l(t('FCKeditor userguide'), 'http://docs.fckeditor.net/FCKeditor/Users_Guide'))
0c87a920
WW
67 );
68 $output .= t('<h3>Installation</h3><p>Go to the !fckeditorlink and download the latest version. Then uncompress the contents of the "fckeditor" directory of the downloaded file to %fckeditordir.</p>',
69 array(
c01081e7 70 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net/download'),
0c87a920
WW
71 '%fckeditordir' => base_path() . drupal_get_path('module', 'fckeditor') .'/fckeditor/')
72 );
c01081e7 73 $output .= t('<h3>Configuration</h3><ol><li>Enable the module as usual from Drupal\'s admin pages.</li><li>Grant permissions for use of FCKeditor in <code>!path2</code></li><li>Under <code>!path1</code>, create 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 (modules/fckeditor/fckeditor/fckconfig.js), the lines in fckeditor.config.js will override most settings.</li></ol>',
0c87a920 74 array(
c01081e7
WW
75 '!path1' => l(t('Administer > Settings > FCKeditor'), 'admin/settings/fckeditor'),
76 '!path2' => l(t('Administer > User Management > Access Control'), 'admin/user/permissions'),
0c87a920
WW
77 '!filter' => htmlentities('<a> <p> <span> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area>
78 <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <tr> <td> <em>
79 <b> <u> <i> <strong> <font> <del> <ins> <sub> <sup> <quote> <blockquote>
80 <pre> <address> <code> <cite> <embed> <object> <strike> <caption>'),
c01081e7
WW
81 '!filterlink' => l(t('filters'), 'admin/settings/filters'))
82 );
83 $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>',
84 array(
85 '%fckeditordir' => base_path() . drupal_get_path('module', 'fckeditor') .'/fckeditor/')
0c87a920 86 );
c01081e7
WW
87 $output .= t('The correct directory structure is as follows: <blockquote><pre>!structure</pre></blockquote>', array(
88 '!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 ..."
89 ));
0c87a920
WW
90 $output .= t("<h3>Plugins: Teaser break and Pagebreak</h3><p>By default, FCKeditor module comes with two plugins that can handle teaser break (&lt;!--break--&gt;) and pagebreak (&lt;!--pagebreak--&gt;). 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>",
91 array(
c01081e7
WW
92 '!fckeditor.config.js' => base_path() . drupal_get_path('module', 'fckeditor') .'/fckeditor.config.js',
93 '!code' => "
94 FCKConfig.PluginsPath = '../../plugins/' ;
95 FCKConfig.Plugins.Add( 'drupalbreak' ) ;
96 FCKConfig.Plugins.Add( 'drupalpagebreak' ) ;
97 ",
98 '!buttons1' => "['Image','Flash','Table','Rule','SpecialChar']",
99 '!buttons2' => "['Image','Flash','Table','Rule','SpecialChar', 'DrupalBreak', 'DrupalPageBreak']",
0c87a920
WW
100 ));
101 $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>',
102 array(
103 '!imce' => l(t('IMCE'), 'http://drupal.org/project/imce')
104 )
105 );
e44c2389 106 // the rest is untranslated for the moment
c01081e7 107 $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>",
0c87a920
WW
108 array('!config1' => base_path() . drupal_get_path('module', 'fckeditor') ."/fckeditor/editor/filemanager/browser/default/connectors/php/config.php",
109 '!config2' => base_path() . drupal_get_path('module', 'fckeditor') ."/fckeditor/editor/filemanager/upload/php/config.php",
110 '!config3' => base_path() . drupal_get_path('module', 'fckeditor') ."/fckeditor/editor/filemanager/connectors/php/config.php",
111 '!filesdir' => file_directory_path(),
c01081e7
WW
112 '!code1' => 'require_once "../../../../../filemanager.config.php";', //2.5
113 '!code2' => 'require_once "'. str_replace("\\", "\\\\", dirname(__FILE__) . DIRECTORY_SEPARATOR .'filemanager.config.php"'), //2.4
114 '!code3' => "\$Config['UserFilesAbsolutePath'] = '' ;",
0c87a920 115 )
c01081e7
WW
116 );
117 $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>&#36;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>");
118 $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.</li>', array('!link' => l(t('separate permission'), 'admin/user/permissions')));
119 $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')));
5477dba0 120 //$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"));
0c87a920 121
e44c2389 122 break;
04b827fa
DS
123 }
124 return $output;
125}
126
04b827fa
DS
127/**
128 * Implementation of hook_perm
0c87a920 129 * Administer -> User management -> Access Control
04b827fa
DS
130 */
131function fckeditor_perm() {
0c87a920 132 return array('administer fckeditor', 'access fckeditor', 'allow fckeditor file uploads');
04b827fa
DS
133}
134
9b429add 135
04b827fa 136/**
9b429add 137 * Implementation of textarea
0c87a920 138 * Replace textarea with FCKeditor using callback function (fckeditor_process_textarea)
04b827fa 139 */
f3d88ca0 140function fckeditor_elements() {
141 $type = array();
0c87a920
WW
142 if (user_access('administer fckeditor')) {
143 $type['textfield'] = array(
144 '#process' => array(
145 'fckeditor_process_input'
146 ),
147 );
148 }
149 if (user_access('access fckeditor')) {
f3d88ca0 150 // only roles with permission get the fckeditor
151 if (fckeditor_is_compatible_client()) {
152 // it would be useless to dig deeper if we're not able or allowed to
153 $type['textarea'] = array(
0c87a920
WW
154 '#process' => array(
155 'fckeditor_process_textarea'
156 ),
f3d88ca0 157 );
04b827fa
DS
158 }
159 }
f3d88ca0 160 return $type;
04b827fa
DS
161}
162
0c87a920
WW
163/**
164 * Allow more than 255 chars in Allowed HTML tags textfield
165 *
166 */
167function fckeditor_process_input($element) {
168 if ($element['#id']=='edit-allowed-html-1') {
169 $element['#maxlength'] = max($element['#maxlength'], 1024);
9b429add 170 }
0c87a920 171 return $element;
9b429add 172}
173
0c87a920
WW
174/**
175 * Add link to FCKeditor configuration in "Administer -> Site configuration" section
176 *
177 */
178function fckeditor_menu() {
c01081e7 179
0c87a920 180 $items = array();
ebc6fdec 181
0c87a920 182 $items['admin/settings/fckeditor'] = array(
04b827fa 183
0c87a920
WW
184 'title' => t('FCKeditor'),
185 'description' => t('Configure the rich editor.'),
186 'page callback' => 'fckeditor_admin',
187 'access arguments' => array('administer fckeditor'),
188 'type' => MENU_NORMAL_ITEM,
f3d88ca0 189 );
0c87a920
WW
190
191 return $items;
192}
193
194//Remove a profile from the database.
195function fckeditor_profile_delete($name) {
196 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s'", $name);
197 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s'", $name);
198}
199
200/**
201 * Profile validation.
202 */
203function fckeditor_profile_validate($edit) {
204 $errors = array();
c01081e7
WW
205
206 if (!preg_match("/^\d+$/", trim($edit['min_rows']))) {
207 $errors['min_rows'] = t('Minimum rows must be a valid number');
208 }
209
210 if ($edit['default'] == 't' && $edit['popup'] == 't') {
211 $errors['popup'] = t('If FCKeditor is enabled by default, popup window must be disabled.');
212 }
213
214 if ($edit['show_toggle'] == 't' && $edit['popup'] == 't') {
215 $errors['popup'] = t('If toggle is enabled, popup window must be disabled.');
216 }
217
0c87a920
WW
218 if (!$edit['name']) {
219 $errors['name'] = t('You must give a profile name.');
220 }
221
c01081e7
WW
222 if (!preg_match("/^\d+%?$/", $edit['width'])) {
223 $errors['width'] = t('Enter valid width. Ex: 400 or 100%');
224 }
225
226 if (!empty($edit['css_path'])) {
227 if ($edit['css_mode'] != 'self') {
228 $errors['css_path'] = t('CSS path is not empty. Please set the "Editor CSS" option to "define css" mode.');
229 }
230 else if (false !== strpos($edit['css_path'], '"')) {
231 $errors['css_path'] = t('Double quotes are not allowed in CSS path.');
232 }
233 else if (substr($edit['css_path'], 0, 1) == "'" && substr($edit['css_path'], -1) == "'") {
234 $errors['css_path'] = t('Enter valid path, do not surround it with quotes.');
235 }
236 }
237
238 if (!empty($edit['styles_path'])) {
239 if ($edit['css_style'] != 'self') {
240 $errors['styles_path'] = t('Path to predefined styles is not empty. Please set the "Predefined styles" option to "define path to fckstyles.xml" mode.');
241 }
242 else if (false !== strpos($edit['styles_path'], '"')) {
243 $errors['styles_path'] = t('Double quotes are not allowed in path.');
244 }
245 else if (substr($edit['styles_path'], 0, 1) == "'" && substr($edit['styles_path'], -1) == "'") {
246 $errors['styles_path'] = t('Enter valid path, do not surround it with quotes.');
247 }
248 }
249
250 if (!empty($edit['font_format'])) {
251 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'])) {
252 $errors['font_format'] = t('Enter valid, semicolon separated, list of HTML font formats (no semicolon at the end of list expected).');
253 }
254 }
255
256 //validate fields
257 $fields = preg_split("/[\s,]+/", strip_tags($edit['excl_fields']));
258 foreach ($fields as $field) {
259 if ($field && !preg_match("/^[a-z]+(\-[a-z]+)+$/i", $field)) {
260 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
261 break;
262 }
263 }
264
265 $fields = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_fields']));
266 foreach ($fields as $field) {
267 if ($field && !preg_match("/^[a-z]+(\-[a-z]+)+$/i", $field)) {
268 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
269 break;
270 }
271 }
272
273 //validate paths
274 $paths = preg_split("/[\s,]+/", strip_tags($edit['excl_paths']));
275 foreach ($paths as $path) {
276 if ($path && !preg_match("|^[a-z0-9-\*/]*$|i", $path)) {
277 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
278 break;
279 }
280 }
281
282 $paths = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_paths']));
283 foreach ($paths as $path) {
284 if ($path && !preg_match("|^[a-z0-9-\*/]*$|i", $path)) {
285 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
286 break;
287 }
288 }
289
290 if ($edit['UserFilesAbsolutePath'] && !$edit['UserFilesPath']) {
291 $errors['UserFilesPath'] = t("Path to uploaded files is required.");
292 }
293 if ($edit['UserFilesPath'] && !$edit['UserFilesAbsolutePath']) {
294 $errors['UserFilesPath'] = t("Absolute path to uploaded files is required.");
0c87a920
WW
295 }
296
297 foreach ($errors as $name => $message) {
298 form_set_error($name, $message);
299 }
300
301 return count($errors) == 0;
ebc6fdec 302}
04b827fa 303
c01081e7
WW
304/**
305 * Global profile validation.
306 */
307function fckeditor_global_profile_validate($edit) {
308 $errors = array();
309
310 //validate fields
311 $fields = preg_split("/[\s,]+/", strip_tags($edit['excl_fields']));
312 foreach ($fields as $field) {
313 if ($field && !preg_match("/^[a-z]+(\-[a-z]+)+$/i", $field)) {
314 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
315 break;
316 }
317 }
318
319 $fields = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_fields']));
320 foreach ($fields as $field) {
321 if ($field && !preg_match("/^[a-z]+(\-[a-z]+)+$/i", $field)) {
322 $errors['excl_fields'] = t("Invalid field specified: %1", array("%1" => $field));
323 break;
324 }
325 }
326
327 //validate paths
328 $paths = preg_split("/[\s,]+/", strip_tags($edit['excl_paths']));
329 foreach ($paths as $path) {
330 if ($path && !preg_match("|^[a-z0-9-\*/]*$|i", $path)) {
331 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
332 break;
333 }
334 }
335
336 $paths = preg_split("/[\s,]+/", strip_tags($edit['simple_incl_paths']));
337 foreach ($paths as $path) {
338 if ($path && !preg_match("|^[a-z0-9-\*/]*$|i", $path)) {
339 $errors['excl_paths'] = t("Invalid path specified: %1", array("%1" => $path));
340 break;
341 }
342 }
343
344 foreach ($errors as $name => $message) {
345 form_set_error($name, $message);
346 }
347
348 return count($errors) == 0;
349}
04b827fa
DS
350
351/**
0c87a920
WW
352 * Controller for FCKeditor administrative settings.
353 */
354function fckeditor_admin($arg = NULL) {
355
c01081e7
WW
356 $module_drupal_path = drupal_get_path('module', 'fckeditor');
357 $fckconfig_file = $module_drupal_path .'/fckeditor/fckconfig.js';
0c87a920
WW
358 if (!file_exists($fckconfig_file)) {
359 drupal_set_message(t('checking for %filename', array('%filename' => $fckconfig_file)));
360 drupal_set_message(
c01081e7
WW
361 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.',
362 array(
363 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://www.fckeditor.net/download'),
364 '!readme' => l('readme.txt', 'admin/help/fckeditor'),
365 '%modulepath' => base_path() . $module_drupal_path .'/fckeditor/',
366 '%modulesubdir' => base_path() . $module_drupal_path .'/fckeditor/editor',
367 '%modulefile' => base_path() . $module_drupal_path .'/fckeditor/fckeditor.js')),
368 'error');
0c87a920
WW
369 return false;
370 }
371
372 $edit = $_POST;
c7d6f61d 373 $op = isset($_POST['op']) ? $_POST['op'] : "";
0c87a920
WW
374
375 $op = $arg && !$op ? $arg : $op;
376
377 switch ($op) {
378 case 'add':
0c87a920
WW
379 $output = fckeditor_profile_form($edit);
380 break;
381
c01081e7
WW
382 case 'addg':
383 $output = fckeditor_global_profile_form($edit);
384 break;
385
0c87a920
WW
386 case 'edit':
387 drupal_set_title(t('Edit FCKeditor profile'));
388 $output = fckeditor_profile_form(fckeditor_profile_load(urldecode(arg(4))));
389 break;
390
c01081e7
WW
391 case 'editg':
392 drupal_set_title(t('Edit FCKeditor profile'));
393 $output = fckeditor_global_profile_form(fckeditor_profile_load("FCKeditor Global Profile"));
394 break;
395
0c87a920
WW
396 case 'delete':
397 fckeditor_profile_delete(urldecode(arg(4)));
398 drupal_set_message(t('Deleted profile'));
399 drupal_goto('admin/settings/fckeditor');
400 break;
401
c01081e7 402 case 'deleteg':
354f0f04 403 fckeditor_profile_delete("FCKeditor Global Profile");
c01081e7
WW
404 drupal_set_message(t('Deleted Global profile'));
405 drupal_goto('admin/settings/fckeditor');
406 break;
407
0c87a920
WW
408 case t('Create profile');
409 case t('Update profile');
410 if (fckeditor_profile_validate($edit)) {
411 fckeditor_profile_save($edit);
412 $edit['old_name'] ? drupal_set_message(t('Your FCKeditor profile has been updated.')) : drupal_set_message(t('Your FCKeditor profile has been created.'));
413 drupal_goto('admin/settings/fckeditor');
414 }
415 else {
416 $output = fckeditor_profile_form($edit);
417 }
418 break;
419
c01081e7
WW
420 case t('Create global profile');
421 case t('Update global profile');
422 if (fckeditor_global_profile_validate($edit)) {
423 $edit['name'] = 'FCKeditor Global Profile';
424 fckeditor_global_profile_save($edit);
425 drupal_set_message(t('FCKeditor global profile has been saved.'));
426 drupal_goto('admin/settings/fckeditor');
427 }
428 else {
429 $output = fckeditor_global_profile_form($edit);
430 }
431 break;
432
0c87a920
WW
433 default:
434 drupal_set_title(t('FCKeditor settings'));
435 //Check if FCKeditor is installed.
436 $fckeditor_loc = drupal_get_path('module', 'fckeditor') .'/fckeditor/';
437 if (!is_dir($fckeditor_loc)) {
c01081e7 438 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');
0c87a920
WW
439 }
440 $output = fckeditor_profile_overview();
441 }
442
443 return $output;
444}
445
446/**
447 * Save a profile to the database.
448 * @todo add more entries to array in the user_save line
449 */
450function fckeditor_profile_save($edit) {
451 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
452 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
453 db_query("INSERT INTO {fckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], serialize($edit));
c01081e7 454 if ($edit['rids'])
0c87a920
WW
455 foreach ($edit['rids'] as $rid => $value) {
456 db_query("INSERT INTO {fckeditor_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid);
457 }
458
459 // if users can't set their own defaults, make sure to remove $user->fckeditor_status so their default doesn't override the main default
460 if ($edit['user_choose'] == 'false') {
461 global $user;
462 user_save($user, array('fckeditor_status' => NULL));
463 }
464}
465
c01081e7
WW
466function fckeditor_global_profile_save($edit) {
467 if (isset($edit['rank'])) {
468 $edit['rank'] = explode('>', str_replace(' ', '', $edit['rank']));
469 }
470
471 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
472 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s' or name = '%s'", $edit['name'], $edit['old_name']);
473 db_query("INSERT INTO {fckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], serialize($edit));
474}
475
0c87a920
WW
476/**
477 * Controller for fckeditor profiles.
478 */
479function fckeditor_profile_overview() {
480 $output = '';
481
482 $profiles = fckeditor_profile_load();
483 if ($profiles) {
484 $roles = user_roles();
485 $header = array(t('Profile'), t('Roles'), t('Operations'));
486 foreach ($profiles as $p) {
c01081e7
WW
487 if ($p->name !== "FCKeditor Global Profile") {
488 $rows[] = array(array('data' => $p->name, 'valign' => 'top'), array('data' => implode("<br />\n", $p->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'));
489 }
0c87a920 490 }
c01081e7 491 $output .= "<h3>". t("Profiles") ."</h3>";
0c87a920 492 $output .= theme('table', $header, $rows);
c01081e7
WW
493 $output .= '<p>'. l(t('Create new profile'), 'admin/settings/fckeditor/add') .'</p>';
494 }
495 else {
496 drupal_set_message(t('No profiles found. Click here to !create.', array('!create' => l(t("create a new profile"), 'admin/settings/fckeditor/add'))));
497 }
498
499 $rows = array();
500 if (!isset($profiles['FCKeditor Global Profile'])) {
501 drupal_set_message(t('Global Profile not found. Click here to !create.', array('!create' => l(t("create the global profile"), 'admin/settings/fckeditor/addg'))));
0c87a920
WW
502 }
503 else {
c01081e7
WW
504 $output .= "<h3>". t("Global Settings") ."</h3>";
505 $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'));
506 $output .= theme('table', array(t('Profile'), t('Operations')), $rows);
0c87a920
WW
507 }
508
509 return $output;
510}
511
512/**
513 * Load all profiles. Just load one profile if $name is passed in.
514 */
515function fckeditor_profile_load($name = '') {
516 static $profiles = array();
517
518 if (!$profiles) {
519 $roles = user_roles();
520 $result = db_query('SELECT * FROM {fckeditor_settings}');
521 while ($data = db_fetch_object($result)) {
522 $data->settings = unserialize($data->settings);
523 $result2 = db_query("SELECT rid FROM {fckeditor_role} WHERE name = '%s'", $data->name);
524 $role = array();
525 while ($r = db_fetch_object($result2)) {
526 $role[$r->rid] = $roles[$r->rid];
527 }
528 $data->rids = $role;
529
530 $profiles[$data->name] = $data;
531 }
532 }
533
534 return ($name ? $profiles[$name] : $profiles);
535}
536
c01081e7
WW
537/**
538 * @param int $excl_mode 1/include, exclude otherwise
539 * @param string $excl_fields fields (HTML IDs)
540 * @param string $excl_paths paths (drupal paths)
541 * @param string $element_id current ID
542 * @param string $get_q current path
543 *
544 * @return boolean
545 * returns true if FCKeditor is enabled
546 */
547function fckeditor_is_enabled($excl_mode, $excl_fields, $excl_paths, $element_id, $get_q) {
548 $arr_excl_fields = preg_split("/[\s,]+/", strip_tags($excl_fields));
549 $field_found = fckeditor_idsearch($element_id, $arr_excl_fields);
0c87a920 550
c01081e7
WW
551 $path = drupal_get_path_alias($get_q);
552 $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($excl_paths, '/')) .')$/';
553 $path_found = preg_match($regexp, $path);
0c87a920 554
c01081e7
WW
555 $found = $field_found || $path_found;
556
557 $result = ($excl_mode == 1) ? $found : !$found;
558 return $result;
0c87a920
WW
559}
560
561/**
9286dec5 562 * This function create the HTML objects required for the FCKeditor
e44c2389 563 *
564 * @param $element
565 * A fully populated form elment to add the editor to
566 * @return
567 * The same $element with extra FCKeditor markup and initialization
04b827fa 568 */
f3d88ca0 569function fckeditor_process_textarea($element) {
0c87a920
WW
570 static $is_running = FALSE;
571 static $num = 1;
572 global $user, $fckeditor_simple_toolbar_ids;
573 static $profile_name;
f3d88ca0 574
0c87a920 575 //skip this one, surely nobody wants WYSIWYG here
c01081e7 576
0c87a920
WW
577 switch ($element['#id']) {
578 case 'edit-excl-list':
579 case 'edit-simple-incl-list':
c01081e7
WW
580 case 'edit-simple-incl-paths':
581 case 'edit-simple-incl-fields':
0c87a920 582 case 'edit-log':
c01081e7
WW
583 case 'edit-excl-fields':
584 case 'edit-excl-paths':
585 case 'edit-js-conf':
0c87a920
WW
586 return $element;
587 break;
588 }
c01081e7 589
0c87a920 590 if (isset($element['#attributes']['disabled']) && $element['#attributes']['disabled'] == 'disabled') {
c01081e7
WW
591 return $element;
592 }
593
0c87a920
WW
594 // Since fckeditor_profile_load() makes a db hit, only call it when we're pretty sure
595 // we're gonna render fckeditor.
596 if (!$profile_name) {
c01081e7
WW
597 $sorted_roles = fckeditor_sorted_roles();
598 foreach ($sorted_roles as $rid => $name) {
599 if (isset($user->roles[$rid])) {
600 break;
601 }
602 }
603
604 $profile_name = 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));
0c87a920
WW
605 if (!$profile_name) {
606 return $element;
607 }
608 }
609
610 $profile = fckeditor_profile_load($profile_name);
c01081e7 611
0c87a920
WW
612 $conf = array();
613 $conf = $profile->settings;
614
c01081e7
WW
615 if ($conf['allow_user_conf']=='t') {
616 foreach (array('default', 'show_toggle', 'popup', 'skin', 'toolbar', 'expand', 'width', 'lang', 'auto_lang') as $setting) {
0c87a920
WW
617 $conf[$setting] = fckeditor_user_get_setting($user, $profile, $setting);
618 }
619 }
620 if ($conf["popup"]=="t" && $conf["show_toggle"]=="t") {
621 $conf["show_toggle"]="f";
622 }
623
c01081e7 624 $themepath = path_to_theme() .'/';
0c87a920
WW
625 $host = base_path();
626
627 // Set resizable to false to avoid drupal.js resizable function from taking control of the textarea
c01081e7
WW
628 if ($conf["popup"]=="f") {
629 $element['#resizable'] = FALSE;
630 }
0c87a920 631
c01081e7
WW
632 $enabled = fckeditor_is_enabled($conf['excl_mode'], $conf['excl_fields'], $conf['excl_paths'], $element['#id'], $_GET['q']);
633 if ($enabled) {
634 $global_profile = fckeditor_profile_load("FCKeditor Global Profile");
635 $global_conf = $global_profile->settings;
636 if ($global_conf) {
637 $enabled = fckeditor_is_enabled($global_conf['excl_mode'], $global_conf['excl_fields'], $global_conf['excl_paths'], $element['#id'], $_GET['q']);
638 }
639 }
0c87a920
WW
640
641 if (($element['#rows'] > $conf['min_rows']) && $enabled) {
0c87a920 642 // only replace textarea when it has enough rows and it is enabled
0c87a920 643
c01081e7
WW
644 $js_id = 'oFCK_'. $num++;
645 $fckeditor_on = ($conf['default']=='t') ? 1 : 0 ;
646
647 $wysiwyg_link = "<div id=\"fck_{$js_id}\"><textarea id=\"{$js_id}\">". htmlspecialchars($element['#value']) ."</textarea></div>\n";
648 $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")) ."');\" id=\"switch_{$js_id}\" ". ($fckeditor_on?"style=\"display:none\"":"") .">";
649 $wysiwyg_link .= $fckeditor_on ? t("Switch to plain text editor") : t("Switch to rich text editor");
0c87a920
WW
650 $wysiwyg_link .= "</a>";
651 $wysiwyg_link .= "\n<script type=\"text/javascript\">";
c01081e7 652 $wysiwyg_link .= "window.setTimeout(\"CreateToggle('{$element['#id']}','{$js_id}', $fckeditor_on);\",100);\n</script>";
c7d6f61d 653 if (!isset($element['#suffix'])) {
c01081e7 654 $element['#suffix'] = "";
c7d6f61d 655 }
0c87a920
WW
656 //settings are saved as strings, not booleans
657 if ($profile->settings['show_toggle'] == 't') {
658 // Make sure to append to #suffix so it isn't completely overwritten
659 $element['#suffix'] .= $wysiwyg_link;
660 }
f3d88ca0 661 // setting some variables
c01081e7
WW
662 $module_drupal_path = drupal_get_path('module', 'fckeditor');
663 $module_full_path = base_path() . $module_drupal_path;
e2610d9c 664 // get the default drupal files path
0c87a920
WW
665 $files_path = base_path() . file_directory_path();
666 // module_drupal_path:
667 // 'modules/fckeditor' (length=17)
668 // module_full_path:
669 // '/drupal5/modules/fckeditor' (length=26)
670 // files_path:
671 // '/drupal5/files' (length=14)
f3d88ca0 672 // configured in settings
0c87a920 673 $width = $conf['width'];
f3d88ca0 674
675 // sensible default for small toolbars
0c87a920 676 $height = $element['#rows'] * 14 + 140;
f3d88ca0 677
0c87a920 678 if (!$is_running) {
c01081e7
WW
679 drupal_add_js($module_drupal_path .'/fckeditor/fckeditor.js');
680 drupal_add_js($module_drupal_path .'/fckeditor.utils.js');
0c87a920 681 $is_running = true;
e44c2389 682 }
0c87a920
WW
683
684 $toolbar = $conf['toolbar'];
685 //$height += 100; // for larger toolbars
686
c01081e7
WW
687 $force_simple_toolbar = fckeditor_is_enabled(1, $conf['simple_incl_fields'], $conf['simple_incl_paths'], $element['#id'], $_GET['q']);
688 if (!$force_simple_toolbar) {
689 $force_simple_toolbar = fckeditor_is_enabled(1, $global_conf['simple_incl_fields'], $global_conf['simple_incl_paths'], $element['#id'], $_GET['q']);
690 }
691 if ($force_simple_toolbar) {
0c87a920 692 $toolbar = FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME;
f3d88ca0 693 }
694
c01081e7 695 $textarea_id = $profile->settings['show_toggle'] == 't' ? $js_id : $element['#id'];
0c87a920
WW
696
697 $element['#suffix'] .= "\n<script type=\"text/javascript\">
c01081e7
WW
698var ". $js_id ." = new FCKeditor( '". $textarea_id ."' );
699". $js_id .".BasePath = '". $module_full_path ."/fckeditor/';
700". $js_id .".Config['CustomConfigurationsPath'] = \"". $module_full_path ."/fckeditor.config.js\";
701". $js_id .".Config['TextareaID'] = \"". $element['#id'] ."\";";
0c87a920
WW
702
703 //if ($conf['appearance_conf'] == 'f') {
c01081e7
WW
704 $element['#suffix'] .= "\n". $js_id .".ToolbarSet = \"". $toolbar ."\";
705". $js_id .".Config['SkinPath'] = ". $js_id .".BasePath + \"editor/skins/". $conf['skin'] ."/\";
706". $js_id .".Config['DefaultLanguage'] = \"". $conf['lang'] ."\";
707". $js_id .".Config['AutoDetectLanguage'] = ". ($conf['auto_lang']=="t"?"true":"false") .";
708". $js_id .".Height = \"". $height ."\";
709". $js_id .".Config['ToolbarStartExpanded'] = ". ($conf['expand']=="t"?"true":"false") .";
710". $js_id .".Width = \"". $width ."\";\n";
0c87a920
WW
711 //}
712 //if ($conf['output_conf'] == 'f') {
c01081e7
WW
713 $element['#suffix'] .= "\n". $js_id .".Config['EnterMode'] = '". $conf['enter_mode'] ."';
714". $js_id .".Config['ShiftEnterMode'] = \"". $conf['shift_enter_mode'] ."\";
715". $js_id .".Config['FontFormats'] = \"". str_replace(",", ";", $conf['font_format']) ."\";
716". $js_id .".Config['FormatSource'] = ". ($conf['format_source']=="t"?"true":"false") .";
717". $js_id .".Config['FormatOutput'] = ". ($conf['format_output']=="t"?"true":"false") .";\n";
0c87a920 718 //}
e44c2389 719
0c87a920
WW
720 // integrate IMCE if it exists and is prefered
721 if (function_exists('imce_integrate') && variable_get('imce_settings_fck', 0)) {
722 imce_integrate('fck');
723 $advanced_uploads = 0;
724 $basic_uploads = 0;
725 }
726 else {
727 $advanced_uploads = ($conf['upload_advanced']=="t");
728 $basic_uploads = ($conf['upload_basic']=="t");
729 }
e44c2389 730 // add code for filebrowser for users that have access
0c87a920 731 if (user_access('allow fckeditor file uploads')==1) {
c01081e7 732 $connector_path = $module_drupal_path ."/fckeditor/editor/filemanager/connectors/php/connector.php" ;
0c87a920 733 $connector_path = file_exists($connector_path) ? "../../connectors/php/connector.php" : "connectors/php/connector.php" ;
c01081e7 734 $upload_path = $module_drupal_path ."/fckeditor/editor/filemanager/connectors/php/upload.php" ;
0c87a920
WW
735 $upload_path = file_exists($upload_path) ? "/fckeditor/editor/filemanager/connectors/php/upload.php" : "/fckeditor/editor/filemanager/upload/php/upload.php" ;
736 if ($advanced_uploads) {
c01081e7
WW
737 $element['#suffix'] .= $js_id .".Config['LinkBrowserURL'] = \"". $module_full_path ."/fckeditor/editor/filemanager/browser/default/browser.html?Connector=". $connector_path ."&ServerPath=". $files_path ."\";
738 ". $js_id .".Config['ImageBrowserURL'] = \"". $module_full_path ."/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=". $connector_path ."&ServerPath=". $files_path ."\";
739 ". $js_id .".Config['FlashBrowserURL'] = \"". $module_full_path ."/fckeditor/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=". $connector_path ."&ServerPath=". $files_path ."\";\n";
0c87a920
WW
740 }
741 else {
c01081e7
WW
742 $element['#suffix'] .= $js_id .".Config['LinkBrowser'] = false;
743". $js_id .".Config['ImageBrowser'] = false;
744". $js_id .".Config['FlashBrowser'] = false;\n";
0c87a920
WW
745 }
746 if ($basic_uploads) {
c01081e7
WW
747 $element['#suffix'] .= $js_id .".Config['LinkUploadURL'] = \"". $module_full_path . $upload_path ."\";
748 ". $js_id .".Config['ImageUploadURL'] = \"". $module_full_path . $upload_path ."?Type=Image\";
749 ". $js_id .".Config['FlashUploadURL'] = \"". $module_full_path . $upload_path ."?Type=Flash\";\n";
0c87a920
WW
750 }
751 else {
c01081e7
WW
752 $element['#suffix'] .= $js_id .".Config['LinkUpload'] = false;
753". $js_id .".Config['ImageUpload'] = false;
754". $js_id .".Config['FlashUpload'] = false;\n";
0c87a920 755 }
c01081e7
WW
756 $_SESSION['FCKeditor']['UserFilesPath'] = strtr($profile->settings['UserFilesPath'], array("%f" => file_directory_path(), "%u" => $user->uid, "%b" => base_path()));
757 $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = strtr($profile->settings['UserFilesAbsolutePath'], array("%f" => file_directory_path(), "%u" => $user->uid, "%b" => base_path(), "%d" => $_SERVER['DOCUMENT_ROOT']));
0c87a920
WW
758 }
759 else {
c01081e7
WW
760 $element['#suffix'] .= $js_id .".Config['LinkBrowser'] = false;
761". $js_id .".Config['ImageBrowser'] = false;
762". $js_id .".Config['FlashBrowser'] = false;
763". $js_id .".Config['LinkUpload'] = false;
764". $js_id .".Config['ImageUpload'] = false;
765". $js_id .".Config['FlashUpload'] = false;\n";
766 }
767
768 if ($conf['js_conf']) {
769 $lines = preg_split("/[\n\r]+/", $conf['js_conf']);
770 foreach ($lines as $l)
771 if ($l && strlen($l) > 5) {
772 $eqpos = strpos($l, "=");
773 if (false !== $eqpos) {
774 $option = str_replace("FCKConfig.", "", substr($l, 0, $eqpos));
775 $element['#suffix'] .= "\n". $js_id .".Config['". $option ."'] =". substr($l, $eqpos + 1);
776 }
777 }
92b2e6cf 778 }
e44c2389 779
0c87a920 780 // add custom xml stylesheet if it exists
c01081e7
WW
781 if ($conf['css_style'] == 'theme') {
782 if (file_exists($themepath .'/fckstyles.xml')) {
783 $styles_xml_path = $host . $themepath .'/fckstyles.xml';
784 $element['#suffix'] .= $js_id .".Config['StylesXmlPath'] = \"". $styles_xml_path ."\";\n";
785 }
786 }
787 else if ($conf['css_style'] == 'self') {
788 $element['#suffix'] .= $js_id .".Config['StylesXmlPath'] = \"". str_replace(array('%h', '%t', '%m'), array($host, $themepath, $module_drupal_path), $conf['styles_path']) ."\";\n";
0c87a920
WW
789 }
790
791 // add custom stylesheet if configured
792 // lets hope it exists but we'll leave that to the site admin
793 if ($conf['css_mode'] == 'theme') {
c01081e7 794 $css = $themepath .'style.css';
0c87a920 795 if (file_exists($css)) {
c01081e7 796 $element['#suffix'] .= $js_id .".Config['EditorAreaCSS'] = \"". $host . $css .",". $module_full_path ."/fckeditor.css\";";
0c87a920
WW
797 }
798 }
799 else if ($conf['css_mode'] == 'self') {
c01081e7 800 $element['#suffix'] .= $js_id .".Config['EditorAreaCSS'] = \"". str_replace(array('%h', '%t'), array($host, $themepath), $conf['css_path']) .",". $module_full_path ."/fckeditor.css\";";
0c87a920
WW
801 }
802
92b2e6cf 803 $element['#suffix'] .= "</script>\n";
f3d88ca0 804
0c87a920
WW
805 if ($conf['popup']=="t") {
806 // Add the script file with the popup open function.
c01081e7
WW
807 drupal_add_js($module_drupal_path .'/fckeditor.popup.js');
808 $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>";
0c87a920 809 }
e44c2389 810 else {
0c87a920
WW
811 // if no popup mode, add the editor initialization to the footer
812 // this obviously needs print($closure) in page.tpl.php
c01081e7
WW
813 if ($fckeditor_on) {
814 drupal_add_js('if (Drupal.jsEnabled) {$(document).ready(function() {if (typeof ('. $js_id .') != "undefined") '. $js_id .'.ReplaceTextarea();});}', 'inline', 'footer');
0c87a920 815 }
f3d88ca0 816 }
817 }
9b429add 818
0c87a920
WW
819 // display the field id for administrators
820 if (user_access('administer fckeditor')) {
c01081e7
WW
821 $element['#suffix'] .= t('<div class="textarea-identifier description">The ID for !excluding this element is: !id - the path is: !path</div>', array(
822 '!excluding' => l(t("excluding or including"), 'admin/settings/fckeditor'),
823 '!id' => $element['#id'],
824 '!path' => $_GET['q'],
825 ));
0c87a920
WW
826 }
827
f3d88ca0 828 return $element;
04b827fa
DS
829}
830
23824481 831/**
0c87a920
WW
832 * Implementation of hook_user().
833 */
834function fckeditor_user($type, &$edit, &$user, $category = NULL) {
835 if ($type == 'form' && $category == 'account' && user_access('access fckeditor')) {
836 $profile = fckeditor_user_get_profile($user);
837 $toolbar_options = fckeditor_load_toolbar_options();
838 $skin_options = fckeditor_load_skin_options();
839 $lang_options = fckeditor_load_lang_options();
840
841 // because the settings are saved as strings we need to test for the string 'true'
842 if ($profile->settings['allow_user_conf'] == 't') {
843 $form['fckeditor'] = array(
844 '#type' => 'fieldset',
845 '#title' => t('Rich Text Editor settings'),
846 '#weight' => 10,
847 '#collapsible' => TRUE,
848 '#collapsed' => TRUE
849 );
850
851 $form['fckeditor']['fckeditor_default'] = array(
852 '#type' => 'select',
853 '#title' => t('Default state'),
854 '#default_value' => isset($user->fckeditor_default) ? $user->fckeditor_default : (isset($profile->settings['default']) ? $profile->settings['default'] : 'f'),
c01081e7 855 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
0c87a920
WW
856 '#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.'),
857 );
858
859 $form['fckeditor']['fckeditor_show_toggle'] = array(
860 '#type' => 'select',
861 '#title' => t('Show disable/enable rich text editor toggle'),
862 '#default_value' => isset($user->fckeditor_show_toggle) ? $user->fckeditor_show_toggle : (isset($profile->settings['show_toggle']) ? $profile->settings['show_toggle'] : 't'),
863 '#options' => array('t' => t('true'), 'f' => t('false')),
864 '#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).'),
865 );
866
867 $form['fckeditor']['fckeditor_popup'] = array(
868 '#type' => 'select',
869 '#title' => t('Use FCKeditor in a popup window'),
870 '#default_value' => isset($user->fckeditor_popup) ? $user->fckeditor_popup : (isset($profile->settings['popup']) ? $profile->settings['popup'] : 'f'),
871 '#options' => array('f' => t('false'), 't' => t('true')),
872 '#description' => t('If this option is enabled a link to a popup window will be used instead of a textarea replace.'),
873 );
874
875 $form['fckeditor']['fckeditor_skin'] = array(
876 '#type' => 'select',
877 '#title' => t('Skin'),
878 '#default_value' => isset($user->fckeditor_skin) ? $user->fckeditor_skin : (isset($profile->settings['skin']) ? $profile->settings['skin'] : 'default'),
879 '#options' => $skin_options,
880 '#description' => t('Choose a FCKeditor skin.'),
881 );
882
883 $form['fckeditor']['fckeditor_toolbar'] = array(
884 '#type' => 'select',
885 '#title' => t('Toolbar'),
886 '#default_value' => isset($user->fckeditor_toolbar) ? $user->fckeditor_toolbar : (isset($profile->settings['toolbar']) ? $profile->settings['toolbar'] : 'default'),
887 '#options' => $toolbar_options,
888 '#description' => t('Choose a FCKeditor toolbar set.'),
889 );
890
891 $form['fckeditor']['fckeditor_expand'] = array(
892 '#type' => 'select',
893 '#title' => t('Start the toolbar expanded'),
894 '#default_value' => isset($user->fckeditor_expand) ? $user->fckeditor_expand : (isset($profile->settings['expand']) ? $profile->settings['expand'] : 't'),
895 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
896 '#description' => t('The toolbar start expanded or collapsed.'),
897 );
898
899 $form['fckeditor']['fckeditor_width'] = array(
900 '#type' => 'textfield',
901 '#title' => t('Width'),
902 '#default_value' => isset($user->fckeditor_width) ? $user->fckeditor_width : (isset($profile->settings['width']) ? $profile->settings['width'] : '100%'),
903 '#description' => t("Width in pixels or percent. Ex: 400 or 100%"),
904 '#size' => 40,
905 '#maxlength' => 128,
906 );
907
908 $form['fckeditor']['fckeditor_lang'] = array(
909 '#type' => 'select',
910 '#title' => t('Language'),
911 '#default_value' => isset($user->fckeditor_lang) ? $user->fckeditor_lang : (isset($profile->settings['lang']) ? $profile->settings['lang'] : 'en'),
912 '#options' => $lang_options,
913 '#description' => t('The language for the FCKeditor interface.')
914 );
915
916 $form['fckeditor']['fckeditor_auto_lang'] = array(
917 '#type' => 'select',
918 '#title' => t('Auto-detect language'),
919 '#default_value' => isset($user->fckeditor_auto_lang) ? $user->fckeditor_auto_lang : (isset($profile->settings['auto_lang']) ? $profile->settings['auto_lang'] : 't'),
920 '#options' => array('t' => t('true'), 'f' => t('false')),
921 '#description' => t('Use auto detect user language feature.')
922 );
923
924 return array('fckeditor' => $form);
925 }
926 }
927
928 if ($type == 'validate') {
929 return array(
930 'fckeditor_default' => $edit['fckeditor_default'],
931 'fckeditor_show_toggle' => $edit['fckeditor_show_toggle'],
932 'fckeditor_popup' => $edit['fckeditor_popup'],
933 'fckeditor_skin' => $edit['fckeditor_skin'],
934 'fckeditor_toolbar' => $edit['fckeditor_toolbar'],
935 'fckeditor_expand' => $edit['fckeditor_expand'],
936 'fckeditor_width' => $edit['fckeditor_width'],
937 'fckeditor_lang' => $edit['fckeditor_lang'],
938 'fckeditor_auto_lang' => $edit['fckeditor_auto_lang'],
939 );
940 }
941}
942
943/**
944 * Return an HTML form for profile configuration.
945 */
946function fckeditor_profile_form($edit) {
947
948 $output .= drupal_get_form('fckeditor_profile_form_build', $edit);
949
950 return $output;
951}
952
c01081e7
WW
953/**
954 * Return an HTML form for global profile configuration.
955 */
956function fckeditor_global_profile_form($edit) {
957
958 $output .= drupal_get_form('fckeditor_global_profile_form_build', $edit);
959
960 return $output;
961}
962
0c87a920
WW
963function fckeditor_load_toolbar_options() {
964 $arr = array();
c01081e7
WW
965 $module_drupal_path = drupal_get_path('module', 'fckeditor');
966 $fckconfig_js = $module_drupal_path .'/fckeditor/fckconfig.js';
967 $fckeditor_config_js = $module_drupal_path .'/fckeditor.config.js';
0c87a920
WW
968 if (file_exists($fckconfig_js) && is_readable($fckconfig_js)) {
969 $fp = @fopen($fckconfig_js, "r");
970 if ($fp) {
971 while (!feof($fp)) {
c01081e7 972 $line = fgets($fp, 1024);
0c87a920
WW
973 if (preg_match("/FCKConfig\.ToolbarSets\[(\"|')(.*?)\\1\]/i", $line, $matches)) {
974 $arr[$matches[2]] = ucfirst($matches[2]);
975 }
976 }
977 fclose($fp);
978 }
979 }
980 if (file_exists($fckeditor_config_js) && is_readable($fckeditor_config_js)) {
981 $fp = @fopen($fckeditor_config_js, "r");
982 if ($fp) {
983 while (!feof($fp)) {
c01081e7 984 $line = fgets($fp, 1024);
0c87a920
WW
985 if (preg_match("/FCKConfig\.ToolbarSets\[(\"|')(.*?)\\1\]/i", $line, $matches)) {
986 $arr[$matches[2]] = ucfirst($matches[2]);
987 }
988 }
989 fclose($fp);
990 }
991 }
992
993 //oops, we have no information about toolbars, let's use hardcoded array
994 if (empty($arr)) {
995 $arr = array(
996 'Basic' => 'Basic',
997 'Default' => 'Default',
998 );
999 }
1000 asort($arr);
1001
1002 return $arr;
1003}
1004
1005function fckeditor_load_skin_options() {
1006 $arr = array();
c01081e7
WW
1007 $module_drupal_path = drupal_get_path('module', 'fckeditor');
1008 $skin_dir = $module_drupal_path .'/fckeditor/editor/skins';
0c87a920
WW
1009 if (is_dir($skin_dir)) {
1010 $dh = @opendir($skin_dir);
c01081e7
WW
1011 if (false !== $dh) {
1012 while (($file = readdir($dh)) !== false ) {
1013 if (in_array($file, array(".", "..", "CVS", ".svn"))) {
0c87a920
WW
1014 continue;
1015 }
c01081e7 1016 if (is_dir($skin_dir . DIRECTORY_SEPARATOR . $file)) {
0c87a920
WW
1017 $arr[$file] = ucfirst($file);
1018 }
1019 }
1020 closedir( $dh );
1021 }
1022 }
1023
1024 //oops, we have no information about skins, let's use only default
1025 if (empty($arr)) {
1026 $arr = array(
1027 'default' => 'Default',
1028 );
1029 }
1030 asort($arr);
1031
1032 return $arr;
1033}
1034
1035function fckeditor_load_lang_options() {
1036 $arr = array();
c01081e7
WW
1037 $module_drupal_path = drupal_get_path('module', 'fckeditor');
1038 $lang_dir = $module_drupal_path .'/fckeditor/editor/lang';
0c87a920
WW
1039 if (is_dir($lang_dir)) {
1040 $dh = @opendir($lang_dir);
c01081e7
WW
1041 if (false !== $dh ) {
1042 while (($file = readdir($dh)) !== false) {
1043 if (in_array($file, array(".", "..", "CVS", ".svn"))) {
0c87a920
WW
1044 continue;
1045 }
c01081e7 1046 if (is_file($lang_dir . DIRECTORY_SEPARATOR . $file) && preg_match("/^(.*?)\.js$/", $file, $matches)) {
0c87a920
WW
1047 $lang = $matches[1];
1048 $arr[$lang] = strtoupper($lang);
1049 }
1050 }
1051 closedir( $dh );
1052 }
1053 }
1054
1055 //oops, we have no information about languages, let's use those available in FCKeditor 2.4.3
1056 if (empty($arr)) {
1057 $arr = array(
1058 'af' => 'Afrikaans',
1059 'ar' => 'Arabic',
1060 'bg' => 'Bulgarian',
1061 'bn' => 'Bengali/Bangla',
1062 'bs' => 'Bosnian',
1063 'ca' => 'Catalan',
1064 'cs' => 'Czech',
1065 'da' => 'Danish',
1066 'de' => 'German',
1067 'el' => 'Greek',
1068 'en' => 'English',
c01081e7
WW
1069 'en-au' => 'English (Australia)',
1070 'en-ca' => 'English (Canadian)',
1071 'en-uk' => 'English (United Kingdom)',
0c87a920
WW
1072 'eo' => 'Esperanto',
1073 'es' => 'Spanish',
1074 'et' => 'Estonian',
1075 'eu' => 'Basque',
1076 'fa' => 'Persian',
1077 'fi' => 'Finnish',
1078 'fo' => 'Faroese',
1079 'fr' => 'French',
1080 'gl' => 'Galician',
1081 'he' => 'Hebrew',
1082 'hi' => 'Hindi',
1083 'hr' => 'Croatian',
1084 'hu' => 'Hungarian',
1085 'it' => 'Italian',
1086 'ja' => 'Japanese',
1087 'km' => 'Khmer',
1088 'ko' => 'Korean',
1089 'lt' => 'Lithuanian',
1090 'lv' => 'Latvian',
1091 'mn' => 'Mongolian',
1092 'ms' => 'Malay',
1093 'nb' => 'Norwegian Bokmal',
1094 'nl' => 'Dutch',
1095 'no' => 'Norwegian',
1096 'pl' => 'Polish',
1097 'pt' => 'Portuguese (Portugal)',
c01081e7 1098 'pt-br' => 'Portuguese (Brazil)',
0c87a920
WW
1099 'ro' => 'Romanian',
1100 'ru' => 'Russian',
1101 'sk' => 'Slovak',
1102 'sl' => 'Slovenian',
1103 'sr' => 'Serbian (Cyrillic)',
c01081e7 1104 'sr-latn' => 'Serbian (Latin)',
0c87a920
WW
1105 'sv' => 'Swedish',
1106 'th' => 'Thai',
1107 'tr' => 'Turkish',
1108 'uk' => 'Ukrainian',
1109 'vi' => 'Vietnamese',
1110 'zh' => 'Chinese Traditional',
c01081e7 1111 'zh-cn' => 'Chinese Simplified',
0c87a920
WW
1112 );
1113 }
1114
1115 asort($arr);
1116
1117 return $arr;
1118}
1119
1120/**
c01081e7
WW
1121 * sort roles according to precedence settings. previously sorted roles are followed by latest added roles.
1122 */
1123function fckeditor_sorted_roles() {
1124 static $order;
1125 if (isset($order)) {
1126 return $order;
1127 }
1128 $order = array();
1129 $roles = user_roles(0, 'access fckeditor');
1130
1131 $result = db_query("SELECT settings FROM {fckeditor_settings} WHERE name='FCKeditor Global Profile'");
1132 $data = db_fetch_object($result);
1133 if ($data->settings) {
1134 $settings = unserialize($data->settings);
1135 if (isset($settings['rank']) && !empty($settings['rank']))
1136 foreach ($settings['rank'] as $rid) {
1137 if (isset($roles[$rid])) {
1138 $order[$rid] = $roles[$rid];
1139 unset($roles[$rid]);
1140 }
1141 }
1142 }
1143 krsort($roles);//sort the remaining unsorted roles by id, descending.
1144 $order += $roles;
1145 return $order;
1146}
1147
1148function fckeditor_global_profile_form_build($sth, $edit) {
1149 $edit = (object) $edit;
1150
1151 if (arg(3) == 'addg') {
1152 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')));
1153
1154 $result = db_query("SELECT DISTINCT(rid) FROM {fckeditor_role} WHERE name='FCKeditor Global Profile'");
1155 $data = db_fetch_object($result);
1156
1157 if ($data->rid) {
1158 drupal_set_message(t("Global profile already exist. Only one global profile is allowed."), "error");
1159 return array();
1160 }
1161
1162 $btn = t('Create global profile');
1163 }
1164 else {
1165 $form['old_name'] = array('#type' => 'hidden', '#value' => $edit->name);
1166 $btn = t('Update global profile');
1167 }
1168
1169 $form['common'] = array(
1170 '#type' => 'fieldset',
1171 '#title' => t('Main setup'),
1172 '#collapsible' => TRUE,
1173 '#collapsed' => TRUE
1174 );
1175
1176 $roles = fckeditor_sorted_roles();
1177 $rids = $rtext = array();
1178 foreach ($roles as $rid => $name) {
1179 $rids[] = $rid;
1180 $rtext[] = '<strong>'. $rid .' - </strong>'. $name;
1181 }
1182 $form['common']['rank'] = array('#type' => 'textfield',
1183 '#title' => t('Role precedence'),
1184 '#default_value' => implode('>', $rids),
1185 '#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 />'),
1186 );
1187 if ($rids) {
1188 $form['common']['rank']['#description'] .= t('Here is the id-name pairs of roles having access to FCKeditor:') .'<div>'. implode('<br />', $rtext) .'</div>';
1189 }
1190 else {
1191 $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')));
1192 }
1193
1194 $form['fckeditor_exclude_settings'] = array(
1195 '#type' => 'fieldset',
1196 '#title' => t('Visibility settings'),
1197 '#collapsible' => TRUE,
1198 '#collapsed' => TRUE,
1199 );
1200
1201 $form['fckeditor_exclude_settings']['excl_mode'] = array(
1202 '#type' => 'select',
1203 '#title' => t('Use inclusion or exclusion mode'),
1204 '#default_value' => (in_array($edit->settings['excl_mode'], array(0, 2))) ? 0 : 1,
1205 '#options' => array('0' => t('exclude'), '1' => t('include')),
1206 '#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.'),
1207 );
1208
1209 /**
1210 * get excluded fields - so we can have normal textareas too
1211 * split the phrase by any number of commas or space characters,
1212 * which include " ", \r, \t, \n and \f
1213 */
1214 $form['fckeditor_exclude_settings']['excl_fields'] = array(
1215 '#type' => 'textarea',
1216 '#title' => t('Fields to exclude/include'),
1217 '#cols' => 60,
1218 '#rows' => 5,
1219 '#prefix' => '<div style="margin-left:20px">',
1220 '#suffix' => '</div>',
1221 '#default_value' => $edit->settings['excl_fields'] ? $edit->settings['excl_fields'] : '',
1222 '#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."),
1223 );
1224
1225 /**
1226 * get excluded paths - so we can have normal textareas too
1227 * split the phrase by any number of commas or space characters,
1228 * which include " ", \r, \t, \n and \f
1229 */
1230 $form['fckeditor_exclude_settings']['excl_paths'] = array(
1231 '#type' => 'textarea',
1232 '#title' => t('Paths to exclude/include'),
1233 '#prefix' => '<div style="margin-left:20px">',
1234 '#suffix' => '</div>',
1235 '#cols' => 60,
1236 '#rows' => 5,
1237 '#default_value' => $edit->settings['excl_paths'] ? $edit->settings['excl_paths'] : '',
1238 '#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>)."),
1239 );
1240
1241 $form['fckeditor_exclude_settings']['simple_incl_fields'] = array(
1242 '#type' => 'textarea',
1243 '#title' => t('Force simplified toolbar on the following fields'),
1244 '#cols' => 60,
1245 '#rows' => 5,
1246 '#default_value' => $edit->settings['simple_incl_fields'] ? $edit->settings['simple_incl_fields'] : '',
1247 '#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."),
1248 );
1249
1250 $form['fckeditor_exclude_settings']['simple_incl_paths'] = array(
1251 '#type' => 'textarea',
1252 '#title' => t('Force simplified toolbar on the following paths'),
1253 '#cols' => 60,
1254 '#rows' => 5,
1255 '#default_value' => $edit->settings['simple_incl_paths'] ? $edit->settings['simple_incl_paths'] : '',
1256 '#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>)."),
1257 );
1258
1259 $form['submit'] = array(
1260 '#type' => 'submit',
1261 '#value' => $btn
1262 );
1263
1264 return $form;
1265}
1266
1267/**
0c87a920
WW
1268 * Return an HTML form for profile configuration.
1269 */
1270function fckeditor_profile_form_build($sth, $edit) {
1271 $edit = (object) $edit;
1272
1273 $toolbar_options = fckeditor_load_toolbar_options();
1274 $skin_options = fckeditor_load_skin_options();
1275 $lang_options = fckeditor_load_lang_options();
1276
1277 // Only display the roles that currently don't have a fckeditor profile. One
1278 // profile per role.
1279 $orig_roles = user_roles(FALSE, 'access fckeditor');
1280 $roles = $orig_roles;
1281 if (arg(3) == 'add') {
c01081e7
WW
1282 drupal_set_breadcrumb(array(l(t('administer'), 'admin'), l(t('fckeditor'), 'admin/settings/fckeditor'), l(t('Add new FCKeditor profile'), 'admin/settings/fckeditor/add')));
1283
0c87a920
WW
1284 $result = db_query('SELECT DISTINCT(rid) FROM {fckeditor_role}');
1285 while ($data = db_fetch_object($result)) {
c01081e7 1286 if (!in_array($data->rid, array_keys((array) $edit->rids)) && !form_get_errors()) {
0c87a920
WW
1287 unset($roles[$data->rid]);
1288 }
1289 }
c01081e7 1290 if (count($orig_roles) != count($roles)) {
0c87a920
WW
1291 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.'));
1292 }
1293 $btn = t('Create profile');
1294 }
1295 else {
1296 $form['old_name'] = array('#type' => 'hidden', '#value' => $edit->name);
1297 $btn = t('Update profile');
1298 }
1299
1300 $form['basic'] = array(
1301 '#type' => 'fieldset',
1302 '#title' => t('Basic setup'),
1303 '#collapsible' => TRUE,
1304 '#collapsed' => TRUE
1305 );
1306
1307 $form['basic']['name'] = array(
1308 '#type' => 'textfield',
1309 '#title' => t('Profile name'),
1310 '#default_value' => $edit->name,
1311 '#size' => 40,
1312 '#maxlength' => 128,
1313 '#description' => t('Enter a name for this profile. This name is only visible within the fckeditor administration page.'),
1314 '#required' => TRUE
1315 );
1316
1317 $form['basic']['rids'] = array(
1318 '#type' => 'checkboxes',
1319 '#title' => t('Roles allowed to use this profile'),
1320 '#default_value' => array_keys((array) $edit->rids),
1321 '#options' => $roles,
c01081e7 1322 '#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"))),
0c87a920
WW
1323 '#required' => TRUE
1324 );
1325
1326 $form['basic']['allow_user_conf'] = array(
1327 '#type' => 'select',
1328 '#title' => t('Allow users to customize FCKeditor appearance'),
1329 '#default_value' => $edit->settings['allow_user_conf'] ? $edit->settings['allow_user_conf'] : 'f',
1330 '#options' => array('f' => t('false'), 't' => t('true')),
1331 '#description' => t('If allowed, users will be able to override <code>Editor appearance</code> by visiting their profile page.'),
1332 );
1333
1334 $form['fckeditor_exclude_settings'] = array(
1335 '#type' => 'fieldset',
1336 '#title' => t('Visibility settings'),
1337 '#collapsible' => TRUE,
1338 '#collapsed' => TRUE,
1339 );
1340
1341 $form['fckeditor_exclude_settings']['min_rows'] = array(
1342 '#type' => 'textfield',
1343 '#title' => t('Minimum rows'),
1344 '#default_value' => $edit->settings['min_rows'] ? $edit->settings['min_rows'] : '5',
1345 '#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."),
1346 );
1347
1348 $form['fckeditor_exclude_settings']['excl_mode'] = array(
c01081e7 1349 '#type' => 'select',
0c87a920 1350 '#title' => t('Use inclusion or exclusion mode'),
c01081e7
WW
1351 '#default_value' => (in_array($edit->settings['excl_mode'], array(0, 2))) ? 0 : 1,
1352 '#options' => array('0' => t('exclude'), '1' => t('include')),
1353 '#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.'),
0c87a920
WW
1354 );
1355
1356 /**
1357 * get excluded fields - so we can have normal textareas too
1358 * split the phrase by any number of commas or space characters,
1359 * which include " ", \r, \t, \n and \f
1360 */
c01081e7 1361 $form['fckeditor_exclude_settings']['excl_fields'] = array(
0c87a920 1362 '#type' => 'textarea',
c01081e7 1363 '#title' => t('Fields to exclude/include'),
0c87a920
WW
1364 '#cols' => 60,
1365 '#rows' => 5,
c01081e7
WW
1366 '#prefix' => '<div style="margin-left:20px">',
1367 '#suffix' => '</div>',
1368 '#default_value' => $edit->settings['excl_fields'] ? $edit->settings['excl_fields'] : '',
1369 '#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."),
0c87a920
WW
1370 );
1371
1372 /**
c01081e7 1373 * get excluded paths - so we can have normal textareas too
0c87a920
WW
1374 * split the phrase by any number of commas or space characters,
1375 * which include " ", \r, \t, \n and \f
1376 */
c01081e7 1377 $form['fckeditor_exclude_settings']['excl_paths'] = array(
0c87a920 1378 '#type' => 'textarea',
c01081e7
WW
1379 '#title' => t('Paths to exclude/include'),
1380 '#prefix' => '<div style="margin-left:20px">',
1381 '#suffix' => '</div>',
0c87a920
WW
1382 '#cols' => 60,
1383 '#rows' => 5,
c01081e7
WW
1384 '#default_value' => $edit->settings['excl_paths'] ? $edit->settings['excl_paths'] : '',
1385 '#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>)."),
1386 );
1387
1388 $form['fckeditor_exclude_settings']['simple_incl_fields'] = array(
1389 '#type' => 'textarea',
1390 '#title' => t('Force simplified toolbar on the following fields'),
1391 '#cols' => 60,
1392 '#rows' => 5,
1393 //'#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)),
1394 '#default_value' => $edit->settings['simple_incl_fields'] ? $edit->settings['simple_incl_fields'] : '',
1395 '#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."),
1396 );
1397
1398 $form['fckeditor_exclude_settings']['simple_incl_paths'] = array(
1399 '#type' => 'textarea',
1400 '#title' => t('Force simplified toolbar on the following paths'),
1401 '#cols' => 60,
1402 '#rows' => 5,
1403 //'#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)),
1404 '#default_value' => $edit->settings['simple_incl_paths'] ? $edit->settings['simple_incl_paths'] : '',
1405 '#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>)."),
1406 );
0c87a920
WW
1407
1408 $form['appearance'] = array(
1409 '#type' => 'fieldset',
1410 '#title' => t('Editor appearance'),
1411 '#collapsible' => TRUE,
1412 '#collapsed' => TRUE,
1413 );
1414
1415 $form['appearance']['default'] = array(
1416 '#type' => 'select',
1417 '#title' => t('Default state'),
1418 '#default_value' => $edit->settings['default'] ? $edit->settings['default'] : 't',
c01081e7 1419 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
0c87a920
WW
1420 '#description' => t('Default editor state. If disabled, rich text editor may still be enabled using toggle or popup window.'),
1421 );
1422
1423 $form['appearance']['show_toggle'] = array(
1424 '#type' => 'select',
1425 '#title' => t('Show disable/enable rich text editor toggle'),
1426 '#default_value' => $edit->settings['show_toggle'] ? $edit->settings['show_toggle'] : 't',
1427 '#options' => array('t' => t('true'), 'f' => t('false')),
1428 '#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).'),
1429 );
1430
1431 $form['appearance']['popup'] = array(
1432 '#type' => 'select',
1433 '#title' => t('Use FCKeditor in a popup window'),
1434 '#default_value' => $edit->settings['popup'] ? $edit->settings['popup'] : 'f',
1435 '#options' => array('f' => t('false'), 't' => t('true')),
1436 '#description' => t('If this option is enabled a link to a popup window will be used instead of a textarea replace.'),
1437 );
1438
1439 $form['appearance']['skin'] = array(
1440 '#type' => 'select',
1441 '#title' => t('Skin'),
1442 '#default_value' => $edit->settings['skin'] ? $edit->settings['skin'] : 'default',
1443 '#options' => $skin_options,
1444 '#description' => t('Choose a default skin.'),
1445 );
1446
1447 $form['appearance']['toolbar'] = array(
1448 '#type' => 'select',
1449 '#title' => t('Toolbar'),
1450 '#default_value' => $edit->settings['toolbar'] ? $edit->settings['toolbar'] : 'default',
1451 '#options' => $toolbar_options,
1452 '#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'))),
1453 );
1454
1455 $form['appearance']['expand'] = array(
1456 '#type' => 'select',
1457 '#title' => t('Start the toolbar expanded'),
1458 '#default_value' => $edit->settings['expand'] ? $edit->settings['expand'] : 't',
1459 '#options' => array('t' => t('enabled'), 'f' => t('disabled')),
1460 '#description' => t('The toolbar start expanded or collapsed.'),
1461 );
1462
1463 $form['appearance']['width'] = array(
1464 '#type' => 'textfield',
1465 '#title' => t('Width'),
1466 '#default_value' => $edit->settings['width'] ? $edit->settings['width'] : '100%',
1467 '#description' => t("Width in pixels or percent. Ex: 400 or 100%"),
1468 '#size' => 40,
1469 '#maxlength' => 128,
1470 );
1471
1472 $form['appearance']['lang'] = array(
1473 '#type' => 'select',
1474 '#title' => t('Language'),
1475 '#default_value' => $edit->settings['lang'] ? $edit->settings['lang'] : 'en',
1476 '#options' => $lang_options,
1477 '#description' => t('The language for the FCKeditor interface.')
1478 );
1479
1480 $form['appearance']['auto_lang'] = array(
1481 '#type' => 'select',
1482 '#title' => t('Auto-detect language'),
1483 '#default_value' => $edit->settings['auto_lang'] ? $edit->settings['auto_lang'] : 't',
1484 '#options' => array('t' => t('true'), 'f' => t('false')),
1485 '#description' => t('Use auto detect user language feature.')
1486 );
1487
c01081e7
WW
1488 /*
1489 $form['appearance']['appearance_conf'] = array(
1490 '#type' => 'select',
1491 '#title' => t('Ignore this section, use default settings defined in config files'),
1492 '#default_value' => $edit->settings['appearance_conf'] ? $edit->settings['appearance_conf'] : 'f',
1493 '#options' => array('f' => t('false'), 't' => t('true')),
1494 '#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.'),
1495 );
1496 */
0c87a920
WW
1497
1498 $form['output'] = array(
1499 '#type' => 'fieldset',
1500 '#title' => t('Cleanup and output'),
1501 '#collapsible' => TRUE,
1502 '#collapsed' => TRUE,
1503 );
1504
1505 $form['output']['enter_mode'] = array(
1506 '#type' => 'select',
1507 '#title' => t('Enter mode'),
1508 '#default_value' => $edit->settings['enter_mode'] ? $edit->settings['enter_mode'] : 'p',
1509 '#options' => array('p' => '<p>', 'br' => '<br>', 'div' => '<div>'),
1510 '#description' => t('Set which tag FCKeditor should use when [Enter] key is pressed.')
1511 );
1512
1513 $form['output']['shift_enter_mode'] = array(
1514 '#type' => 'select',
1515 '#title' => t('Shift + Enter mode'),
1516 '#default_value' => $edit->settings['shift_enter_mode'] ? $edit->settings['shift_enter_mode'] : 'br',
1517 '#options' => array('p' => '<p>', 'br' => '<br>', 'div' => '<div>'),
1518 '#description' => t('Set which tag FCKeditor should use when [Shift] + [Enter] is pressed.')
1519 );
1520
1521 $form['output']['font_format'] = array(
1522 '#type' => 'textfield',
1523 '#title' => t('Font formats'),
1524 '#default_value' => $edit->settings['font_format'] ? $edit->settings['font_format'] : 'p;div;pre;address;h1;h2;h3;h4;h5;h6',
1525 '#size' => 40,
1526 '#maxlength' => 250,
1527 '#description' => t('Semicolon separated list of HTML font formats. Allowed values are: p;div;pre;address;h1;h2;h3;h4;h5;h6'),
1528 );
1529
1530 $form['output']['format_source'] = array(
1531 '#type' => 'select',
1532 '#title' => t('Apply source formatting'),
1533 '#default_value' => $edit->settings['format_source'] ? $edit->settings['format_source'] : 't',
1534 '#options' => array('t' => 'true', 'f' => 'false'),
1535 '#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.'),
1536 );
1537
1538 $form['output']['format_output'] = array(
1539 '#type' => 'select',
1540 '#title' => t('Format output'),
1541 '#default_value' => $edit->settings['format_output'] ? $edit->settings['format_output'] : 't',
1542 '#options' => array('t' => 'true', 'f' => 'false'),
1543 '#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.'),
1544 );
1545
c01081e7
WW
1546 /*
1547 $form['output']['output_conf'] = array(
1548 '#type' => 'select',
1549 '#title' => t('Ignore this section, use default settings defined in config files'),
1550 '#default_value' => $edit->settings['output_conf'] ? $edit->settings['output_conf'] : 'f',
1551 '#options' => array('f' => t('false'), 't' => t('true')),
1552 '#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.'),
1553 );
1554 */
0c87a920
WW
1555
1556 $form['css'] = array(
1557 '#type' => 'fieldset',
1558 '#title' => t('CSS'),
1559 '#collapsible' => TRUE,
1560 '#collapsed' => TRUE
1561 );
1562
1563 $form['css']['css_mode'] = array(
1564 '#type' => 'select',
1565 '#title' => t('Editor CSS'),
1566 '#default_value' => $edit->settings['css_mode'] ? $edit->settings['css_mode'] : 'theme',
1567 '#options' => array('theme' => t('use theme css'), 'self' => t('define css'), 'none' => t('FCKeditor default')),
1568 '#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.')
1569 );
1570
1571 $form['css']['css_path'] = array(
1572 '#type' => 'textfield',
1573 '#title' => t('CSS path'),
1574 '#default_value' => $edit->settings['css_path'],
1575 '#size' => 40,
1576 '#maxlength' => 255,
c01081e7 1577 '#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' => path_to_theme() .'/'))
0c87a920
WW
1578 );
1579
1580 $form['css']['css_style'] = array(
c01081e7
WW
1581 '#type' => 'select',
1582 '#title' => t('Predefined styles'),
1583 '#default_value' => $edit->settings['css_style'] ? $edit->settings['css_style'] : 'theme',
1584 '#options' => array('theme' => t('use theme fckstyles.xml'), 'self' => t('define path to fckstyles.xml'), 'default' => t('FCKeditor default')),
1585 '#description' => t('Define the location of <code>fckstyles.xml</code> file. It is used by the &quot;Style&quot; 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'))
0c87a920
WW
1586 );
1587
c01081e7
WW
1588 $form['css']['styles_path'] = array(
1589 '#type' => 'textfield',
1590 '#title' => t('Predefined styles path'),
1591 '#default_value' => $edit->settings['styles_path'],
1592 '#size' => 40,
1593 '#maxlength' => 255,
1594 '#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' => path_to_theme() .'/', '!module' => drupal_get_path('module', 'fckeditor')))
0c87a920 1595 );
c01081e7
WW
1596
1597 // don't show useless options if IMCE is preferred
1598 if (function_exists('imce_integrate') && variable_get('imce_settings_fck', 0)) {
1599 $form['fckeditor_upload_settings'] = array(
1600 '#type' => 'fieldset',
1601 '#title' => t('File browser settings'),
1602 '#collapsible' => TRUE,
1603 '#collapsed' => TRUE,
1604 '#description' => t('The file browser settings are not diplayed because you have configured IMCE to handle file browsing.')
1605 );
1606 }
1607 else {
1608 $form['fckeditor_upload_settings'] = array(
1609 '#type' => 'fieldset',
1610 '#title' => t('File browser settings'),
1611 '#collapsible' => TRUE,
1612 '#collapsed' => TRUE,
1613 '#description' => t('Set file browser settings. If you enable file uploads and disable basic and advanced file management, you will need to manage your images and other files with the core upload module or a contrib module like !imce. Please note that these options require manual configuration, check !readme for more information.<br />',
1614 array(
1615 '!imce' => l(t('IMCE'), 'http://drupal.org/project/imce'),
1616 '!readme' => l('readme.txt', 'admin/help/fckeditor'),
1617 )
1618 )
1619 );
1620 $form['fckeditor_upload_settings']['upload_basic'] = array(
1621 '#type' => 'select',
1622 '#options' => array('f' => t('false'), 't' => t('true')),
1623 '#title' => t('Allow basic file management'),
1624 '#default_value' => $edit->settings['upload_basic'] ? $edit->settings['upload_basic'] : 'f',
1625 '#description' => t("Allow quick uploads."),
1626 );
1627 $form['fckeditor_upload_settings']['upload_advanced'] = array(
1628 '#type' => 'select',
1629 '#options' => array('f' => t('false'), 't' => t('true')),
1630 '#title' => t('Allow advanced file management'),
1631 '#default_value' => $edit->settings['upload_advanced'] ? $edit->settings['upload_advanced'] : 'f',
1632 '#description' => t('Allow file management in the advanced file manager.'),
1633 );
1634
1635 $current_user_files_path = strtr($edit->settings['UserFilesPath'], array("%f" => file_directory_path(), "%u" => "UID", "%b" => base_path()));
1636 $current_user_files_absolute_path = strtr($edit->settings['UserFilesAbsolutePath'], array("%f" => file_directory_path(), "%u" => "UID", "%b" => base_path(), "%d" => $_SERVER['DOCUMENT_ROOT']));
1637
1638 $form['fckeditor_upload_settings']['UserFilesPath'] = array(
1639 '#type' => 'textfield',
1640 '#title' => t('Path to uploaded files'),
1641 '#default_value' => $edit->settings['UserFilesPath'] ? $edit->settings['UserFilesPath'] : "%b%f/",
1642 '#size' => 40,
1643 '#maxlength' => 255,
1644 '#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())),
1645 );
1646 $form['fckeditor_upload_settings']['UserFilesAbsolutePath'] = array(
1647 '#type' => 'textfield',
1648 '#title' => t('Absolute path to uploaded files'),
1649 '#default_value' => $edit->settings['UserFilesAbsolutePath'] ? $edit->settings['UserFilesAbsolutePath'] : "%d%b%f/",
1650 '#size' => 40,
1651 '#maxlength' => 255,
1652 '#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'])),
1653 );
1654 }
1655
1656 $form['advanced'] = array(
0c87a920 1657 '#type' => 'fieldset',
c01081e7 1658 '#title' => t('Advanced options'),
0c87a920
WW
1659 '#collapsible' => TRUE,
1660 '#collapsed' => TRUE,
0c87a920 1661 );
c01081e7
WW
1662 $form['advanced']['js_conf'] = array(
1663 '#type' => 'textarea',
1664 '#title' => t('Custom javascript configuration'),
1665 '#default_value' => $edit->settings['js_conf'],
1666 '#cols' => 60,
1667 '#rows' => 5,
1668 '#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',
1669 array(
1670 '!fckeditor_config' => drupal_get_path('module', 'fckeditor') ."/fckeditor.config.js",
1671 '!docs' => l(t("FCKeditor documentation"), "http://docs.fckeditor.net/FCKeditor_2.x/Developers_Guide/Configuration/Configuration_Options"),
1672 "!example" => "<pre>LinkDlgHideTarget = true ;
1673LinkDlgHideAdvanced = true ;
1674ImageDlgHideLink = true ;
1675ImageDlgHideAdvanced = true ;
1676FlashDlgHideAdvanced = true ;</pre>")
1677));
0c87a920
WW
1678
1679$form['submit'] = array(
1680'#type' => 'submit',
1681'#value' => $btn
1682);
1683
1684return $form;
1685}
1686
1687/**
e44c2389 1688 * Search the field id for matches in array of matches
1689 *
1690 * @param $search
1691 * A string representing a form field id
1692 * @ param $array
1693 * An $array with strings to match the $search parameter against
1694 *
1695 * @return
1696 * TRUE on match, FALSE on no match
23824481 1697 */
1698function fckeditor_idsearch($search, $array) {
1699 foreach ($array as $key => $value) {
c01081e7 1700 if (!empty($value) && preg_match('/^'. str_replace('*', '.*', addslashes($value)) .'$/i', $search)) {
23824481 1701 // on any first match we know we're done here so return positive
1702 return true;
f3d88ca0 1703 }
f3d88ca0 1704 }
23824481 1705 return false;
f3d88ca0 1706}
04b827fa
DS
1707
1708/**
e44c2389 1709 * Test if client can render the FCKeditor
0c87a920
WW
1710 * Use built-in test method in fckeditor.php
1711 * If fckeditor.php is not found, return false (probably in such case fckeditor is not installed correctly)
e44c2389 1712 *
1713 * @return
1714 * TRUE if the browser is reasonably capable
04b827fa
DS
1715 */
1716function fckeditor_is_compatible_client() {
ebc6fdec 1717
c01081e7 1718 $fckeditor_main_file = drupal_get_path('module', 'fckeditor') .'/fckeditor/fckeditor.php';
0c87a920
WW
1719 if (file_exists($fckeditor_main_file)) {
1720 include $fckeditor_main_file;
1721 if (function_exists('FCKeditor_IsCompatibleBrowser')) {
1722 return FCKeditor_IsCompatibleBrowser();
1723 }
1724 else {
1725 $fck = new FCKeditor("fake");
1726 return $fck->IsCompatible();
1727 }
1728 }
1729
1730 return false;
1731}
1732
c01081e7 1733function fckeditor_user_get_setting($user, $profile, $setting) {
0c87a920
WW
1734 $default = array(
1735 'default' => 't',
1736 'show_toggle' => 't',
1737 'popup' => 'f',
1738 'skin' => 'default',
1739 'toolbar' => 'default',
1740 'expand' => 't',
1741 'width' => '100%',
1742 'lang' => 'en',
1743 'auto_lang' => 't',
1744 );
1745 $settings = $profile->settings;
1746
1747 if ($settings['allow_user_conf']) {
c01081e7 1748 $status = isset($user->{"fckeditor_". $setting}) ? $user->{"fckeditor_". $setting} : (isset($settings[$setting]) ? $settings[$setting] : $default[$setting]);
04b827fa 1749 }
0c87a920
WW
1750 else {
1751 $status = isset($settings[$setting]) ? $settings[$setting] : $default[$setting];
04b827fa 1752 }
0c87a920
WW
1753
1754 return $status;
1755}
1756
1757function fckeditor_user_get_profile($account) {
1758 $profile_name = db_result(db_query('SELECT s.name FROM {fckeditor_settings} s INNER JOIN {fckeditor_role} r ON r.name = s.name WHERE r.rid IN (%s)', implode(',', array_keys($account->roles))));
c01081e7 1759 if ($profile_name) {
0c87a920
WW
1760 return fckeditor_profile_load($profile_name);
1761 }
1762 else {
1763 return FALSE;
1764 }
1765}
1766
1767function fckeditor_init() {
1768 drupal_add_css(drupal_get_path('module', 'fckeditor') .'/fckeditor.css');
c01081e7 1769}