some more clarification of the instructions
[project/fckeditor.git] / fckeditor.module
CommitLineData
04b827fa 1<?php
e44c2389 2// $Id$
3/**
4 * @file
f3d88ca0 5 * FCKeditor Module for Drupal 4.7
ebc6fdec 6 *
e44c2389 7 * This module allows Drupal to replace textarea fields with the FCKeditor.
8 * This HTML text editor brings many of the powerful functionalities of
9 * known desktop editors like Word to the web. It's relatively lightweight
10 * and doesn't require any kind of installation on the client computer.
f3d88ca0 11 *
12 * ----------------------------------------------------------------------------
04b827fa 13 * FCKeditor - The text editor for internet
f3d88ca0 14 * Copyright (C) 2003-2006 Frederico Caldeira Knabben
ebc6fdec 15 *
04b827fa 16 * Licensed under the terms of the GNU Lesser General Public License:
f3d88ca0 17 * http://www.opensource.org/licenses/lgpl-license.php
ebc6fdec 18 *
04b827fa 19 * For further information visit:
f3d88ca0 20 * http://www.fckeditor.net/
f3d88ca0 21 * ----------------------------------------------------------------------------
04b827fa
DS
22 *
23 * @version 1.0
24 * @author LatPro Inc (George)
f3d88ca0 25 * @version 1.1
26 * @author Frederico Caldeira Knabben (www.fckeditor.net)
27 * @version 1.2
28 * @author Ontwerpwerk (www.ontwerpwerk.nl)
04b827fa
DS
29 */
30
31
32/**
33 * Implementation of hook_help
34 */
35function fckeditor_help($section = '') {
e44c2389 36 switch($section) {
37 case 'admin/modules#name':
38 $output = t("FCKeditor");
39 break;
40 case 'admin/modules#description':
41 $output = t("Enables the usage of FCKeditor (WYSIWYG editor) instead of plain text fields.");
42 break;
43 case 'admin/help#fckeditor':
44 $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>
ccd18229 45<p>More information is located at the %fckeditorlink. A small user guide is located at %userguidelink.</p>", array('%fckeditorlink'=>l(t('FCKeditor homepage'), 'http://www.fckeditor.net'), '%userguidelink'=>l(t('FCKeditor userguide'), 'http://wiki.fckeditor.net/UsersGuide')));
92b2e6cf 46 $output .= t('<h3>Security</h3>
47<p>Note that enabling file uploads is a security risk, please take care about to who and when you will grant access.</p>');
e44c2389 48 // the rest is untranslated for the moment
b683d2b1 49 $output .= "<h3>How to enable the file browser (in FCKeditor 2.3.x)</h3>
e44c2389 50<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>
51<p>To enable file browsing you need to edit the connector configuration file in your fckeditor module directory, the file should be in:<br /><code>/fckeditor/editor/filemanager/browser/default/connectors/php/config.php</code></p>
ccd18229 52<p>In this file you will need to enable the file browser:<br /><code>$ Config['Enabled'] = true;</code></p>
53<p>To use the drupal files directory you also need to comment out the following line in the connector configuration:<br /><code>//$ Config['UserFilesPath'] = '/UserFiles/';</code></p>
b683d2b1 54<p>Furthermore, you will need to create a <em>'File'</em>, an <em>'Image'</em> and a <em>'Flash'</em> subdirectory in your drupal files directory ('".file_directory_path()."'). These directories must have the same privileges as the drupal files directory. In some cases these directories must be world writable (chmod 0777).</p>";
e44c2389 55 break;
04b827fa
DS
56 }
57 return $output;
58}
59
60
61/**
62 * Implementation of hook_perm
63 */
64function fckeditor_perm() {
92b2e6cf 65 return array('use default fckeditor', 'use advanced fckeditor', 'allow fckeditor file uploads');
04b827fa
DS
66}
67
04b827fa 68/**
e44c2389 69 * Implementation of hook_elelments
70 *
71 * Adds an extra procession instruction to the form rendering for textareas
72 *
73 * @return $type
74 * Additional array for the element configuration
04b827fa 75 */
f3d88ca0 76function fckeditor_elements() {
77 $type = array();
ebc6fdec 78 if (user_access('use advanced fckeditor') || user_access('use default fckeditor')) {
f3d88ca0 79 // only roles with permission get the fckeditor
80 if (fckeditor_is_compatible_client()) {
81 // it would be useless to dig deeper if we're not able or allowed to
82 $type['textarea'] = array(
83 '#process' => array(
84 'fckeditor_process_textarea' => array()
85 ),
86 );
04b827fa
DS
87 }
88 }
f3d88ca0 89 return $type;
04b827fa
DS
90}
91
04b827fa
DS
92/**
93 * Implementation of hook_setting().
e44c2389 94 *
95 * Configuration for the FCKeditor module
04b827fa
DS
96 */
97function fckeditor_settings() {
f3d88ca0 98 // Settings form
e44c2389 99 $toolbar_options = array(
100 'Default' => 'Default',
101 'DrupalFull' => 'Drupal Full',
102 'DrupalBasic' => 'Drupal Basic',
103 'Basic' => 'Basic',
104 );
ebc6fdec 105
f3d88ca0 106 // Generate the form - settings applying to all patterns first
107 $form['fckeditor_settings'] = array(
108 '#type' => 'fieldset',
109 '#weight' => -20,
110 '#title' => t('Basic settings'),
111 '#collapsible' => TRUE,
e44c2389 112 '#collapsed' => FALSE,
f3d88ca0 113 );
e44c2389 114
115 $form['fckeditor_settings']['fckeditor_popup'] = array(
116 '#type' => 'checkbox',
117 '#title' => t('Use FCKeditor in a popup window'),
118 '#default_value' => variable_get('fckeditor_popup', '0'),
119 '#description' => t('If this option is selected a link to a popup window will be used instead of a textarea replace.'),
120 );
121
f3d88ca0 122 $form['fckeditor_settings']['fckeditor_default_toolbar'] = array(
123 '#type' => 'select',
124 '#title' => t('Default Toolbar'),
125 '#default_value' => variable_get('fckeditor_default_toolbar', 'DrupalBasic'),
126 '#options' => $toolbar_options,
127 '#description' => t('Choose a default toolbar set.'),
128 );
e44c2389 129
f3d88ca0 130 $form['fckeditor_settings']['fckeditor_advanced_toolbar'] = array(
131 '#type' => 'select',
132 '#title' => t('Advanced Toolbar'),
133 '#default_value' => variable_get('fckeditor_advanced_toolbar', 'DrupalFull'),
134 '#options' => $toolbar_options,
135 '#description' => t('Choose a toolbar set for administrators.'),
136 );
04b827fa 137
f3d88ca0 138 $form['fckeditor_exclude_settings'] = array(
139 '#type' => 'fieldset',
140 '#weight' => -15,
141 '#title' => t('Exclusion settings'),
142 '#collapsible' => TRUE,
143 '#collapsed' => TRUE,
144 );
e44c2389 145
f3d88ca0 146 $form['fckeditor_exclude_settings']['fckeditor_minimum_rows'] = array(
147 '#type' => 'textfield',
148 '#title' => t('Minimum rows'),
149 '#default_value' => variable_get('fckeditor_minimum_rows', 5),
e44c2389 150 '#description' => t("Textareas must have a minimum of rows before FCKeditor will be triggered. Enter '1' if you do not want to use this feature."),
f3d88ca0 151 );
e44c2389 152
153 /**
154 * get excluded fields - so we can have normal textareas too
155 * split the phrase by any number of commas or space characters,
156 * which include " ", \r, \t, \n and \f
157 */
f3d88ca0 158 $form['fckeditor_exclude_settings']['fckeditor_exclude'] = array(
159 '#type' => 'textarea',
ccd18229 160 '#title' => t('Exclude fields'),
f3d88ca0 161 '#cols' => 60,
162 '#rows' => 5,
163 '#default_value' => variable_get("fckeditor_exclude", ''),
164 '#description' => t("Names (HTML ID's) of fields that may not have an FCKeditor (separated by commas, spaces or newlines. You may also use * for a wildcard)"),
165 );
166
167 $form['fckeditor_special_settings'] = array(
168 '#type' => 'fieldset',
169 '#weight' => -10,
170 '#title' => t('Advanced settings'),
171 '#collapsible' => TRUE,
172 '#collapsed' => TRUE,
173 );
e44c2389 174
f3d88ca0 175 $form['fckeditor_special_settings']['fckeditor_toolbar_start_expanded'] = array(
176 '#type' => 'checkbox',
177 '#title' => t('Start the toolbar expanded'),
178 '#default_value' => variable_get('fckeditor_toolbar_start_expanded', '1'),
179 '#description' => t('The toolbar start expanded or collapsed.'),
180 );
e44c2389 181
f3d88ca0 182 $form['fckeditor_special_settings']['fckeditor_width'] = array(
183 '#type' => 'textfield',
184 '#title' => t('Width'),
185 '#default_value' => variable_get("fckeditor_width", "100%"),
9286dec5 186 '#description' => t("Width in pixels or percent. Ex: 400 or 100%"),
f3d88ca0 187 );
188
e44c2389 189 // People might want other skins, but lets be evil and not let them have them that easy
f3d88ca0 190 $form['fckeditor_skin'] = array('#type' => 'value', '#value' => variable_get('fckeditor_skin', 'default'));
191
192 return $form;
ebc6fdec 193}
04b827fa
DS
194
195
196/**
9286dec5 197 * This function create the HTML objects required for the FCKeditor
e44c2389 198 *
199 * @param $element
200 * A fully populated form elment to add the editor to
201 * @return
202 * The same $element with extra FCKeditor markup and initialization
04b827fa 203 */
f3d88ca0 204function fckeditor_process_textarea($element) {
205 $exclude = preg_split("/[\s,]+/", strip_tags(variable_get("fckeditor_exclude", '')));
206
ccd18229 207 if (($element['#rows'] > variable_get('fckeditor_minimum_rows', 5))
23824481 208 && !fckeditor_idsearch($element['#id'], $exclude)) {
e44c2389 209 // only replace textarea when it has enough rows and it is not in the exclusion list
f3d88ca0 210
211 // setting some variables
25f91b44 212 $module_drupal_path = drupal_get_path('module', 'fckeditor');
213 $module_full_path = base_path() . $module_drupal_path;
e44c2389 214 // '-' in a javascript id will not work
f3d88ca0 215 $js_id = 'oFCKeditor_' . str_replace('-', '_', $element['#id']);
216
217 // configured in settings
218 $width = variable_get("fckeditor_width", '100%');
219
220 // sensible default for small toolbars
e44c2389 221 $height = $element['#rows'] * 14 + 100;
f3d88ca0 222
223 // nessecary because FCKeditor interferes with resize script
224 $element['#resizable'] = FALSE;
225
25f91b44 226 drupal_add_js($module_drupal_path . '/fckeditor/fckeditor.js');
f3d88ca0 227
228 if (user_access('use advanced fckeditor')) {
229 $toolbar = variable_get("fckeditor_advanced_toolbar", 'DrupalFull');
230 $height += 100; // sensible default for admin toolbars toolbars
e44c2389 231 }
232 else {
f3d88ca0 233 $toolbar = variable_get("fckeditor_default_toolbar", 'DrupalBasic');
234 }
235
e44c2389 236 $element['#suffix'] .= "\n<script type=\"text/javascript\">
f3d88ca0 237var ".$js_id." = new FCKeditor( '".$element['#id']."' );
25f91b44 238".$js_id.".BasePath = '".$module_full_path."/fckeditor/';
239".$js_id.".Config['CustomConfigurationsPath'] = '".$module_full_path."/fckeditor.config.js';
f3d88ca0 240".$js_id.".ToolbarSet = '".$toolbar."';
92b2e6cf 241".$js_id.".Height = '".$height."';\n";
e44c2389 242
243 // add code for filebrowser for users that have access
92b2e6cf 244 if (user_access('allow fckeditor file uploads')) {
245 $element['#suffix'] .= $js_id.".Config['LinkBrowserURL'] = '".$module_full_path."/fckeditor/editor/filemanager/browser/default/browser.html?Connector=connectors/php/connector.php&ServerPath=/".variable_get("file_directory_path", 'files')."';
e44c2389 246".$js_id.".Config['ImageBrowserURL'] = '".$module_full_path."/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/php/connector.php&ServerPath=/".variable_get("file_directory_path", 'files')."';
92b2e6cf 247".$js_id.".Config['FlashBrowserURL'] = '".$module_full_path."/fckeditor/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=connectors/php/connector.php&ServerPath=/".variable_get("file_directory_path", 'files')."';
248".$js_id.".Config['LinkUpload'] = false;
249".$js_id.".Config['ImageUpload'] = false;
250".$js_id.".Config['FlashUpload'] = false;\n";
251 } else {
252 $element['#suffix'] .= $js_id.".Config['LinkBrowser'] = false;
253".$js_id.".Config['ImageBrowser'] = false;
254".$js_id.".Config['FlashBrowser'] = false;
255".$js_id.".Config['LinkUpload'] = false;
256".$js_id.".Config['ImageUpload'] = false;
257".$js_id.".Config['FlashUpload'] = false;\n";
258 }
e44c2389 259
92b2e6cf 260 $element['#suffix'] .= "</script>\n";
f3d88ca0 261
262 if (variable_get('fckeditor_popup', '0')) {
263 // Add the script file with the popup open function.
25f91b44 264 drupal_add_js($module_drupal_path . '/fckeditor.popup.js');
e44c2389 265 $element['#title'] .= " <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>";
266 }
267 else {
f3d88ca0 268 // if no popup mode, add the editor
e44c2389 269 $element['#suffix'] .="<script type=\"text/javascript\">
f3d88ca0 270 ".$js_id.".ReplaceTextarea();
92b2e6cf 271</script>\n";
f3d88ca0 272 }
273 }
f3d88ca0 274 return $element;
04b827fa
DS
275}
276
23824481 277
278/**
e44c2389 279 * Search the field id for matches in array of matches
280 *
281 * @param $search
282 * A string representing a form field id
283 * @ param $array
284 * An $array with strings to match the $search parameter against
285 *
286 * @return
287 * TRUE on match, FALSE on no match
23824481 288 */
289function fckeditor_idsearch($search, $array) {
290 foreach ($array as $key => $value) {
291 if (!empty($value) && preg_match('/^'.str_replace('*','.*',$value).'$/i', $search)) {
292 // on any first match we know we're done here so return positive
293 return true;
f3d88ca0 294 }
f3d88ca0 295 }
23824481 296 return false;
f3d88ca0 297}
04b827fa 298
23824481 299
04b827fa 300/**
e44c2389 301 * Test if client can render the FCKeditor
302 *
303 * Check the user agent for a matching browser,
304 * using HTTP_USER_AGENT because the browsers that are known to support FCKeditor are limited
305 *
306 * @return
307 * TRUE if the browser is reasonably capable
04b827fa
DS
308 */
309function fckeditor_is_compatible_client() {
e44c2389 310 $useragent = $_SERVER['HTTP_USER_AGENT'];
ebc6fdec 311
e44c2389 312 if (strpos($useragent, 'MSIE') !== false && strpos($useragent, 'mac') === false && strpos($useragent, 'Opera') === false) {
313 $browserversion = (int)substr($useragent, strpos($useragent, 'MSIE') + 5, 3);
314 return ($browserversion >= 5.5);
04b827fa 315 }
ccd18229 316 elseif (strpos($useragent, 'Gecko') !== false) {
e44c2389 317 $browserversion = (int)substr($useragent, strpos($useragent, 'Gecko/') + 6, 8);
318 return ($browserversion >= 20030210);
04b827fa
DS
319 }
320 else
321 return false;
322}