| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: fckeditor.admin.inc,v 1.1.2.53 2010/03/08 11:06:44 jorrit Exp $ 3 /** 4 * FCKeditor - The text editor for Internet - http://www.fckeditor.net 5 * Copyright (C) 2003-2008 Frederico Caldeira Knabben 6 * 7 * == BEGIN LICENSE == 8 * 9 * Licensed under the terms of any of the following licenses at your 10 * choice: 11 * 12 * - GNU General Public License Version 2 or later (the "GPL") 13 * http://www.gnu.org/licenses/gpl.html 14 * 15 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") 16 * http://www.gnu.org/licenses/lgpl.html 17 * 18 * - Mozilla Public License Version 1.1 or later (the "MPL") 19 * http://www.mozilla.org/MPL/MPL-1.1.html 20 * 21 * == END LICENSE == 22 * 23 * @file 24 * FCKeditor Module for Drupal 6.x 25 * 26 * This module allows Drupal to replace textarea fields with FCKeditor. 27 * 28 * This HTML text editor brings to the web many of the powerful functionalities 29 * of known desktop editors like Word. It's really lightweight and doesn't 30 * require any kind of installation on the client computer. 31 */ 32 33 /** 34 * Main administrative page 35 */ 36 function fckeditor_admin_main() { 37 $editor_path = fckeditor_path(TRUE); 38 $fckconfig_file = $editor_path .'/fckconfig.js'; 39 if (!file_exists($fckconfig_file)) { 40 drupal_set_message( 41 t('The FCKeditor component appears to be not installed correctly, because %checkfile could not be found.', 42 array( 43 '%checkfile' => $fckconfig_file, 44 )) .'<br/>'. 45 t('Please go to the !fckeditorlink to download the latest version. After that you must extract the files to %fckeditorpath and make sure that the directory %fckeditorsubdir and the file %fckeditorfile exist. Refer to the !readme for more information.', 46 array( 47 '!fckeditorlink' => l(t('FCKeditor homepage'), 'http://ckeditor.com/download'), 48 '!readme' => l(t('readme.txt'), 'admin/help/fckeditor'), 49 '%fckeditorpath' => $editor_path, 50 '%fckeditorsubdir' => $editor_path .'/editor', 51 '%fckeditorfile' => $editor_path .'/fckeditor.js', 52 )), 'error'); 53 drupal_set_message(t('If you have FCKeditor already installed please edit !editgloballink and update FCKeditor path.', 54 array( 55 '!editgloballink' => l(t('FCKeditor Global Profile'), 'admin/settings/fckeditor/editg'), 56 )), 'warning'); 57 return FALSE; 58 } 59 60 $access_fckeditor_roles = user_roles(FALSE, 'access fckeditor'); 61 if (!$access_fckeditor_roles) { 62 drupal_set_message(t('There is currently no role with the %accesspermission permission. Visit !permissionslink administration section.', 63 array( 64 '%accesspermission' => t('access fckeditor'), 65 '!permissionslink' => l(t('permissions'), 'admin/user/permissions') 66 )), 'warning'); 67 } 68 else { 69 $result = db_query_range("SELECT name FROM {fckeditor_settings} WHERE name <> 'FCKeditor Global Profile'", 0, 1); 70 $has_profiles = FALSE; 71 //find profile other than Global 72 if (($obj = db_fetch_object($result))) { 73 $has_profiles = TRUE; 74 } 75 76 //find roles with profiles 77 $result = db_query("SELECT rid FROM {fckeditor_role}"); 78 $rids = array(); 79 while (($obj = db_fetch_object($result))) { 80 $rids[] = $obj->rid; 81 } 82 $rids = array_unique($rids); 83 if (!$has_profiles) { 84 drupal_set_message(t('No FCKeditor profiles found. At this moment, nobody is able to use FCKeditor. Create new profile below.'), 'error'); 85 } 86 else { 87 //not all roles with access fckeditor has their FCKeditor profile assigned 88 $diff = array_diff(array_keys($access_fckeditor_roles), $rids); 89 if ($diff) { 90 $items = array(); 91 foreach ($diff as $rid) { 92 $items[] = $access_fckeditor_roles[$rid]; 93 } 94 drupal_set_message(t('Not all roles with %accesspermission permission are associated with FCKeditor profiles. As a result, users having the following roles may be unable to use FCKeditor: !list Create new or edit FCKeditor profiles below and in the %basicsetupsection section, check %rolesetting.', 95 array( 96 '%accesspermission' => t('access fckeditor'), 97 '%basicsetupsection' => t('Basic setup'), 98 '%rolesetting' => t('Roles allowed to use this profile'), 99 '!list' => theme('item_list', $items), 100 )), 'warning'); 101 } 102 } 103 } 104 105 return fckeditor_profile_overview(); 106 } 107 108 /** 109 * Controller for fckeditor profiles. 110 */ 111 function fckeditor_profile_overview() { 112 $output = ''; 113 114 $profiles = fckeditor_profile_load(); 115 if ($profiles) { 116 $access_fckeditor_roles = user_roles(FALSE, 'access fckeditor'); 117 $header = array(t('Profile'), t('Roles'), t('Operations')); 118 foreach ($profiles as $p) { 119 $rids = $p->rids; 120 if ($p->name !== 'FCKeditor Global Profile') { 121 foreach (array_keys($p->rids) as $rid) { 122 if (!isset($access_fckeditor_roles[$rid])) { 123 unset($rids[$rid]); 124 } 125 } 126 $rows[] = array( 127 array('data' => $p->name, 'valign' => 'top'), 128 array('data' => implode("<br />\n", $rids)), 129 array('data' => 130 l(t('edit'), 'admin/settings/fckeditor/edit/'. rawurlencode($p->name)) .' '. 131 l(t('clone'), 'admin/settings/fckeditor/clone/'. rawurlencode($p->name)) .' '. 132 l(t('delete'), 'admin/settings/fckeditor/delete/'. rawurlencode($p->name)), 'valign' => 'top' 133 ) 134 ); 135 } 136 } 137 $output .= '<h3>'. t('Profiles') .'</h3>'; 138 $output .= theme('table', $header, $rows); 139 $output .= '<p>'. l(t('Create new profile'), 'admin/settings/fckeditor/add') .'</p>'; 140 } 141 else { 142 drupal_set_message(t('No profiles found. Click here to !createlink.', 143 array( 144 '!createlink' => l(t('create a new profile'), 'admin/settings/fckeditor/add'), 145 ))); 146 } 147 148 $rows = array(); 149 if (!isset($profiles['FCKeditor Global Profile'])) { 150 drupal_set_message(t('Global profile not found. Click here to !createlink.', 151 array( 152 '!createlink' => l(t('create the global profile'), 'admin/settings/fckeditor/addg'), 153 ))); 154 } 155 else { 156 $output .= '<h3>'. t('Global settings') .'</h3>'; 157 $rows[] = array( 158 array('data' => t('FCKeditor Global Profile'), 'valign' => 'top'), 159 array('data' => l(t('edit'), 'admin/settings/fckeditor/editg') .' '. l(t('delete'), 'admin/settings/fckeditor/delete/FCKeditor Global Profile'), 'valign' => 'top') 160 ); 161 $output .= theme('table', array(t('Profile'), t('Operations')), $rows); 162 } 163 return $output; 164 } 165 166 /** 167 * Clone profile 168 */ 169 function fckeditor_admin_profile_clone_form($form_state, $oldprofile) { 170 return fckeditor_admin_profile_form($form_state, $oldprofile); 171 } 172 173 function fckeditor_admin_profile_clone_form_validate($form_state, $oldprofile) { 174 fckeditor_admin_profile_form_validate($form_state, $oldprofile); 175 } 176 177 function fckeditor_admin_profile_clone_form_submit($form, &$form_state) { 178 $edit =& $form_state['values']; 179 drupal_set_message(t('Your FCKeditor profile has been created.')); 180 $settings = fckeditor_admin_values_to_settings($edit); 181 db_query("INSERT INTO {fckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], $settings); 182 fckeditor_rebuild_selectors($edit['name']); 183 if (!empty($edit['rids'])) { 184 foreach (array_keys($edit['rids']) as $rid) { 185 if ($edit['rids'][$rid]!=0) { 186 db_query("INSERT INTO {fckeditor_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid); 187 } 188 } 189 } 190 $form_state['redirect'] = 'admin/settings/fckeditor'; 191 } 192 193 /** 194 * Form builder for a normal profile 195 */ 196 function fckeditor_admin_profile_form($form_state, $profile = NULL) { 197 if ($profile != NULL) { 198 $form['_profile'] = array( 199 '#type' => 'value', 200 '#value' => $profile, 201 ); 202 } 203 else { 204 $profile = new stdClass(); 205 } 206 207 module_load_include('lib.inc', 'fckeditor'); 208 209 $toolbar_options = fckeditor_load_toolbar_options(); 210 $skin_options = fckeditor_load_skin_options(); 211 $lang_options = fckeditor_load_lang_options(); 212 213 // Only display the roles that currently don't have a fckeditor profile. One 214 // profile per role. 215 $orig_roles = user_roles(FALSE, 'access fckeditor'); 216 $roles = $orig_roles; 217 218 if (!empty($profile->rids) && !user_roles(FALSE, 'access fckeditor')) { 219 drupal_set_message(t('You haven\'t assigned %accesspermission !permissionslink yet. It is recommended to assign the %accesspermission !permissionslink before updating FCKeditor profiles.', 220 array( 221 '%accesspermission' => t('access fckeditor'), 222 '!permissionslink' => l(t('permission'), 'admin/user/permissions'), 223 )), 'warning'); 224 } 225 226 if (empty($profile->name)) { 227 $result = db_query("SELECT DISTINCT(rid) FROM {fckeditor_role}"); 228 while (($data = db_fetch_object($result))) { 229 if ((empty($profile->rids) || !in_array($data->rid, array_keys((array) $profile->rids))) && !form_get_errors()) { 230 unset($roles[$data->rid]); 231 } 232 } 233 if (count($orig_roles) != count($roles)) { 234 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.')); 235 } 236 } 237 238 $form['basic'] = array( 239 '#type' => 'fieldset', 240 '#title' => t('Basic setup'), 241 '#collapsible' => TRUE, 242 '#collapsed' => TRUE 243 ); 244 245 if (arg(3) == 'clone') { 246 //load all profiles to check their names 247 $profiles = fckeditor_profile_load(); 248 $oldname = $profile->name; 249 $maxsize=128; //default max name length 250 251 $res=array(); 252 $pat = "/^(?P<name>.*?)_(?P<n>[0-9]*)$/"; 253 if (preg_match_all($pat, $oldname, $res)) { // oldname like 'name_nr' 254 $name=$res['name'][0]; 255 $num=$res['n'][0]+1; 256 } 257 else{ 258 $name=$oldname; 259 $num=2; 260 } 261 262 $newname=substr($name, 0, $maxsize-3) .'_'. $num; // +limit 263 while (isset($profiles[$newname])) { //find next free number 264 $num++; 265 $newname=substr($name, 0, $maxsize-3) .'_'. $num; 266 267 } 268 //dont clone rids 269 $profile->settings['rids']=array(); 270 $profile->rids=array(); 271 } 272 else { 273 $newname = $profile->name; 274 } 275 276 $form['basic']['name'] = array( 277 '#type' => 'textfield', 278 '#title' => t('Profile name'), 279 '#default_value' => !empty($profile->name) ? $newname : '', 280 '#size' => 40, 281 '#maxlength' => 128, 282 '#description' => t('Enter a name for this profile. This name is only visible within the fckeditor administration page.'), 283 '#required' => TRUE 284 ); 285 286 $form['basic']['rids'] = array( 287 '#type' => 'checkboxes', 288 '#title' => t('Roles allowed to use this profile'), 289 '#default_value' => !empty($profile->rids) ? array_keys((array) $profile->rids) : array(), 290 '#options' => $roles, 291 '#description' => t('Only roles with %accesspermission permission will be shown here. If no role is available, make sure that you have assigned the %accesspermission !permissionslink.', 292 array( 293 '%accesspermission' => t('access fckeditor'), 294 '!permissionslink' => l(t('permission'), 'admin/user/permissions'), 295 )), 296 '#required' => TRUE 297 ); 298 299 $form['basic']['allow_user_conf'] = array( 300 '#type' => 'radios', 301 '#title' => t('Allow users to customize FCKeditor appearance'), 302 '#default_value' => !empty($profile->settings['allow_user_conf']) ? $profile->settings['allow_user_conf'] : 'f', 303 '#options' => array( 304 'f' => t('No'), 305 't' => t('Yes') 306 ), 307 '#description' => t('If allowed, users will be able to override the %appearancesection by visiting their profile page.', array('%appearancesection' => t('Editor appearance'))), 308 ); 309 310 $form['security'] = array( 311 '#type' => 'fieldset', 312 '#title' => t('Security'), 313 '#description' => '<p>'. t('The FCKeditor security system protects you from executing malicious code that is already in your database. In plain text areas database content is harmless because it is not executed, but the FCKeditor WYSIWYG editor evaluates HTML like a web browser and content needs to be filtered before it is loaded.') .'</p>', 314 '#collapsible' => TRUE, 315 '#collapsed' => TRUE 316 ); 317 318 $all = filter_list_all(); 319 320 $form['security']['filters'] = array( 321 '#type' => 'fieldset', 322 '#title' => t('Security filters'), 323 '#description' => t('Please choose carefully all filters that protect your content (probably not all filters listed below are security filters).'), 324 '#tree' => TRUE, 325 ); 326 327 //don't bother administrator with filters that definitely are not security filters 328 $modules_with_filters_to_skip = array('amazon_filter', 'asy', 'bbcode', 'biblio', 'blockquote', 'bookpost', 'chessboard', 'citation_filter', 'codefilter', 'collapse_text', 'contextlinks', 'coolfilter', 'dialectic', 'dript', 'dme', 'drutex', 'embedfilter', 'ext_link_page', 'extlink', 'elf', 'flickr', 'flickrstickr', 'footnotes', 'formdefaults', 'freelinking', 'gallery', 'geogebra', 'geshifilter', 'gotwo', 'googtube', 'gotcha', 'gtspam', 'hidden_content', 'img_assist', 'image_filter', 'inlinetags', 'insert_view', 'insertframe', 'insertnode', 'interwiki', 'jlightbox', 'jsmath', 'language_sections', 'link_node', 'lootz', 'markdown', 'marksmarty', 'mobile_codes', 'mykml', 'nofollowlist', 'oagwt', 'paging', 'pathfilter', 'pearwiki_filter', 'php', 'pirate', 'reptag', 'scrippet', 'scripturefilter', 'signwriter', 'slideshowpro', 'smartlinebreakconverter', 'smartypants', 'smileys', 'spamspan', 'spam_tokens', 'spoiler', 'table_altrow', 'tablemanager', 'tableofcontents', 'textile', 'tooltips', 'twikifilter', 'typogrify', 'unwrap', 'urlclass', 'urlicon', 'url_replace_filter', 'username_highlighter', 'video_filter', 'quote'); 329 330 if (!isset($profile->settings['ss'])) { 331 $profile->settings['filters']['filter/0'] = 1; 332 } 333 334 foreach ($all as $id => $filter) { 335 if (in_array(strtolower($filter->module), $modules_with_filters_to_skip)) { 336 continue; 337 } 338 //skip line break converter and email -> link 339 if ($filter->module == 'filter' && in_array($filter->delta, array(1, 2))) { 340 continue; 341 } 342 $form['security']['filters'][$id] = array( 343 '#type' => 'checkbox', 344 '#title' => $filter->name, 345 '#default_value' => !empty($profile->settings['filters'][$id]), 346 '#description' => module_invoke($filter->module, 'filter', 'description', $filter->delta), 347 ); 348 } 349 350 $form['security']['ss'] = array( 351 '#type' => 'radios', 352 '#title' => t('Security settings'), 353 '#default_value' => isset($profile->settings['ss']) ? $profile->settings['ss'] : '2', 354 '#options' => array( 355 '2' => t('Always run security filters for FCKeditor.'), 356 '1' => t('Run security filters only when FCKeditor is set to start automatically.'), 357 ), 358 '#description' => t('There are two ways of starting FCKeditor: automatically and manually (via toggle or in a popup). If you decide to apply security filters only when FCKeditor starts automatically, you will not be protected when toggling manually from plain text area to FCKeditor or when using FCKeditor in a popup mode. So choose this option only, if you can detect various attacks (mainly XSS) by yourself just by looking at the HTML code.'), 359 ); 360 361 $form['fckeditor_exclude_settings'] = array( 362 '#type' => 'fieldset', 363 '#title' => t('Visibility settings'), 364 '#collapsible' => TRUE, 365 '#collapsed' => TRUE, 366 '#description' => t('The following settings are combined with the visibility settings of the global profile.'), 367 ); 368 369 $form['fckeditor_exclude_settings']['min_rows'] = array( 370 '#type' => 'textfield', 371 '#title' => t('Minimum rows'), 372 '#default_value' => !empty($profile->settings['min_rows']) ? $profile->settings['min_rows'] : '5', 373 '#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.'), 374 ); 375 376 $form['fckeditor_exclude_settings']['excl_mode'] = array( 377 '#type' => 'radios', 378 '#title' => t('Use inclusion or exclusion mode'), 379 '#default_value' => (empty($profile->settings['excl_mode']) || in_array($profile->settings['excl_mode'], array(0, 2))) ? 0 : 1, 380 '#options' => array( 381 '0' => t('Exclude'), 382 '1' => t('Include') 383 ), 384 '#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.'), 385 ); 386 387 /** 388 * get excluded fields - so we can have normal textareas too 389 * split the phrase by any number of commas or space characters, 390 * which include " ", \r, \t, \n and \f 391 */ 392 $form['fckeditor_exclude_settings']['excl'] = array( 393 '#type' => 'textarea', 394 '#title' => t('Fields to exclude/include'), 395 '#cols' => 60, 396 '#rows' => 5, 397 '#prefix' => '<div style="margin-left:20px">', 398 '#suffix' => '</div>', 399 '#default_value' => !empty($profile->settings['excl']) ? $profile->settings['excl'] : '', 400 '#description' => 401 t('Enter the paths to the textarea fields on which you want to enable or disable FCKeditor.') .' '. 402 t('Please see the !helppagelink for more information about defining field names. Short instruction is available below.', 403 array( 404 '!helppagelink' => l(t('help page'), 'admin/help/fckeditor', array('fragment' => 'fieldinclexcl')), 405 )) . 406 ' <ul>' . 407 '<li>'. t('Path structure') .': <strong>content_type@path.element_id</strong></li>'. 408 '<li>'. t('The following wildcards are available: *, ?') .'</li>'. 409 '<li>'. t('Content type is optional. You may even specify only path or field id') .'</li>'. 410 '<li>'. t('Examples') .':<ul>'. 411 '<li><em>blog@*.edit-body</em> - '. t('matches all fields of type %type called %field, on any page', array('%type' => 'blog', '%field' => 'edit-body')) . 412 '<li><em>node/add/*.edit-user-*</em> - '. t('matches fields starting with %field on pages starting with %path', array('%field' => 'edit-user-', '%path' => 'node/add/')) .'</li></ul>'. 413 '</li></ul>', 414 '#wysiwyg' => FALSE, 415 ); 416 417 $form['fckeditor_exclude_settings']['simple_incl'] = array( 418 '#type' => 'textarea', 419 '#title' => t('Force simplified toolbar on the following fields'), 420 '#cols' => 60, 421 '#rows' => 5, 422 '#default_value' => !empty($profile->settings['simple_incl']) ? $profile->settings['simple_incl'] : '', 423 '#description' => 424 t('Enter the paths to the textarea fields on which you want to force the simplified toolbar (%toolbarname).', 425 array( 426 '%toolbarname' => FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME, 427 )) .' '. 428 t('Please see the !helppagelink for more information about defining field names. Take a look at the exclusion settings (above) for short instruction.', 429 array( 430 '!helppagelink' => l(t('help page'), 'admin/help/fckeditor', array('fragment' => 'fieldinclexcl')), 431 )), 432 '#wysiwyg' => FALSE, 433 ); 434 435 $form['appearance'] = array( 436 '#type' => 'fieldset', 437 '#title' => t('Editor appearance'), 438 '#collapsible' => TRUE, 439 '#collapsed' => TRUE, 440 ); 441 442 $form['appearance']['default'] = array( 443 '#type' => 'radios', 444 '#title' => t('Default state'), 445 '#default_value' => !empty($profile->settings['default']) ? $profile->settings['default'] : 't', 446 '#options' => array( 447 't' => t('Enabled'), 448 'f' => t('Disabled') 449 ), 450 '#description' => t('Default editor state. If disabled, rich text editor may still be enabled using toggle or popup window.'), 451 ); 452 453 $form['appearance']['show_toggle'] = array( 454 '#type' => 'radios', 455 '#title' => t('Show disable/enable rich text editor toggle'), 456 '#default_value' => !empty($profile->settings['show_toggle']) ? $profile->settings['show_toggle'] : 't', 457 '#options' => array( 458 't' => t('Show'), 459 'f' => t('Hide') 460 ), 461 '#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).'), 462 ); 463 464 $form['appearance']['popup'] = array( 465 '#type' => 'radios', 466 '#title' => t('Use FCKeditor in a popup window'), 467 '#default_value' => !empty($profile->settings['popup']) ? $profile->settings['popup'] : 'f', 468 '#options' => array( 469 'f' => t('No'), 470 't' => t('Yes') 471 ), 472 '#description' => t('If this option is enabled a link to a popup window will be used instead of a textarea replace.'), 473 ); 474 475 $form['appearance']['skin'] = array( 476 '#type' => 'select', 477 '#title' => t('Skin'), 478 '#default_value' => !empty($profile->settings['skin']) ? $profile->settings['skin'] : 'default', 479 '#options' => $skin_options, 480 '#description' => t('Choose a default skin.'), 481 ); 482 483 $form['appearance']['toolbar'] = array( 484 '#type' => 'select', 485 '#title' => t('Toolbar'), 486 '#default_value' => !empty($profile->settings['toolbar']) ? $profile->settings['toolbar'] : 'default', 487 '#options' => $toolbar_options, 488 '#description' => t('Choose a default toolbar set. To define new toolbar, edit %configfile located in %module_path.', 489 array( 490 '%configfile' => 'fckeditor.config.js', 491 '%module_path' => drupal_get_path('module', 'fckeditor'), 492 )), 493 ); 494 495 $form['appearance']['expand'] = array( 496 '#type' => 'radios', 497 '#title' => t('Start the toolbar expanded'), 498 '#default_value' => !empty($profile->settings['expand']) ? $profile->settings['expand'] : 't', 499 '#options' => array( 500 't' => t('Expanded'), 501 'f' => t('Collapsed') 502 ), 503 '#description' => t('The toolbar start expanded or collapsed.'), 504 ); 505 506 $form['appearance']['width'] = array( 507 '#type' => 'textfield', 508 '#title' => t('Width'), 509 '#default_value' => !empty($profile->settings['width']) ? $profile->settings['width'] : '100%', 510 '#description' => t('Width in pixels or percent.') .' '. t('Example') .': 400 '. t('or') .' 100%.', 511 '#size' => 40, 512 '#maxlength' => 128, 513 ); 514 515 $form['appearance']['lang'] = array( 516 '#type' => 'select', 517 '#title' => t('Language'), 518 '#default_value' => !empty($profile->settings['lang']) ? $profile->settings['lang'] : 'en', 519 '#options' => $lang_options, 520 '#description' => t('The language for the FCKeditor interface.') 521 ); 522 523 $form['appearance']['auto_lang'] = array( 524 '#type' => 'radios', 525 '#title' => t('Auto-detect language'), 526 '#default_value' => !empty($profile->settings['auto_lang']) ? $profile->settings['auto_lang'] : 't', 527 '#options' => array( 528 't' => t('Enabled'), 529 'f' => t('Disabled') 530 ), 531 '#description' => t('Use auto detect user language feature.') 532 ); 533 534 $form['output'] = array( 535 '#type' => 'fieldset', 536 '#title' => t('Cleanup and output'), 537 '#collapsible' => TRUE, 538 '#collapsed' => TRUE, 539 ); 540 541 $form['output']['enter_mode'] = array( 542 '#type' => 'select', 543 '#title' => t('Enter mode'), 544 '#default_value' => !empty($profile->settings['enter_mode']) ? $profile->settings['enter_mode'] : 'p', 545 '#options' => array( 546 'p' => '<p>', 547 'br' => '<br />', 548 'div' => '<div>' 549 ), 550 '#description' => t('Set which tag FCKeditor should use when [Enter] key is pressed.') 551 ); 552 553 $form['output']['shift_enter_mode'] = array( 554 '#type' => 'select', 555 '#title' => t('Shift + Enter mode'), 556 '#default_value' => !empty($profile->settings['shift_enter_mode']) ? $profile->settings['shift_enter_mode'] : 'br', 557 '#options' => array( 558 'p' => '<p>', 559 'br' => '<br />', 560 'div' => '<div>' 561 ), 562 '#description' => t('Set which tag FCKeditor should use when [Shift] + [Enter] is pressed.') 563 ); 564 565 $form['output']['font_format'] = array( 566 '#type' => 'textfield', 567 '#title' => t('Font formats'), 568 '#default_value' => !empty($profile->settings['font_format']) ? $profile->settings['font_format'] : 'p;div;pre;address;h1;h2;h3;h4;h5;h6', 569 '#size' => 40, 570 '#maxlength' => 250, 571 '#description' => t('Semicolon separated list of HTML font formats.') .' '. t('Allowed values are') .': p;div;pre;address;h1;h2;h3;h4;h5;h6', 572 ); 573 574 $form['output']['format_source'] = array( 575 '#type' => 'radios', 576 '#title' => t('Apply source formatting'), 577 '#default_value' => !empty($profile->settings['format_source']) ? $profile->settings['format_source'] : 't', 578 '#options' => array( 579 't' => t('Yes'), 580 'f' => t('No') 581 ), 582 '#description' => 583 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.', 584 array( 585 '%true' => t('Yes'), 586 )), 587 ); 588 589 $form['output']['format_output'] = array( 590 '#type' => 'radios', 591 '#title' => t('Format output'), 592 '#default_value' => !empty($profile->settings['format_output']) ? $profile->settings['format_output'] : 't', 593 '#options' => array( 594 't' => t('Yes'), 595 'f' => t('No') 596 ), 597 '#description' => 598 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.', 599 array( 600 '%true' => t('Yes'), 601 )), 602 ); 603 604 $form['output']['autofixplaintext'] = array( 605 '#type' => 'radios', 606 '#title' => t('Automatically detect and convert plain text'), 607 '#default_value' => !empty($profile->settings['autofixplaintext']) ? $profile->settings['autofixplaintext'] : 'f', 608 '#options' => array( 609 't' => t('Yes'), 610 'f' => t('No') 611 ), 612 '#description' => 613 t('When set to %true the editor will try to detect if a field was created using the plain text editor and convert line breaks to <br /> and <p> tags. This will alter the field contents and is not reversible.', 614 array( 615 '%true' => t('Yes'), 616 )), 617 ); 618 619 $form['css'] = array( 620 '#type' => 'fieldset', 621 '#title' => t('Style and template files'), 622 '#collapsible' => TRUE, 623 '#collapsed' => TRUE 624 ); 625 626 $form['css']['css_mode'] = array( 627 '#type' => 'select', 628 '#title' => t('Editor CSS'), 629 '#default_value' => !empty($profile->settings['css_mode']) ? $profile->settings['css_mode'] : 'theme', 630 '#options' => array( 631 'theme' => t('Use theme CSS'), 632 'self' => t('Define CSS'), 633 'none' => t('FCKeditor default') 634 ), 635 '#description' => 636 t('Defines the CSS to be used in the editor area.') .'<br />'. 637 t('Use theme CSS') .': '. t('load style.css from current site theme.') .'<br/>'. 638 t('Define CSS') .': '. t('enter path for CSS file below.') .'<br />'. 639 t('FCKeditor default') .': '. t('uses default CSS from editor.') 640 ); 641 642 $form['css']['css_path'] = array( 643 '#type' => 'textfield', 644 '#title' => t('CSS path'), 645 '#default_value' => !empty($profile->settings['css_path']) ? $profile->settings['css_path'] : "", 646 '#size' => 40, 647 '#maxlength' => 255, 648 '#description' => 649 t('Enter path to CSS file (Example: %cssexample1) or a list of CSS files separated by a comma (Example: %cssexample2). Make sure to select %defcss above.', 650 array( 651 '%cssexample1' => 'css/editor.css', 652 '%cssexample2' => '/themes/garland/style.css,http://example.com/style.css', 653 '%defcss' => 'Define css', 654 )) .'<br />'. 655 t('Available placeholders') .':<br />'. 656 '<strong>%h</strong> - '. t('host name (%host)', array('%host' => base_path())) .'<br />'. 657 '<strong>%t</strong> - '. t('path to theme (%theme)', array('%theme' => base_path() . fckeditor_path_to_theme() .'/')) 658 ); 659 660 $form['css']['css_style'] = array( 661 '#type' => 'select', 662 '#title' => t('Predefined styles'), 663 '#default_value' => !empty($profile->settings['css_style']) ? $profile->settings['css_style'] : 'theme', 664 '#options' => array( 665 'theme' => t('Use theme fckstyles.xml'), 666 'self' => t('Define path to fckstyles.xml'), 667 'default' => t('FCKeditor default') 668 ), 669 '#description' => 670 t('Define the location of %file file. It is used by the %setting dropdown list available in the default toolbar. Copy %sourcefile inside your theme directory (%themefile) and adjust it to your needs.', 671 array( 672 '%file' => 'fckstyles.xml', 673 '%setting' => t('Style'), 674 '%sourcefile' => fckeditor_path(TRUE) .'/fckstyles.xml', 675 '%themefile' => fckeditor_path_to_theme() .'/fckstyles.xml', 676 )) 677 ); 678 679 $form['css']['styles_path'] = array( 680 '#type' => 'textfield', 681 '#title' => t('Predefined styles path'), 682 '#default_value' => !empty($profile->settings['styles_path']) ? $profile->settings['styles_path'] : "", 683 '#size' => 40, 684 '#maxlength' => 255, 685 '#description' => 686 t('Enter the path to XML file with predefined @type (Example: %example). Be sure to select %setting above.', 687 array( 688 '@type' => t('styles'), 689 '%example' => '/fckstyles.xml', 690 '%setting' => t('Define path to fckstyles.xml'), 691 )) .'<br />'. 692 t('Available placeholders') .':<br />'. 693 '<strong>%h</strong> - '. t('host name (%host)', array('%host' => base_path())) .'<br />'. 694 '<strong>%t</strong> - '. t('path to theme (%theme)', array('%theme' => base_path() . fckeditor_path_to_theme() .'/')) .'<br />'. 695 '<strong>%m</strong> - '. t('path to FCKeditor module (%module)', array('%module' => drupal_get_path('module', 'fckeditor'))), 696 ); 697 698 $form['css']['templatefile_mode'] = array( 699 '#type' => 'select', 700 '#title' => t('Predefined templates'), 701 '#default_value' => !empty($profile->settings['templatefile_mode']) ? $profile->settings['templatefile_mode'] : 'default', 702 '#options' => array( 703 'default' => t('FCKeditor default'), 704 'theme' => t('Use theme fcktemplates.xml'), 705 'self' => t('Define path to fcktemplates.xml'), 706 ), 707 '#description' => 708 t('Define the location of %file file. It is used by the %setting dropdown list available in the default toolbar. Copy %sourcefile inside your theme directory (%themefile) and adjust it to your needs.', 709 array( 710 '%file' => 'fcktemplates.xml', 711 '%setting' => t('Templates'), 712 '%sourcefile' => fckeditor_path(TRUE) .'/fcktemplates.xml', 713 '%themefile' => fckeditor_path_to_theme() .'/fcktemplates.xml', 714 )) 715 ); 716 717 $form['css']['templatefile_path'] = array( 718 '#type' => 'textfield', 719 '#title' => t('Predefined templates path'), 720 '#default_value' => !empty($profile->settings['templatefile_path']) ? $profile->settings['templatefile_path'] : '', 721 '#size' => 40, 722 '#maxlength' => 255, 723 '#description' => 724 t('Enter the path to XML file with predefined @type (Example: %example). Be sure to select %setting above.', 725 array( 726 '@type' => t('templates'), 727 '%example' => '/fckstyles.xml', 728 '%setting' => t('Define path to fckstyles.xml'), 729 )) .'<br />'. 730 t('Available placeholders') .':<br />'. 731 '<strong>%h</strong> - '. t('host name (%host)', array('%host' => base_path())) .'<br />'. 732 '<strong>%t</strong> - '. t('path to theme (%theme)', array('%theme' => base_path() . fckeditor_path_to_theme() .'/')) .'<br />'. 733 '<strong>%m</strong> - '. t('path to FCKeditor module (%module)', array('%module' => drupal_get_path('module', 'fckeditor'))), 734 ); 735 736 $form['fckeditor_upload_settings'] = array( 737 '#type' => 'fieldset', 738 '#title' => t('File browser settings'), 739 '#collapsible' => TRUE, 740 '#collapsed' => TRUE, 741 '#description' => 742 t('Set file browser settings. A file browser will allow you to explore the files contained on the server and embed them as links, images or flash movies. Besides the built-in FCKeditor file browser, you can also use a contributed module like !imcelink, !iblink or !webfmlink. The quick upload setting controls whether images, flash movies and files can be uploaded using the upload tab of the respective dialogs. Please note that these options require manual configuration, check !readmelink for more information.', 743 array( 744 '!imcelink' => l(t('IMCE'), 'http://drupal.org/project/imce'), 745 '!iblink' => l(t('Image Browser'), 'http://drupal.org/project/imagebrowser'), 746 '!webfmlink' => l(t('Web File Manager'), 'http://drupal.org/project/webfm'), 747 '!readmelink' => l(t('readme.txt'), 'admin/help/fckeditor'), 748 )) 749 ); 750 751 $filebrowsers = array( 752 'none' => t('None'), 753 'builtin' => t('Built-in file browser'), 754 ); 755 756 if (module_exists('imce')) { 757 $filebrowsers['imce'] = t('IMCE'); 758 } 759 760 if (module_exists('imagebrowser')) { 761 $filebrowsers['ib'] = t('Image Browser'); 762 } 763 764 if (module_exists('webfm_popup')) { 765 $filebrowsers['webfm'] = t('Web File Manager'); 766 } 767 768 $form['fckeditor_upload_settings']['filebrowser'] = array( 769 '#type' => 'select', 770 '#title' => t('File browser type'), 771 '#default_value' => !empty($profile->settings['filebrowser']) ? $profile->settings['filebrowser'] : 'none', 772 '#options' => $filebrowsers, 773 '#description' => t('Select the file browser that you would like to use to upload files, images and flash movies.'), 774 ); 775 776 $form['fckeditor_upload_settings']['quickupload'] = array( 777 '#type' => 'radios', 778 '#title' => t('Allow quick uploads'), 779 '#default_value' => !empty($profile->settings['quickupload']) ? $profile->settings['quickupload'] : 'f', 780 '#options' => array( 781 'f' => t('No'), 782 't' => t('Yes') 783 ), 784 '#description' => t('The quick upload functionality can be disabled and enabled independently of the file browser. It will always use the settings below. To enable quick uploads you must follow the same configuration procedure as when enabling the built-in file browser.'), 785 ); 786 787 $current_user_files_path = empty($profile->settings['UserFilesPath']) ? "" : strtr($profile->settings['UserFilesPath'], array("%f" => file_directory_path(), "%u" => "UID", "%b" => base_path(), "%n" => "UNAME")); 788 $current_user_files_absolute_path = empty($profile->settings['UserFilesAbsolutePath']) ? "" : strtr($profile->settings['UserFilesAbsolutePath'], array("%f" => file_directory_path(), "%u" => "UID", "%b" => base_path(), "%d" => $_SERVER['DOCUMENT_ROOT'], "%n" => "UNAME")); 789 790 $form['fckeditor_upload_settings']['UserFilesPath'] = array( 791 '#type' => 'textfield', 792 '#title' => t('Path to uploaded files'), 793 '#default_value' => !empty($profile->settings['UserFilesPath']) ? $profile->settings['UserFilesPath'] : "%b%f/", 794 '#size' => 40, 795 '#maxlength' => 255, 796 '#description' => 797 t('Path to uploaded files relative to the document root.') .'<br />'. 798 t('Available placeholders') .':<br/>'. 799 '<strong>%b</strong> - '. t('base URL path of the Drupal installation (%base)', array('%base' => base_path())) .'<br/>'. 800 '<strong>%f</strong> - '. t('Drupal file system path where the files are stored (%files)', array('%files' => file_directory_path())) .'<br />'. 801 '<strong>%u</strong> - '. t('User ID') .'<br />'. 802 '<strong>%n</strong> - '. t('Username') .'<br />'. 803 t('Current path: %path', array('%path' => $current_user_files_path)), 804 ); 805 806 $form['fckeditor_upload_settings']['UserFilesAbsolutePath'] = array( 807 '#type' => 'textfield', 808 '#title' => t('Absolute path to uploaded files'), 809 '#default_value' => !empty($profile->settings['UserFilesAbsolutePath']) ? $profile->settings['UserFilesAbsolutePath'] : "%d%b%f/", 810 '#size' => 40, 811 '#maxlength' => 255, 812 '#description' => 813 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 />'. 814 t('Available placeholders') .':<br/>'. 815 '<strong>%d</strong> - '. t('server path to document root (%root)', array('%root' => $_SERVER['DOCUMENT_ROOT'])) .'<br />'. 816 '<strong>%b</strong> - '. t('base URL path of the Drupal installation (%base)', array('%base' => base_path())) .'<br/>'. 817 '<strong>%f</strong> - '. t('Drupal file system path where the files are stored (%files)', array('%files' => file_directory_path())) .'<br />'. 818 '<strong>%u</strong> - '. t('User ID') .'<br />'. 819 '<strong>%n</strong> - '. t('Username') .'<br />'. 820 t('Current path: %path', array('%path' => $current_user_files_absolute_path)), 821 ); 822 823 if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE) { 824 $form['fckeditor_upload_settings']['UserFilesPath']['#description'] = t('Setting relative path to uploaded files has been disabled because private downloads are enabled and this path is calculated automatically. To change the location of uploaded files in the private file system, edit the !globallink.', array('!globallink' => l(t('FCKeditor Global Profile'), 'admin/settings/fckeditor/editg'))); 825 $form['fckeditor_upload_settings']['UserFilesPath']['#disabled'] = TRUE; 826 $form['fckeditor_upload_settings']['UserFilesAbsolutePath']['#description'] = t('Setting path to uploaded files has been disabled because private downloads are enabled and this path is calculated automatically. To change the location of uploaded files in the private file system, edit the !globallink.', array('!globallink' => l(t('FCKeditor Global Profile'), 'admin/settings/fckeditor/editg'))); 827 $form['fckeditor_upload_settings']['UserFilesAbsolutePath']['#disabled'] = TRUE; 828 } 829 830 $form['advanced'] = array( 831 '#type' => 'fieldset', 832 '#title' => t('Advanced options'), 833 '#collapsible' => TRUE, 834 '#collapsed' => TRUE, 835 ); 836 $form['advanced']['theme_config_js'] = array( 837 '#type' => 'radios', 838 '#title' => t('Load fckeditor.config.js from theme path'), 839 '#default_value' => !empty($profile->settings['theme_config_js']) ? $profile->settings['theme_config_js'] : 'f', 840 '#options' => array( 841 't' => t('Yes'), 842 'f' => t('No') 843 ), 844 '#description' => 845 t('When set to %true the editor will try to load the %configfile file from theme directory.', 846 array( 847 '%true' => t('Yes'), 848 '%configfile' => 'fckeditor.config.js', 849 )), 850 ); 851 $form['advanced']['js_conf'] = array( 852 '#type' => 'textarea', 853 '#title' => t('Custom javascript configuration'), 854 '#default_value' => !empty($profile->settings['js_conf']) ? $profile->settings['js_conf'] : "", 855 '#cols' => 60, 856 '#rows' => 5, 857 '#description' => 858 t('To change FCKeditor configuration globally, you should modify the config file: %fckeditor_config. Sometimes it is required to change the FCKeditor configuration for a single profile only. Use this box to define settings that are unique for this profile. Available options are listed in the !docslink. Add the following code snippet to disable some advanced tabs in dialog windows of FCKeditor.', 859 array( 860 '%fckeditor_config' => drupal_get_path('module', 'fckeditor') .'/fckeditor.config.js', 861 '!docslink' => l(t('FCKeditor documentation'), 'http://docs.cksource.com/FCKeditor_2.x/Developers_Guide/Configuration/Configuration_Options'), 862 )) . 863 "<pre>LinkDlgHideTarget = true;\nLinkDlgHideAdvanced = true;\nImageDlgHideLink = true;\nImageDlgHideAdvanced = true;\nFlashDlgHideAdvanced = true;</pre>". 864 '<strong>'. t('Warning') .'</strong>: '. 865 t('If you do something wrong here, FCKeditor may fail to load.'), 866 '#wysiwyg' => FALSE, 867 ); 868 869 $form['submit'] = array( 870 '#type' => 'submit', 871 '#value' => t('Save') 872 ); 873 874 return $form; 875 } 876 877 /** 878 * Profile validation. 879 */ 880 function fckeditor_admin_profile_form_validate($form, &$form_state) { 881 $edit =& $form_state['values']; 882 883 //include mode and all other fields are empty, invalid 884 if ($edit['excl_mode'] == 1 && empty($edit['excl'])) { 885 form_set_error('excl_mode', t('Include mode selected, but no paths given. Enter at least one path where FCKeditor should appear.')); 886 } 887 else { 888 fckeditor_admin_profile_validate_fieldpaths('excl', $edit['excl']); 889 } 890 891 fckeditor_admin_profile_validate_fieldpaths('simple_incl', $edit['simple_incl']); 892 893 if (!preg_match('/^\d+$/', trim($edit['min_rows']))) { 894 form_set_error('min_rows', t('Minimum rows must be a valid number.')); 895 } 896 897 if ($edit['default'] == 't' && $edit['popup'] == 't') { 898 form_set_error('popup', t('If FCKeditor is enabled by default, popup window must be disabled.')); 899 } 900 901 if ($edit['show_toggle'] == 't' && $edit['popup'] == 't') { 902 form_set_error('popup', t('If toggle is enabled, popup window must be disabled.')); 903 } 904 905 if (!$edit['name']) { 906 form_set_error('name', t('You must give a profile name.')); 907 } 908 elseif ($edit['name'] == 'FCKeditor Global Profile') { 909 form_set_error('name', t('This profile name is reserved. Please choose a different name.')); 910 } 911 elseif (!isset($edit['_profile']) || ($edit['_profile']->name != $edit['name'])) { 912 $result = fckeditor_profile_load($edit['name']); 913 if (!empty($result)) { 914 form_set_error('name', t('The profile name must be unique. A profile with this name already exists.')); 915 } 916 } 917 918 if (!preg_match('/^\d+%?$/', $edit['width'])) { 919 form_set_error('width', t('Enter valid width.') .' '. t('Example') .': 400 '. t('or') .' 100%.'); 920 } 921 922 if (!empty($edit['css_path'])) { 923 if ($edit['css_mode'] != 'self') { 924 form_set_error('css_path', t('CSS path is not empty.') .' '. t('Please set the %settingname option to %settingoption mode.', 925 array('%settingname' => t('Editor CSS'), '%settingoption' => t('Define CSS')))); 926 } 927 elseif (FALSE !== strpos($edit['css_path'], '"')) { 928 form_set_error('css_path', t('Double quotes are not allowed in CSS path.')); 929 } 930 elseif (substr($edit['css_path'], 0, 1) == "'" && substr($edit['css_path'], -1) == "'") { 931 form_set_error('css_path', t('Enter valid path, do not surround it with quotes.')); 932 } 933 } 934 935 if (!empty($edit['styles_path'])) { 936 if ($edit['css_style'] != 'self') { 937 form_set_error('styles_path', t('Path to predefined styles is not empty.') .' '. t('Please set the %settingname option to %settingoption mode.', 938 array('%settingname' => t('Predefined styles'), '%settingoption' => t('Define path to fckstyles.xml')))); 939 } 940 elseif (FALSE !== strpos($edit['styles_path'], '"')) { 941 form_set_error('styles_path', t('Double quotes are not allowed in path.')); 942 } 943 elseif (substr($edit['styles_path'], 0, 1) == "'" && substr($edit['styles_path'], -1) == "'") { 944 form_set_error('styles_path', t('Enter valid path, do not surround it with quotes.')); 945 } 946 } 947 948 if (!empty($edit['templatefile_path'])) { 949 if ($edit['templatefile_mode'] != 'self') { 950 form_set_error('templatefile_path', t('Path to predefined templates is not empty.') .' '. t('Please set the %settingname option to %settingoption mode.', 951 array('%settingname' => t('Predefined templates'), '%settingoption' => t('Define path to fcktemplates.xml')))); 952 } 953 elseif (FALSE !== strpos($edit['templatefile_path'], '"')) { 954 form_set_error('templatefile_path', t('Double quotes are not allowed in path.')); 955 } 956 elseif (substr($edit['templatefile_path'], 0, 1) == "'" && substr($edit['styles_path'], -1) == "'") { 957 form_set_error('templatefile_path', t('Enter valid path, do not surround it with quotes.')); 958 } 959 } 960 961 if (!empty($edit['font_format'])) { 962 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'])) { 963 form_set_error('font_format', t('Enter valid, semicolon separated, list of HTML font formats (no semicolon at the end of list expected).')); 964 } 965 } 966 967 if (variable_get('file_downloads', '') !== FILE_DOWNLOADS_PRIVATE) { 968 if (!empty($edit['UserFilesAbsolutePath']) && empty($edit['UserFilesPath'])) { 969 form_set_error('UserFilesPath', t('Path to uploaded files is required.')); 970 } 971 if (!empty($edit['UserFilesPath']) && empty($edit['UserFilesAbsolutePath'])) { 972 form_set_error('UserFilesPath', t('Absolute path to uploaded files is required.')); 973 } 974 } 975 } 976 977 function fckeditor_admin_profile_form_submit($form, &$form_state) { 978 $edit =& $form_state['values']; 979 980 if (isset($edit['_profile'])) { 981 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s'", $edit['_profile']->name); 982 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s'", $edit['_profile']->name); 983 drupal_set_message(t('Your FCKeditor profile has been updated.')); 984 } 985 else { 986 drupal_set_message(t('Your FCKeditor profile has been created.')); 987 } 988 989 $settings = fckeditor_admin_values_to_settings($edit); 990 db_query("INSERT INTO {fckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], $settings); 991 fckeditor_rebuild_selectors($edit['name']); 992 if (!empty($edit['rids'])) { 993 foreach (array_keys($edit['rids']) as $rid) { 994 if ($edit['rids'][$rid]!=0) { 995 db_query("INSERT INTO {fckeditor_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid); 996 } 997 } 998 } 999 1000 $form_state['redirect'] = 'admin/settings/fckeditor'; 1001 } 1002 1003 function fckeditor_admin_global_profile_form($form_state, $mode = 'add') { 1004 module_load_include('lib.inc', 'fckeditor'); 1005 if ($mode == 'edit') { 1006 $profile = fckeditor_profile_load('FCKeditor Global Profile'); 1007 1008 $form['_profile'] = array( 1009 '#type' => 'value', 1010 '#value' => $profile, 1011 ); 1012 } 1013 else { 1014 $profile = new stdClass(); 1015 } 1016 1017 if ($mode == 'add') { 1018 $data = fckeditor_profile_load('FCKeditor Global Profile'); 1019 if (!empty($data)) { 1020 drupal_set_message(t('Global profile already exist. Only one global profile is allowed.'), 'error'); 1021 drupal_not_found(); 1022 } 1023 1024 $btn = t('Create global profile'); 1025 } 1026 else { 1027 $btn = t('Update global profile'); 1028 } 1029 1030 $form['common'] = array( 1031 '#type' => 'fieldset', 1032 '#title' => t('Main setup'), 1033 '#collapsible' => TRUE, 1034 '#collapsed' => TRUE 1035 ); 1036 1037 $roles = fckeditor_sorted_roles(); 1038 $rids = $rtext = array(); 1039 foreach ($roles as $rid => $name) { 1040 $rids[] = $rid; 1041 $rtext[] = '<strong>'. $rid .' - </strong>'. $name; 1042 } 1043 $form['common']['rank'] = array( 1044 '#type' => 'textfield', 1045 '#title' => t('Role precedence'), 1046 '#default_value' => implode('>', $rids), 1047 '#description' => t('A user having multiple roles gets the permissions of the highest one. Sort role IDs according to their precedence from higher to lower by putting > in between.'), 1048 ); 1049 if ($rids) { 1050 $form['common']['rank']['#description'] .= '<br />'. t('Here are the id-name pairs of roles having access to FCKeditor:') .'<div>'. implode('<br />', $rtext) .'</div>'; 1051 } 1052 else { 1053 $form['common']['rank']['#description'] .= '<br />'. t('You haven\'t assigned the %accesspermission !permissionslink yet.', array('%accesspermission' => t('access fckeditor'), '!permissionslink' => l(t('permission'), 'admin/user/permissions'))); 1054 } 1055 1056 $form['fckeditor_exclude_settings'] = array( 1057 '#type' => 'fieldset', 1058 '#title' => t('Visibility settings'), 1059 '#collapsible' => TRUE, 1060 '#collapsed' => TRUE, 1061 '#description' => t('The following settings are combined with the visibility settings of the specific profile.'), 1062 ); 1063 1064 $form['fckeditor_exclude_settings']['excl_mode'] = array( 1065 '#type' => 'radios', 1066 '#title' => t('Use inclusion or exclusion mode'), 1067 '#default_value' => (empty($profile->settings['excl_mode']) || in_array($profile->settings['excl_mode'], array(0, 2))) ? 0 : 1, 1068 '#options' => array( 1069 '0' => t('Exclude'), 1070 '1' => t('Include') 1071 ), 1072 '#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.'), 1073 ); 1074 /** 1075 * get excluded fields - so we can have normal textareas too 1076 * split the phrase by any number of commas or space characters, 1077 * which include " ", \r, \t, \n and \f 1078 */ 1079 $form['fckeditor_exclude_settings']['excl'] = array( 1080 '#type' => 'textarea', 1081 '#title' => t('Fields to exclude/include'), 1082 '#cols' => 60, 1083 '#rows' => 5, 1084 '#prefix' => '<div style="margin-left:20px">', 1085 '#suffix' => '</div>', 1086 '#default_value' => !empty($profile->settings['excl']) ? $profile->settings['excl'] : '', 1087 '#description' => 1088 t('Enter the paths to the textarea fields on which you want to enable or disable FCKeditor.') .' '. 1089 t('Please see the !helppagelink for more information about defining field names. Short instruction is available below.', 1090 array( 1091 '!helppagelink' => l(t('help page'), 'admin/help/fckeditor', array('fragment' => 'fieldinclexcl')), 1092 )) . 1093 ' <ul>' . 1094 '<li>'. t('Path structure') .': <strong>content_type@path.element_id</strong></li>'. 1095 '<li>'. t('The following wildcards are available: *, ?') .'</li>'. 1096 '<li>'. t('Content type is optional. You may even specify only path or field id') .'</li>'. 1097 '<li>'. t('Examples') .':<ul>'. 1098 '<li><em>blog@*.edit-body</em> - '. t('matches all fields of type %type called %field, on any page', array('%type' => 'blog', '%field' => 'edit-body')) . 1099 '<li><em>node/add/*.edit-user-*</em> - '. t('matches fields starting with %field on pages starting with %path', array('%field' => 'edit-user-', '%path' => 'node/add/')) .'</li></ul>'. 1100 '</li></ul>', 1101 '#wysiwyg' => FALSE, 1102 ); 1103 1104 $form['fckeditor_exclude_settings']['simple_incl'] = array( 1105 '#type' => 'textarea', 1106 '#title' => t('Force simplified toolbar on the following fields'), 1107 '#cols' => 60, 1108 '#rows' => 5, 1109 '#default_value' => !empty($profile->settings['simple_incl']) ? $profile->settings['simple_incl'] : '', 1110 '#description' => 1111 t('Enter the paths to the textarea fields on which you want to force the simplified toolbar (%toolbarname).', 1112 array( 1113 '%toolbarname' => FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME, 1114 )) .' '. 1115 t('Please see the !helppagelink for more information about defining field names. Take a look at the exclusion settings (above) for short instruction.', 1116 array( 1117 '!helppagelink' => l(t('help page'), 'admin/help/fckeditor', array('fragment' => 'fieldinclexcl')), 1118 )), 1119 '#wysiwyg' => FALSE, 1120 ); 1121 1122 $form['fckeditor_advanced_settings'] = array( 1123 '#type' => 'fieldset', 1124 '#title' => t('Advanced settings'), 1125 '#collapsible' => TRUE, 1126 '#collapsed' => TRUE, 1127 ); 1128 1129 $module_drupal_path = drupal_get_path('module', 'fckeditor'); 1130 1131 $form['fckeditor_advanced_settings']['fckeditor_path'] = array( 1132 '#type' => 'textfield', 1133 '#title' => t('Path to FCKeditor'), 1134 '#default_value' => !empty($profile->settings['fckeditor_path']) ? $profile->settings['fckeditor_path'] : '%m/fckeditor', 1135 '#size' => 40, 1136 '#maxlength' => 128, 1137 '#description' => 1138 t('Path to FCKeditor (the HTML editor, downloaded from !fckeditorlink) relative to the document root.', 1139 array( 1140 '!fckeditorlink' => l('http://ckeditor.com', 'http://ckeditor.com/download'), 1141 )) .'<br />'. 1142 t('Available placeholders') .':<br />'. 1143 '<strong>%b</strong> - '. t('base URL path of the Drupal installation (%base)', array('%base' => base_path())) .'<br />'. 1144 '<strong>%m</strong> - '. t('base URL path where FCKeditor module is stored (%files)', array('%files' => base_path() . $module_drupal_path)) .'<br />'. 1145 t('Current path: %path', array('%path' => fckeditor_path(FALSE))), 1146 '#required' => TRUE, 1147 ); 1148 1149 $form['fckeditor_advanced_settings']['fckeditor_local_path'] = array( 1150 '#type' => 'textfield', 1151 '#title' => t('Local path to FCKeditor'), 1152 '#default_value' => isset($profile->settings['fckeditor_local_path'])?$profile->settings['fckeditor_local_path']:'', 1153 '#size' => 40, 1154 '#maxlength' => 128, 1155 '#description' => 1156 t('The path to the local directory (on the server) which points to the path defined above. Enter either an absolute server path or path relative to %index. If empty, FCKeditor module will try to find the right path.', array('%index' => 'index.php')) .'<br />'. 1157 t('Current path: %path', array('%path' => fckeditor_path(TRUE))), 1158 ); 1159 1160 $form['fckeditor_advanced_settings']['show_fieldnamehint'] = array( 1161 '#type' => 'radios', 1162 '#title' => t('Show field name hint below each rich text editor'), 1163 '#default_value' => !empty($profile->settings['show_fieldnamehint']) ? $profile->settings['show_fieldnamehint'] : 't', 1164 '#options' => array( 1165 't' => t('Yes'), 1166 'f' => t('No') 1167 ), 1168 '#description' => t('This only applies for users with %adminpermission permissions.', array('%adminpermission' => t('administer fckeditor'))), 1169 ); 1170 1171 if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE) { 1172 global $user; 1173 $current_private_dir = isset($profile->settings['private_dir']) ? trim($profile->settings['private_dir'], '\/') : ''; 1174 $current_private_dir = strtr($current_private_dir, array('%u' => $user->uid, '%n' => $user->name)); 1175 1176 $form['fckeditor_advanced_settings']['private_dir'] = array( 1177 '#type' => 'textfield', 1178 '#title' => t('Location of files uploaded with FCKeditor in the private folder'), 1179 '#default_value' => !empty($profile->settings['private_dir']) ? $profile->settings['private_dir'] : '', 1180 '#size' => 40, 1181 '#maxlength' => 255, 1182 '#description' => 1183 t('The path relative to the location of the private directory where FCKeditor should store uploaded files.') .'<br />'. 1184 '<strong>'. t('Warning') .':</strong> '. 1185 t('FCKeditor does not implement any kind of access protection on files available in this location. All files stored in the directory defined above might be accessible by unauthenticated users if there is no information about the file in the Drupal\'s database.') .'<br />'. 1186 t('System path to the private folder is: @system_path.', array('@system_path' => realpath(file_directory_path()) . DIRECTORY_SEPARATOR)) .'<br />'. 1187 t('Available placeholders') .':<br/>'. 1188 '<strong>%u</strong> - '. t('User ID') .'<br />'. 1189 '<strong>%n</strong> - '. t('Username') .'<br />'. 1190 t('Current path: @path', array('@path' => $current_private_dir .' ('. file_create_path($current_private_dir) .')')), 1191 ); 1192 } 1193 1194 $form['submit'] = array( 1195 '#type' => 'submit', 1196 '#value' => $btn, 1197 ); 1198 1199 return $form; 1200 } 1201 1202 function fckeditor_admin_global_profile_form_validate($form, &$form_state) { 1203 $edit =& $form_state['values']; 1204 1205 //include mode and all other fields are empty, invalid 1206 if ($edit['excl_mode'] == 1 && empty($edit['excl'])) { 1207 form_set_error('excl_mode', t('Include mode selected, but no paths given. Enter at least one path where FCKeditor should appear.')); 1208 } 1209 else { 1210 fckeditor_admin_profile_validate_fieldpaths('excl', $edit['excl']); 1211 } 1212 1213 fckeditor_admin_profile_validate_fieldpaths('simple_incl', $edit['simple_incl']); 1214 } 1215 1216 function fckeditor_admin_global_profile_form_submit($form, &$form_state) { 1217 module_load_include('lib.inc', 'fckeditor'); 1218 $edit =& $form_state['values']; 1219 $edit['name'] = 'FCKeditor Global Profile'; 1220 1221 if (isset($edit['rank'])) { 1222 $edit['rank'] = explode('>', str_replace(' ', '', $edit['rank'])); 1223 } 1224 1225 if (isset($edit['_profile'])) { 1226 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s'", $edit['_profile']->name); 1227 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s'", $edit['_profile']->name); 1228 } 1229 1230 //strip whitespaces 1231 if (empty($edit['fckeditor_local_path'])) { 1232 $edit['fckeditor_local_path'] = ''; 1233 } 1234 else { 1235 $edit['fckeditor_local_path'] = trim($edit['fckeditor_local_path']); 1236 } 1237 1238 //strip slash from the end 1239 if (empty($edit['fckeditor_path'])) { 1240 $edit['fckeditor_path'] = ''; 1241 } 1242 $edit['fckeditor_path'] = trim(rtrim($edit['fckeditor_path'], '/')); 1243 if ($edit['fckeditor_path'] && 0 !== strpos($edit['fckeditor_path'], '/') && 0 !== strpos($edit['fckeditor_path'], '%')) { 1244 //ensure that slash is at the beginning 1245 $edit['fckeditor_path'] = '/'. $edit['fckeditor_path']; 1246 } 1247 //no slash at the end 1248 $edit['fckeditor_local_path'] = trim(rtrim($edit['fckeditor_local_path'], '/')); 1249 1250 $settings = fckeditor_admin_values_to_settings($edit); 1251 db_query("INSERT INTO {fckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], $settings); 1252 fckeditor_rebuild_selectors($edit['name']); 1253 1254 drupal_set_message(t('FCKeditor global profile has been saved.')); 1255 $form_state['redirect'] = 'admin/settings/fckeditor'; 1256 } 1257 1258 /** 1259 * Converts an array of form values to a serialized array that does not 1260 * contain Drupal Form API values 1261 */ 1262 function fckeditor_admin_values_to_settings($values) { 1263 unset($values['name'], $values['rids'], $values['_profile'], $values['op'], $values['submit'], $values['form_build_id'], $values['form_token'], $values['form_id']); 1264 return serialize($values); 1265 } 1266 1267 function fckeditor_admin_profile_validate_fieldpaths($fieldname, $paths) { 1268 $myerrors = array(); 1269 1270 $rules = preg_split('/[\s,]+/', $paths); 1271 1272 foreach ($rules as $rule) { 1273 $rule = trim($rule); 1274 if (!empty($rule) && strpos($rule, '.') === FALSE && strpos($rule, '/') === FALSE && strpos($rule, '-') === FALSE) { 1275 $myerrors[] = t('Rule %rule is ambiguous: please append .* if %rule is a path or prepend *. if %rule is a field', array('%rule' => $rule)); 1276 } 1277 } 1278 1279 if (!empty($myerrors)) { 1280 form_set_error($fieldname, implode('<br/>', $myerrors)); 1281 } 1282 } 1283 1284 function fckeditor_admin_profile_delete_form($form_state, $profile) { 1285 $form = array(); 1286 1287 $form['_profile'] = array( 1288 '#type' => 'value', 1289 '#value' => $profile, 1290 ); 1291 1292 $form['question'] = array( 1293 '#type' => 'item', 1294 '#value' => t('Are you sure that you want to delete the FCKeditor profile %profile?', array('%profile' => $profile->name)), 1295 ); 1296 1297 $form['delete'] = array( 1298 '#type' => 'submit', 1299 '#id' => 'delete', 1300 '#value' => t('Delete'), 1301 ); 1302 1303 $form['back'] = array( 1304 '#type' => 'submit', 1305 '#id' => 'back', 1306 '#value' => t('Cancel'), 1307 ); 1308 1309 return $form; 1310 } 1311 1312 function fckeditor_admin_profile_delete_form_submit($form, &$form_state) { 1313 $v =& $form_state['values']; 1314 1315 if ($form_state['clicked_button']['#id'] == 'delete') { 1316 fckeditor_profile_delete($v['_profile']->name); 1317 drupal_set_message(t('Deleted FCKeditor profile.')); 1318 } 1319 1320 $form_state['redirect'] = 'admin/settings/fckeditor'; 1321 } 1322 1323 /** 1324 * Rebuilds the regular expression that is used to match the inclusion/exclusion rules 1325 * and the simplified toolbar rules 1326 * 1327 * @param string $name Name of the profile to process. If omitted, all profiles are rebuilt 1328 */ 1329 function fckeditor_rebuild_selectors($name = NULL) { 1330 if ($name == NULL) { 1331 $result = db_query("SELECT * FROM {fckeditor_settings}"); 1332 } 1333 else { 1334 $result = db_query("SELECT * FROM {fckeditor_settings} WHERE name = '%s'", $name); 1335 } 1336 1337 while (($data = db_fetch_object($result))) { 1338 if ($data->settings) { 1339 $settings = unserialize($data->settings); 1340 1341 foreach (array('excl', 'simple_incl') as $var) { 1342 $settings[$var .'_regex'] = ''; 1343 1344 if (!empty($settings[$var])) { 1345 $rules = preg_split('/[\s,]+/', $settings[$var]); 1346 $regex = array(); 1347 1348 if (!empty($rules)) { 1349 foreach ($rules as $rule) { 1350 if (!empty($rule)) { 1351 $rule = fckeditor_parse_rule($rule); 1352 $regex[] = '(?:'. fckeditor_rule_to_regex($rule) .')'; 1353 } 1354 } 1355 1356 if (!empty($regex)) { 1357 $settings[$var .'_regex'] = '#'. implode('|', $regex) .'#'; 1358 } 1359 } 1360 } 1361 } 1362 1363 db_query("UPDATE {fckeditor_settings} SET settings='%s' WHERE name='%s'", serialize($settings), $data->name); 1364 } 1365 } 1366 } 1367 1368 function fckeditor_rule_create($nodetype = '*', $path = '*', $fieldname = '*') { 1369 $rule = new stdClass(); 1370 $rule->nodetype = $nodetype; 1371 $rule->path = $path; 1372 $rule->field = $fieldname; 1373 1374 return $rule; 1375 } 1376 1377 function fckeditor_parse_rule($rule) { 1378 $ruleobj = new stdClass(); 1379 1380 $atpos = strpos($rule, '@'); 1381 if ($atpos !== FALSE) { 1382 $ruleobj->nodetype = substr($rule, 0, $atpos); 1383 $rule = substr($rule, $atpos + 1); 1384 } 1385 else { 1386 $ruleobj->nodetype = '*'; 1387 } 1388 1389 $dotpos = strpos($rule, '.'); 1390 if ($dotpos === FALSE) { 1391 if (strpos($rule, '/') === FALSE && strpos($rule, '-') !== FALSE) { 1392 // assume it's a field 1393 $ruleobj->path = '*'; 1394 $ruleobj->field = $rule; 1395 } 1396 elseif (strpos($rule, '/') !== FALSE) { 1397 // assume it's a path 1398 $ruleobj->path = $rule; 1399 $ruleobj->field = '*'; 1400 } 1401 else { 1402 return NULL; 1403 } 1404 } 1405 else { 1406 $ruleobj->path = substr($rule, 0, $dotpos); 1407 $ruleobj->field = str_replace('\.', '.', substr($rule, $dotpos + 1)); 1408 } 1409 1410 return $ruleobj; 1411 } 1412 1413 function fckeditor_rule_to_regex($rule) { 1414 static $replace = array('\*' => '.*', '\?' => '.'); 1415 1416 $field = str_replace('.', '\.', $rule->field); 1417 $regex = '^'. preg_quote($rule->nodetype, '#') .'@'. preg_quote($rule->path, '#') .'\.'. preg_quote($field, '#') .'$'; 1418 $regex = strtr($regex, $replace); 1419 1420 return $regex; 1421 } 1422 1423 function fckeditor_rule_to_string($rule) { 1424 $field = str_replace('.', '\.', $rule->field); 1425 $rulestr = ''; 1426 if ($rule->nodetype != '*') { 1427 $rulestr .= $rule->nodetype .'@'; 1428 } 1429 return $rulestr . $rule->path .'.'. $field; 1430 } 1431 1432 /** 1433 * Remove a profile from the database. 1434 */ 1435 function fckeditor_profile_delete($name) { 1436 db_query("DELETE FROM {fckeditor_settings} WHERE name = '%s'", $name); 1437 db_query("DELETE FROM {fckeditor_role} WHERE name = '%s'", $name); 1438 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |