[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/ckeditor/includes/ -> ckeditor.admin.inc (source)

   1  <?php
   2  // $Id: ckeditor.admin.inc,v 1.2.2.19 2010/09/15 15:23:36 wwalc Exp $
   3  /**
   4   * CKEditor - The text editor for Internet - http://ckeditor.com
   5   * Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
   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   * CKEditor Module for Drupal 6.x
  25   *
  26   * This module allows Drupal to replace textarea fields with CKEditor.
  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 ckeditor_admin_main() {
  37    module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
  38    $editor_path = ckeditor_path(TRUE);
  39    $ckconfig_file = $editor_path .'/config.js';
  40    if (!_ckeditor_requirements_isinstalled()) {
  41      drupal_set_message(t('Checking for %filename or %file.', array('%filename' => $ckconfig_file, '%file' => 'sites/all/libraries/ckeditor/ckeditor.js')));
  42      drupal_set_message(t('The CKEditor component is not installed correctly. Please go to the <a href="!ckeditorlink">CKEditor homepage</a> to download the latest version. After that you must extract the files to %ckeditorpath or %librarypath and make sure that the file %ckeditorfile or %ckeditorlibrary exist. Refer to the <a href="!readme">readme.txt</a> for more information.', array('!ckeditorlink' => url('http://ckeditor.com/download'), '!readme' => url('admin/help/ckeditor'), '%ckeditorpath' => $editor_path, '%ckeditorsubdir' => $editor_path .'/editor', '%ckeditorfile' => $editor_path .'/ckeditor.js', '%ckeditorlibrary' => 'sites/all/libraries/ckeditor/ckeditor.js', '%librarypath' => 'sites/all/libraries/ckeditor')), 'error');
  43      drupal_set_message(t('If you have CKEditor already installed please edit <a href="!editg">CKEditor Global Profile</a> and update CKEditor path.', array('!editg' => url('admin/settings/ckeditor/editg'))), 'warning');
  44      return FALSE;
  45    }
  46  
  47    $access_ckeditor_roles = user_roles(FALSE, 'access ckeditor');
  48    if (!$access_ckeditor_roles) {
  49      drupal_set_message(t('There is currently no role with the "access ckeditor" permission. Visit <a href="!acl">permissions</a> administration section.', array('!acl' => url('admin/user/permissions'))), 'warning');
  50    }
  51    else {
  52      $result = db_query_range("SELECT name FROM {ckeditor_settings} WHERE name<>'CKEditor Global Profile'", 0, 1);
  53      $has_profiles = FALSE;
  54      //find profile other than Global
  55      if (($obj = db_fetch_object($result))) {
  56        $has_profiles = TRUE;
  57      }
  58  
  59      //find roles with profiles
  60      $result = db_query("SELECT rid FROM {ckeditor_role}");
  61      $rids = array();
  62      while (($obj = db_fetch_object($result))) {
  63          $rids[] = $obj->rid;
  64      }
  65      $rids = array_unique($rids);
  66      if (!$has_profiles) {
  67        drupal_set_message(t('No CKEditor profiles found. At this moment, nobody is able to use CKEditor. Create new profile below.'), 'error');
  68      }
  69      else {
  70        //not all roles with access ckeditor has their CKEditor profile assigned
  71        $diff = array_diff(array_keys($access_ckeditor_roles), $rids);
  72        if ($diff) {
  73          $list = "<ul>";
  74          foreach ($diff as $rid) {
  75            $list .= "<li>". $access_ckeditor_roles[$rid] ."</li>";
  76          }
  77          $list .= "</ul>";
  78          drupal_set_message(t('Not all roles with <a href="!access">access ckeditor</a> permission are associated with CKEditor profiles. As a result, users having the following roles may be unable to use CKEditor: !list Create new or edit CKEditor profiles below and in the <em>Basic setup</em> section, check "Roles allowed to use this profile".', array('!access' => url('admin/user/permissions'), '!list' => $list)), 'warning');
  79        }
  80      }
  81    }
  82  
  83    return ckeditor_profile_overview();
  84  }
  85  
  86  /**
  87   * Controller for ckeditor profiles.
  88   */
  89  function ckeditor_profile_overview() {
  90    $output = '';
  91  
  92    $profiles = ckeditor_profile_load();
  93    if ($profiles) {
  94      $access_ckeditor_roles = user_roles(FALSE, 'access ckeditor');
  95      $header = array(t('Profile'), t('Roles'), t('Operations'));
  96      foreach ($profiles as $p) {
  97        $rids = $p->rids;
  98        if ($p->name !== "CKEditor Global Profile") {
  99          foreach (array_keys($p->rids) as $rid) {
 100            if (!isset($access_ckeditor_roles[$rid])) {
 101              unset($rids[$rid]);
 102            }
 103          }
 104          $rows[] = array(
 105            array('data' => $p->name, 'valign' => 'top'),
 106            array('data' => implode("<br />\n", $rids)),
 107            array('data' =>
 108              l(t('edit'), 'admin/settings/ckeditor/edit/'. urlencode($p->name)) .' '.
 109              l(t('clone'), 'admin/settings/ckeditor/clone/'. urlencode($p->name)) .' '.
 110              l(t('delete'), 'admin/settings/ckeditor/delete/'. urlencode($p->name)), 'valign' => 'top'
 111            )
 112          );
 113        }
 114      }
 115      $output .= '<h3>'. t('Profiles') .'</h3>';
 116      $output .= theme('table', $header, $rows);
 117      $output .= '<p>'. l(t('Create new profile'), 'admin/settings/ckeditor/add') .'</p>';
 118    }
 119    else {
 120      drupal_set_message(t('No profiles found. Click here to <a href="!create">create a new profile</a>.', array('!create' => url('admin/settings/ckeditor/add'))));
 121    }
 122  
 123    $rows = array();
 124    if (!isset($profiles['CKEditor Global Profile'])) {
 125      drupal_set_message(t('Global profile not found. Click here to <a href="!create">create the global profile</a>.', array('!create' => url('admin/settings/ckeditor/addg'))));
 126    }
 127    else {
 128      $output .= "<h3>". t("Global settings") ."</h3>";
 129      $rows[] = array(
 130        array('data' => t('CKEditor Global Profile'), 'valign' => 'top'),
 131        array('data' => l(t('edit'), 'admin/settings/ckeditor/editg') ." ". l(t('delete'), 'admin/settings/ckeditor/delete/CKEditor Global Profile'), 'valign' => 'top')
 132      );
 133      $output .= theme('table', array(t('Profile'), t('Operations')), $rows);
 134    }
 135    return $output;
 136  }
 137  
 138  /**
 139   * Clone profile
 140   */
 141  function ckeditor_admin_profile_clone_form($form_state, $oldprofile) {
 142    return ckeditor_admin_profile_form($form_state, $oldprofile);
 143  }
 144  
 145  function ckeditor_admin_profile_clone_form_validate($form_state, $oldprofile) {
 146    ckeditor_admin_profile_form_validate($form_state, $oldprofile);
 147  }
 148  
 149  function ckeditor_admin_profile_clone_form_submit($form, &$form_state) {
 150    $edit =& $form_state['values'];
 151    drupal_set_message(t('Your CKEditor profile has been created.'));
 152    $settings = ckeditor_admin_values_to_settings($edit);
 153    db_query("INSERT INTO {ckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], $settings);
 154    ckeditor_rebuild_selectors($edit['name']);
 155    if (!empty($edit['rids'])) {
 156      foreach (array_keys($edit['rids']) as $rid) {
 157        if ($edit['rids'][$rid]!=0) {
 158          db_query("INSERT INTO {ckeditor_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid);
 159        }
 160      }
 161    }
 162    $form_state['redirect'] = 'admin/settings/ckeditor';
 163  }
 164  
 165  /**
 166   * Form builder for a normal profile
 167   */
 168  function ckeditor_admin_profile_form($form_state, $profile = NULL) {
 169    global $theme;
 170    if ($profile != NULL) {
 171      $form['_profile'] = array(
 172        '#type' => 'value',
 173        '#value' => $profile,
 174      );
 175    }
 176    else {
 177      $profile = new stdClass();
 178    }
 179  
 180    module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
 181  
 182    $toolbar_options = ckeditor_load_toolbar_options();
 183    $skin_options = ckeditor_load_skin_options();
 184    $lang_options = ckeditor_load_lang_options();
 185  
 186    // Only display the roles that currently don't have a ckeditor profile. One
 187    // profile per role.
 188    $orig_roles = user_roles(FALSE, 'access ckeditor');
 189    $roles = $orig_roles;
 190  
 191    if (!empty($profile->rids) && !user_roles(FALSE, 'access ckeditor')) {
 192      drupal_set_message(t('You haven\'t assigned "access ckeditor" <a href="!permissions">permissions</a> yet. It is recommended to assign the "access ckeditor" <a href="!permissions">permissions</a> before updating CKEditor profiles.', array('!permissions' => url('admin/user/permissions'))), 'warning');
 193    }
 194  
 195    if (empty($profile->name)) {
 196      $result = db_query("SELECT DISTINCT(rid) FROM {ckeditor_role}");
 197      while (($data = db_fetch_object($result))) {
 198        if ((empty($profile->rids) || !in_array($data->rid, array_keys((array) $profile->rids))) && !form_get_errors()) {
 199          unset($roles[$data->rid]);
 200        }
 201      }
 202      if (count($orig_roles) != count($roles)) {
 203        drupal_set_message(t('Not all user roles are shown since they already have ckeditor profiles. You must first unassign profiles in order to add them to a new one.'));
 204      }
 205    }
 206  
 207    $form['basic'] = array(
 208      '#type' => 'fieldset',
 209      '#title' => t('Basic setup'),
 210      '#collapsible' => TRUE,
 211      '#collapsed' => TRUE
 212    );
 213  
 214    
 215    switch (arg(3)) {
 216      case 'clone':
 217        //load all profiles to check their names
 218        $profiles = ckeditor_profile_load();
 219        $oldname = $profile->name;
 220        $maxsize=128;   //default max name length
 221  
 222        $res=array();
 223        $pat = "/^(.*?)_([0-9]+)$/";
 224        if (preg_match($pat, $oldname, $res)) {     // oldname like 'name_nr'
 225          $name=$res[1];
 226          $num=$res[2]+1;
 227        }
 228        else{
 229          $name=$oldname;
 230          $num=2;
 231        }
 232  
 233        $newname=substr($name, 0, $maxsize-3) .'_'. $num;   // +limit
 234        while (isset($profiles[$newname])) {            //find next free number
 235          $num++;
 236          $newname=substr($name, 0, $maxsize-3) .'_'. $num;
 237        }
 238        //dont clone rids
 239        $profile->settings['rids']=array();
 240        $profile->rids=array();
 241        break;
 242      case 'edit':
 243        $newname = $profile->name;
 244        break;
 245    }
 246  
 247    $form['basic']['name'] = array(
 248      '#type' => 'textfield',
 249      '#title' => t('Profile name'),
 250      '#default_value' => !empty($profile->name) ? $newname : '',
 251      '#size' => 40,
 252      '#maxlength' => 128,
 253      '#description' => t('Enter a name for this profile. This name is only visible within the ckeditor administration page.'),
 254      '#required' => TRUE
 255    );
 256  
 257    $form['basic']['rids'] = array(
 258      '#type' => 'checkboxes',
 259      '#title' => t('Roles allowed to use this profile'),
 260      '#default_value' => !empty($profile->rids) ? array_keys((array) $profile->rids) : array(),
 261      '#options' => $roles,
 262      '#description' =>  t('Only roles with "access ckeditor" permission will be shown here. If no role is available, make sure that you have assigned the "access ckeditor" <a href="!permission">permission</a>.', array('!permission' => url('admin/user/permissions'))),
 263      '#required' => TRUE
 264    );
 265  
 266    $form['basic']['allow_user_conf'] = array(
 267      '#type' => 'radios',
 268      '#title' => t('Allow users to customize CKEditor appearance'),
 269      '#default_value' => !empty($profile->settings['allow_user_conf']) ? $profile->settings['allow_user_conf'] : 'f',
 270      '#options' => array(
 271        'f' => t('No'),
 272        't' => t('Yes')
 273      ),
 274      '#description' => t('If allowed, users will be able to override the "Editor appearance" by visiting their profile page.'),
 275    );
 276  
 277    $form['security'] = array(
 278      '#type' => 'fieldset',
 279      '#title' => t('Security'),
 280      '#description' => '<p>'. t('The CKEditor 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 CKEditor WYSIWYG editor evaluates HTML like a web browser and content needs to be filtered before it is loaded.') .'</p>',
 281      '#collapsible' => TRUE,
 282      '#collapsed' => TRUE
 283    );
 284  
 285    $all = filter_list_all();
 286  
 287    $form['security']['filters'] = array(
 288      '#type' => 'fieldset',
 289      '#title' => t('Security filters'),
 290      '#description' => t('Please choose carefully all filters that protect your content (probably not all filters listed below are security filters).'),
 291      '#tree' => TRUE,
 292    );
 293  
 294    //don't bother administrator with filters that definitely are not security filters
 295    $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', 'imagebrowser', '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');
 296  
 297    if (!isset($profile->settings['ss'])) {
 298      $profile->settings['filters']['filter/0'] = 1;
 299    }
 300  
 301    foreach ($all as $id => $filter) {
 302      if (in_array(strtolower($filter->module), $modules_with_filters_to_skip)) {
 303        continue;
 304      }
 305      //skip line break converter and email -> link
 306      if ($filter->module == 'filter' && in_array($filter->delta, array(1, 2))) {
 307        continue;
 308      }
 309      $form['security']['filters'][$id] = array(
 310        '#type' => 'checkbox',
 311        '#title' => $filter->name,
 312        '#default_value' => !empty($profile->settings['filters'][$id]),
 313        '#description' => module_invoke($filter->module, 'filter', 'description', $filter->delta),
 314      );
 315    }
 316  
 317    $form['security']['ss'] = array(
 318      '#type' => 'radios',
 319      '#title' => t('Security settings'),
 320      '#default_value' => isset($profile->settings['ss']) ? $profile->settings['ss'] : '2',
 321      '#options' => array(
 322        '2' => t('Always run security filters for CKEditor.'),
 323        '1' => t('Run security filters only when CKEditor is set to start automatically.'),
 324      ),
 325      '#description' => t('There are two ways of starting CKEditor: automatically and manually (via toggle or in a popup). If you decide to apply security filters only when CKEditor starts automatically, you will not be protected when toggling manually from plain text area to CKEditor or when using CKEditor 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.'),
 326    );
 327  
 328    $form['ckeditor_exclude_settings'] = array(
 329      '#type' => 'fieldset',
 330      '#title' => t('Visibility settings'),
 331      '#collapsible' => TRUE,
 332      '#collapsed' => TRUE,
 333      '#description' => t('The following settings are combined with the visibility settings of the global profile.'),
 334    );
 335  
 336    $form['ckeditor_exclude_settings']['min_rows'] = array(
 337      '#type' => 'textfield',
 338      '#title' => t('Minimum rows'),
 339      '#default_value' => !empty($profile->settings['min_rows']) ? $profile->settings['min_rows'] : '1',
 340      '#description' => t("CKEditor will be triggered if the textarea has more rows than entered here. Enter '1' if you do not want to use this feature."),
 341    );
 342  
 343    $form['ckeditor_exclude_settings']['excl_mode'] = array(
 344      '#type' => 'radios',
 345      '#title' => t('Use inclusion or exclusion mode'),
 346      '#default_value' => (empty($profile->settings['excl_mode']) || in_array($profile->settings['excl_mode'], array(0, 2))) ? 0 : 1,
 347      '#options' => array(
 348        '0' => t('Exclude'),
 349        '1' => t('Include')
 350      ),
 351      '#description' => t('Choose the way of disabling/enabling CKEditor on selected fields/paths (see below). Use exclude to disable CKEditor on selected fields/paths. Use include if you want to load CKEditor only on selected paths/fields.'),
 352    );
 353  
 354    /**
 355     * get excluded fields - so we can have normal textareas too
 356     * split the phrase by any number of commas or space characters,
 357     * which include " ", \r, \t, \n and \f
 358     */
 359    $form['ckeditor_exclude_settings']['excl'] = array(
 360      '#type' => 'textarea',
 361      '#title' => t('Fields to exclude/include'),
 362      '#cols' => 60,
 363      '#rows' => 5,
 364      '#prefix' => '<div style="margin-left:20px">',
 365      '#suffix' => '</div>',
 366      '#default_value' => !empty($profile->settings['excl']) ? $profile->settings['excl'] : '',
 367      '#description' => t('Enter the paths to the textarea fields on which you want to enable or disable CKEditor.') .' '. t('Please see the <a href="!helppagelink">help page</a> for more information about defining field names. Short instruction is available below.', array('!helppagelink' => url('admin/help/ckeditor', array('fragment' => 'fieldinclexcl')))) .' <ul><li>'. t('Path structure: <strong>content_type@path.element_id</strong>') .'</li><li>'. t('The following wildcards are available: "*", "?".') .'</li><li>'. t('Content type is optional. You may even specify only path or field id.') .'</li><li>'. t('Examples:') .'<ul><li><em>blog@*.edit-body</em> - '. t('matches all fields of type "blog" called edit-body, on any page.') .'<li><em>node/add/*.edit-user-*</em> - '. t('matches fields starting with "edit-user-" on pages starting with "node/add/') .'</li></ul></li></ul>',
 368      '#wysiwyg' => FALSE,
 369    );
 370  
 371    $form['ckeditor_exclude_settings']['simple_incl'] = array(
 372      '#type' => 'textarea',
 373      '#title' => t('Force simplified toolbar on the following fields'),
 374      '#cols' => 60,
 375      '#rows' => 5,
 376      '#default_value' => !empty($profile->settings['simple_incl']) ? $profile->settings['simple_incl'] : '',
 377      '#description' => t('Enter the paths to the textarea fields on which you want to force the simplified toolbar (!name).', array('!name' => CKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME)) .' '. t('Please see the <a href="!helppagelink">help page</a> for more information about defining field names. Take a look at the exclusion settings (above) for short instruction.', array('!helppagelink' => url('admin/help/ckeditor', array('fragment' => 'fieldinclexcl')))),
 378      '#wysiwyg' => FALSE,
 379    );
 380  
 381    $form['appearance'] = array(
 382      '#type' => 'fieldset',
 383      '#title' => t('Editor appearance'),
 384      '#collapsible' => TRUE,
 385      '#collapsed' => TRUE,
 386    );
 387  
 388    $form['appearance']['default'] = array(
 389      '#type' => 'radios',
 390      '#title' => t('Default state'),
 391      '#default_value' => !empty($profile->settings['default']) ? $profile->settings['default'] : 't',
 392      '#options' => array(
 393        't' => t('Enabled'),
 394        'f' => t('Disabled')
 395      ),
 396      '#description' => t('Default editor state. If disabled, rich text editor may still be enabled using toggle or popup window.'),
 397    );
 398  
 399    $form['appearance']['show_toggle'] = array(
 400      '#type' => 'radios',
 401      '#title' => t('Show disable/enable rich text editor toggle'),
 402      '#default_value' => !empty($profile->settings['show_toggle']) ? $profile->settings['show_toggle'] : 't',
 403      '#options' => array(
 404        't' => t('Show'),
 405        'f' => t('Hide')
 406      ),
 407      '#description' => t('Whether or not to show the disable/enable rich text editor toggle below the textarea. Works only if CKEditor is not running in a popup window (see below).'),
 408    );
 409  
 410    $form['appearance']['popup'] = array(
 411      '#type' => 'radios',
 412      '#title' => t('Use CKEditor in a popup window'),
 413      '#default_value' => !empty($profile->settings['popup']) ? $profile->settings['popup'] : 'f',
 414      '#options' => array(
 415        'f' => t('No'),
 416        't' => t('Yes')
 417      ),
 418      '#description' => t('If this option is enabled a link to a popup window will be used instead of a textarea replace.'),
 419    );
 420  
 421    $form['appearance']['skin'] = array(
 422      '#type' => 'select',
 423      '#title' => t('Skin'),
 424      '#default_value' => !empty($profile->settings['skin']) ? $profile->settings['skin'] : 'default',
 425      '#options' => $skin_options,
 426      '#description' => t('Choose a default skin.'),
 427    );
 428  
 429    $ui_colors = array(
 430    "default" => t('CKEditor default'),
 431    "custom" => t('Select manually')
 432    );
 433    if (function_exists('color_get_palette')) {
 434      // apparently $theme is not initialized (?)
 435      if (empty($theme)) {
 436        init_theme();
 437      }
 438      $palette = @color_get_palette($theme, FALSE); //[#652274]
 439      $color_palette['default'] = '#D3D3D3';
 440      if (!empty($palette)) {
 441        if (!empty($palette['base'])) {
 442          $color_palette['color_base'] = $palette['base'];
 443          $ui_colors["color_base"] = t('Color module: base');
 444        }
 445        if (!empty($palette['top'])) {
 446          $color_palette['color_top'] = $palette['top'];
 447          $ui_colors["color_top"] = t('Color module: top');
 448        }
 449        if (!empty($palette['bottom'])) {
 450          $color_palette['color_bottom'] = $palette['bottom'];
 451          $ui_colors["color_bottom"] = t('Color module: bottom');
 452        }
 453      }
 454      drupal_add_js(array('ckeditor_uicolor' => $color_palette), 'setting');
 455    }
 456  
 457    $editor_path = ckeditor_path(FALSE);
 458    $module_drupal_path = drupal_get_path('module', 'ckeditor');
 459    drupal_add_js($module_drupal_path .'/includes/ckeditor.admin.js');
 460    drupal_set_html_head('<script type="text/javascript" src="'. $editor_path .'/ckeditor.js?I"></script>');
 461  
 462    $form['appearance']['uicolor'] = array(
 463      '#type' => 'select',
 464      '#title' => t('User Interface color'),
 465      '#default_value' => !empty($profile->settings['uicolor']) ? $profile->settings['uicolor'] : 'default',
 466      '#options' => $ui_colors,
 467      '#description' => t('Works only with "!skin" skin.',
 468        array(
 469          '!skin' => 'Kama'
 470        )),
 471      );
 472    $form['appearance']['uicolor_textarea'] = array(
 473      '#type' => 'textarea',
 474      '#title' => '',
 475      '#default_value' => 'Click on the <strong>UI Color Picker</strong> button to set your color preferences.',
 476      '#attributes' => array('style' => 'display:none', 'class' => 'ckeditor_ui_demo'),
 477      '#resizable' => FALSE,
 478      '#wysiwyg' => FALSE
 479    );
 480    $form['appearance']['uicolor_user'] = array(
 481      '#type' => 'hidden',
 482      '#default_value' => !empty($profile->settings['uicolor_user']) ? $profile->settings['uicolor_user'] : 'default',
 483    );
 484  
 485    $form['appearance']['toolbar'] = array(
 486      '#type' => 'select',
 487      '#title' => t('Toolbar'),
 488      '#default_value' => !empty($profile->settings['toolbar']) ? $profile->settings['toolbar'] : 'default',
 489      '#options' => $toolbar_options,
 490      '#description' => t('Choose a default toolbar set. To define new toolbar, edit "ckeditor.config.js" located in "!module_path".', array('!module_path' => drupal_get_path('module', 'ckeditor'))),
 491    );
 492  
 493    $form['appearance']['expand'] = array(
 494      '#type' => 'radios',
 495      '#title' => t('Start the toolbar expanded'),
 496      '#default_value' => !empty($profile->settings['expand']) ? $profile->settings['expand'] : 't',
 497      '#options' => array(
 498        't' => t('Expanded'),
 499        'f' => t('Collapsed')
 500      ),
 501      '#description' => t('The toolbar start expanded or collapsed.'),
 502    );
 503  
 504    $form['appearance']['width'] = array(
 505      '#type' => 'textfield',
 506      '#title' => t('Width'),
 507      '#default_value' => !empty($profile->settings['width']) ? $profile->settings['width'] : '100%',
 508      '#description' => t("Width in pixels or percent. Example: 400 or 100%."),
 509      '#size' => 40,
 510      '#maxlength' => 128,
 511    );
 512  
 513    $form['appearance']['lang'] = array(
 514      '#type' => 'select',
 515      '#title' => t('Language'),
 516      '#default_value' => !empty($profile->settings['lang']) ? $profile->settings['lang'] : 'en',
 517      '#options' => $lang_options,
 518      '#description' => t('The language for the CKEditor interface.')
 519    );
 520  
 521    $form['appearance']['auto_lang'] = array(
 522      '#type' => 'radios',
 523      '#title' => t('Auto-detect language'),
 524      '#default_value' => !empty($profile->settings['auto_lang']) ? $profile->settings['auto_lang'] : 't',
 525      '#options' => array(
 526        't' => t('Enabled'),
 527        'f' => t('Disabled')
 528      ),
 529      '#description' => t('Use auto detect user language feature.')
 530    );
 531  
 532    $form['appearance']['language_direction'] = array(
 533      '#type' => 'select',
 534      '#title' => t('Language Direction'),
 535      '#default_value' => !empty($profile->settings['language_direction']) ? $profile->settings['language_direction'] : 'default',
 536      '#options' => array(
 537        'default' => t('Get from current locale (default)'),
 538        'ltr' => t('Left-To-Right'),// language (like English)
 539        'rtl' => t('Right-To-Left') // languages (like Arabic)
 540      ),
 541      '#description' => t('Choose language direction used in the editing area. Even when CKEditor auto detects user language and adjusts it\'s user interface, the editing area is not automatically changed into LTR or RTL mode. To be able to type LTR (like English) and RTL (like Arabic, Hebrew, Persian) content at the same time, please take a look at the <b>Styles</b> combo and <b>Language: RTL</b>, <b>Language: LTR</b> styles available there. Note: this combo box is not available in the default toolbar, the <b>Styles</b> button needs to be added to the toolbar in ckeditor.config.js.')
 542    );
 543  
 544    $form['output'] = array(
 545      '#type' => 'fieldset',
 546      '#title' => t('Cleanup and output'),
 547      '#collapsible' => TRUE,
 548      '#collapsed' => TRUE,
 549    );
 550  
 551    $form['output']['enter_mode'] = array(
 552      '#type' => 'select',
 553      '#title' => t('Enter mode'),
 554      '#default_value' => !empty($profile->settings['enter_mode']) ? $profile->settings['enter_mode'] : 'p',
 555      '#options' => array(
 556        'p' => '<p>',
 557        'br' => '<br>',
 558        'div' => '<div>'
 559      ),
 560      '#description' => t('Set which tag CKEditor should use when [Enter] key is pressed.')
 561    );
 562  
 563    $form['output']['shift_enter_mode'] = array(
 564      '#type' => 'select',
 565      '#title' => t('Shift + Enter mode'),
 566      '#default_value' => !empty($profile->settings['shift_enter_mode']) ? $profile->settings['shift_enter_mode'] : 'br',
 567      '#options' => array(
 568        'p' => '<p>',
 569        'br' => '<br>',
 570        'div' => '<div>'
 571      ),
 572      '#description' => t('Set which tag CKEditor should use when [Shift] + [Enter] is pressed.')
 573    );
 574  
 575    $form['output']['font_format'] = array(
 576      '#type' => 'textfield',
 577      '#title' => t('Font formats'),
 578      '#default_value' => !empty($profile->settings['font_format']) ? $profile->settings['font_format'] : 'p;div;pre;address;h1;h2;h3;h4;h5;h6',
 579      '#size' => 40,
 580      '#maxlength' => 250,
 581      '#description' => t('Semicolon separated list of HTML font formats. Allowed values are: p;div;pre;address;h1;h2;h3;h4;h5;h6'),
 582    );
 583  
 584    if (!empty($profile->settings['formatting']['custom_formatting_options']))
 585    foreach( $profile->settings['formatting']['custom_formatting_options'] as $k => $v ) {
 586      if ($v === 0) {
 587        unset($profile->settings['formatting']['custom_formatting_options'][$k]);
 588      }
 589    }
 590  
 591    $form['output']['custom_formatting'] = array(
 592      '#type' => 'radios',
 593      '#title' => t('Use custom formatting options'),
 594      '#default_value' => !empty($profile->settings['custom_formatting']) ? $profile->settings['custom_formatting'] : 'f',
 595      '#options' => array(
 596        't' => t('Yes'),
 597        'f' => t('No'),
 598      ),
 599    );
 600  
 601    $form['output']['formatting'] = array(
 602      '#type' => 'fieldset',
 603      '#title' => t('Custom formatting options'),
 604      '#tree' => TRUE,
 605    );
 606  
 607    $form['output']['formatting']['custom_formatting_options'] = array(
 608      '#type' => 'checkboxes',
 609      '#default_value' => isset($profile->settings['formatting']['custom_formatting_options']) ? array_keys((array) $profile->settings['formatting']['custom_formatting_options']) : array('indent' => 'indent', 'breakBeforeOpen' => 'breakBeforeOpen', 'breakAfterOpen' => 'breakAfterOpen', 'breakAfterClose' => 'breakAfterClose'),
 610      '#options' => array(
 611        'indent' => t('indent the element contents'),
 612        'breakBeforeOpen' => t('break line before the opener tag'),
 613        'breakAfterOpen' => t('break line after the opener tag'),
 614        'breakBeforeClose' => t('break line before the closer tag'),
 615        'breakAfterClose' => t('break line after the closer tag'),
 616        'pre_indent' => t('indent the &lt;pre&gt; element contents'),
 617      ),
 618    );
 619  
 620    $form['css'] = array(
 621      '#type' => 'fieldset',
 622      '#title' => t('CSS'),
 623      '#collapsible' => TRUE,
 624      '#collapsed' => TRUE
 625    );
 626  
 627    $form['css']['css_mode'] = array(
 628      '#type' => 'select',
 629      '#title' => t('Editor CSS'),
 630      '#default_value' => !empty($profile->settings['css_mode']) ? $profile->settings['css_mode'] : 'theme',
 631      '#options' => array(
 632        'theme' => t('Use theme css'),
 633        'self' => t('Define css'),
 634        'none' => t('CKEditor default')
 635      ),
 636      '#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 />CKEditor default - uses default CSS from editor.')
 637    );
 638  
 639    $form['css']['css_path'] = array(
 640      '#type' => 'textfield',
 641      '#title' => t('CSS path'),
 642      '#default_value' => !empty($profile->settings['css_path']) ? $profile->settings['css_path'] : "",
 643      '#size' => 40,
 644      '#maxlength' => 255,
 645      '#description' => t('Enter path to CSS file (Example: !example1) or a list of css files separated by a comma (Example: !example2). Make sure to select "Define css" above.',
 646        array(
 647          '!example1' => '"css/editor.css"',
 648          '!example2' => '"/themes/garland/style.css,http://example.com/style.css"',
 649        )) .
 650        '<br />'.
 651        t('Available placeholders:!h - host name (!host).!t - path to theme (!theme).',
 652          array(
 653          '!h' => '<br /><strong>%h</strong>',
 654          '!t' => '<br /><strong>%t</strong>',
 655          '!host' => base_path(),
 656          '!theme' => base_path() . path_to_theme() .'/'
 657          ))
 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 ckeditor.styles.js'),
 666        'self' => t('Define path to ckeditor.styles.js'),
 667        'default' => t('CKEditor default')
 668      ),
 669      '#description' => t('Define the location of "ckeditor.styles.js" file. It is used by the "Style" dropdown list available in the default toolbar. Copy "!ckeditor.styles.js" inside your theme directory ("!theme") and adjust it to your needs.', array('!ckeditor.styles.js' => ckeditor_path(TRUE) .'/ckeditor.styles.js', '!theme' => path_to_theme() .'/ckeditor.styles.js'))
 670    );
 671  
 672    $form['css']['styles_path'] = array(
 673      '#type' => 'textfield',
 674      '#title' => t('Predefined styles path'),
 675      '#default_value' => !empty($profile->settings['styles_path']) ? $profile->settings['styles_path'] : "",
 676      '#size' => 40,
 677      '#maxlength' => 255,
 678      '#description' => t('Enter path to a file with predefined styles (Example: "!example1"). Be sure to select "define path to ckeditor.styles.js" above.',
 679        array(
 680          '!example1' => '/ckeditor.styles.js'
 681        )) .
 682        '<br />'.
 683        t('Available placeholders:!h - host name (!host).!t - path to theme (!theme).!m - path to CKEditor module (!module).',
 684        array(
 685          '!h' => '<br /><strong>%h</strong>',
 686          '!t' => '<br /><strong>%t</strong>',
 687          '!m' => '<br /><strong>%m</strong>',
 688          '!host' => base_path(),
 689          '!theme' => base_path() . path_to_theme() .'/',
 690          '!module' => drupal_get_path('module', 'ckeditor'))
 691        )
 692    );
 693  
 694    $form['ckeditor_upload_settings'] = array(
 695      '#type' => 'fieldset',
 696      '#title' => t('File browser settings'),
 697      '#collapsible' => TRUE,
 698      '#collapsed' => TRUE,
 699      '#description' => t('Set file browser settings. A file browser will allow you to explore the files contained on the server and embed them as links, images or flash movies. CKEditor is compatible with contributed modules like <a href="!imce">IMCE</a>, <a href="!ib">Image Browser</a> or <a href="!webfm">Web File Manager</a>. CKEditor can be also integrated with <a href="!ckfinder">CKFinder</a>.', array('!imce' => url('http://drupal.org/project/imce'), '!ib' => url('http://drupal.org/project/imagebrowser'), '!webfm' => url('http://drupal.org/project/webfm'), '!readme' => url('admin/help/ckeditor'), '!ckfinder' => url('http://ckfinder.com')))
 700    );
 701  
 702    $filebrowsers = array(
 703      'none' => t('None'),
 704      'ckfinder' => t('CKFinder'),
 705    );
 706  
 707    $filebrowsers_dialogs = array(
 708      '' => t('Same as in Link dialog'),
 709      'ckfinder' => t('CKFinder'),
 710    );
 711  
 712    if (module_exists('imce')) {
 713      $filebrowsers['imce'] = t('IMCE');
 714      $filebrowsers_dialogs['imce'] = t('IMCE');
 715    }
 716  
 717    if (module_exists('tinybrowser')) {
 718      $filebrowsers['tinybrowser'] = t('TinyBrowser');
 719      $filebrowsers_dialogs['tinybrowser'] = t('TinyBrowser');
 720    }
 721  
 722    if (module_exists('imagebrowser')) {
 723      $filebrowsers['ib'] = t('Image Browser');
 724      $filebrowsers_dialogs['ib'] = t('Image Browser');
 725    }
 726  
 727    if (module_exists('webfm_popup')) {
 728      $filebrowsers['webfm'] = t('Web File Manager');
 729      $filebrowsers_dialogs['webfm'] = t('Web File Manager');
 730    }
 731  
 732    $form['ckeditor_upload_settings']['filebrowser'] = array(
 733      '#type' => 'select',
 734      '#title' => t('File browser type (Link dialog)'),
 735      '#default_value' => !empty($profile->settings['filebrowser']) ? $profile->settings['filebrowser'] : 'none',
 736      '#options' => $filebrowsers,
 737      '#description' => t('Select the file browser that you would like to use to upload files.'),
 738    );
 739  
 740    $form['ckeditor_upload_settings']['filebrowser_image'] = array(
 741      '#type' => 'select',
 742      '#title' => t('File browser type (Image dialog)'),
 743      '#default_value' => !empty($profile->settings['filebrowser_image']) ? $profile->settings['filebrowser_image'] : 'none',
 744      '#options' => $filebrowsers_dialogs,
 745      '#description' => t('Select the file browser that you would like to use to upload images.'),
 746    );
 747  
 748    $form['ckeditor_upload_settings']['filebrowser_flash'] = array(
 749      '#type' => 'select',
 750      '#title' => t('File browser type (Flash dialog)'),
 751      '#default_value' => !empty($profile->settings['filebrowser_flash']) ? $profile->settings['filebrowser_flash'] : 'none',
 752      '#options' => $filebrowsers_dialogs,
 753      '#description' => t('Select the file browser that you would like to use to upload flash movies.'),
 754    );
 755  
 756    $current_user_files_path = empty($profile->settings['UserFilesPath']) ? "" : strtr($profile->settings['UserFilesPath'], array("%f" => file_directory_path(), "%u" => "UID", "%b" => base_path(), "%n" => "UNAME"));
 757    $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"));
 758  
 759    $form['ckeditor_upload_settings']['UserFilesPath'] = array(
 760      '#type' => 'textfield',
 761      '#prefix' => '<fieldset><legend>' . t('CKFinder settings') .'</legend>',
 762      '#title' => t('Path to uploaded files'),
 763      '#default_value' => !empty($profile->settings['UserFilesPath']) ? $profile->settings['UserFilesPath'] : "%b%f/",
 764      '#size' => 40,
 765      '#maxlength' => 255,
 766      '#description' => t('Path to uploaded files relative to the document root.') .
 767        '<br />'.
 768        t('Available placeholders:!b - base URL path of the Drupal installation (!base).!f - Drupal file system path where the files are stored (!files).!u - User ID.!n - Username.<br />Current path: !path',
 769          array(
 770            '!n' => '<br /><strong>%n</strong>',
 771            '!u' => '<br /><strong>%u</strong>',
 772            '!f' => '<br/><strong>%f</strong>',
 773            '!b' => '<br/><strong>%b</strong>',
 774            '!path' => $current_user_files_path,
 775            '!files' => file_directory_path(),
 776            '!base' => base_path()
 777          ))
 778    );
 779  
 780    $form['ckeditor_upload_settings']['UserFilesAbsolutePath'] = array(
 781      '#type' => 'textfield',
 782      '#title' => t('Absolute path to uploaded files'),
 783      '#default_value' => !empty($profile->settings['UserFilesAbsolutePath']) ? $profile->settings['UserFilesAbsolutePath'] : "%d%b%f/",
 784      '#size' => 40,
 785      '#maxlength' => 255,
 786      '#suffix' => '</fieldset>',
 787      '#description' => t('The path to the local directory (in the server) which points to the path defined above. If empty, CKEditor will try to discover the right path.') .
 788        '<br />'.
 789        t('Available placeholders:!d - server path to document root (!root).!b - base URL path of the Drupal installation (!base).!f - Drupal file system path where the files are stored (!files).!u - User ID.!n - Username.<br />Current path: !path',
 790          array(
 791            '!u' => '<br /><strong>%u</strong>',
 792            '!n' => '<br /><strong>%n</strong>',
 793            '!d' => '<br/><strong>%d</strong>',
 794            '!b' => '<br /><strong>%b</strong>',
 795            '!f' => '<br/><strong>%f</strong>',
 796            '!path' => $current_user_files_absolute_path,
 797            '!files' => file_directory_path(),
 798            '!base' => base_path(),
 799            '!root' => $_SERVER['DOCUMENT_ROOT']
 800          ))
 801    );
 802  
 803    if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE) {
 804      $form['ckeditor_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 <a href="!url">CKEditor Global Profile</a>.', array('!url' => url('admin/settings/ckeditor/editg')));
 805      $form['ckeditor_upload_settings']['UserFilesPath']['#disabled'] = TRUE;
 806      $form['ckeditor_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 <a href="!url">CKEditor Global Profile</a>.', array('!global' => url('admin/settings/ckeditor/editg')));
 807      $form['ckeditor_upload_settings']['UserFilesAbsolutePath']['#disabled'] = TRUE;
 808    }
 809  
 810    $form['advanced'] = array(
 811      '#type' => 'fieldset',
 812      '#title' => t('Advanced options'),
 813      '#collapsible' => TRUE,
 814      '#collapsed' => TRUE,
 815    );
 816    $form['advanced']['ckeditor_load_method'] = array(
 817      '#type' => 'select',
 818      '#title' => t('Load method'),
 819      '#default_value' => !empty($profile->settings['ckeditor_load_method']) ? $profile->settings['ckeditor_load_method'] : 'ckeditor.js',
 820      '#options' => _ckeditor_load_methods(),
 821      '#description' => t('Select the load method of CKEditor. If ckeditor_basic.js is used, only a small file is initially loaded and the rest part of the editor is loaded later (see "Load timeout"). This might be handy if CKEditor is disabled by default.'),
 822    );
 823    $form['advanced']['ckeditor_load_time_out'] = array(
 824      '#type' => 'textfield',
 825      '#title' => t('Load timeout'),
 826      '#default_value' => !empty($profile->settings['ckeditor_load_time_out']) ? $profile->settings['ckeditor_load_time_out'] : "0",
 827      '#size' => 40,
 828      '#maxlength' => 255,
 829      '#description' => t('The time to wait (in seconds) to load the full editor code after the page load, if the "ckeditor_basic.js" file is used. If set to zero, the editor is loaded on demand.'),
 830    );
 831    $form['advanced']['forcePasteAsPlainText'] = array(
 832      '#type' => 'select',
 833      '#title' => t('Force pasting as plain text'),
 834      '#default_value' => !empty($profile->settings['forcePasteAsPlainText']) ? $profile->settings['forcePasteAsPlainText'] : "f",
 835      '#options' => array(
 836        't' => t('Enabled'),
 837        'f' => t('Disabled')
 838        ),
 839        '#description' => t('If enabled, HTML content will be automatically changed to plain text when pasting.'),
 840    );
 841    $form['advanced']['scayt_autoStartup'] = array(
 842      '#type' => 'radios',
 843      '#title' => t('Spell checker'),
 844      '#default_value' => !empty($profile->settings['scayt_autoStartup']) ? $profile->settings['scayt_autoStartup'] : 'f',
 845      '#description' => t('If enabled, turns on SCAYT (Spell Check As You Type) automatically after loading the editor.'),
 846      '#options' => array(
 847        'f' => t('No'),
 848        't' => t('Yes')
 849      ),
 850    );
 851    $form['advanced']['theme_config_js'] = array(
 852      '#type' => 'radios',
 853      '#title' => t('Load ckeditor.config.js from theme path'),
 854      '#default_value' => !empty($profile->settings['theme_config_js']) ? $profile->settings['theme_config_js'] : 'f',
 855      '#options' => array(
 856        't' => t('Yes'),
 857        'f' => t('No')
 858      ),
 859      '#description' => t('When set to "true" the editor will try to load the ckeditor.config.js file from theme directory.'),
 860    );
 861    $form['advanced']['js_conf'] = array(
 862      '#type' => 'textarea',
 863      '#title' => t('Custom javascript configuration'),
 864      '#default_value' => !empty($profile->settings['js_conf']) ? $profile->settings['js_conf'] : "",
 865      '#cols' => 60,
 866      '#rows' => 5,
 867      '#description' => t('To change CKEditor configuration globally, you should modify the config file: "!ckeditor_config". Sometimes it is required to change the CKEditor configuration for a single profile only. Use this box to define settings that are unique for this profile. Available options are listed in the <a href="!docs">CKEditor documentation</a>. Add the following code snippet to change available fonts in combo boxes in CKEditor: <pre>@code</pre><strong>Warning</strong>: If you make something wrong here, CKEditor may fail to load.', array('!ckeditor_config' => drupal_get_path('module', 'ckeditor') ."/ckeditor.config.js", '!docs' => 'http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html', '@code' => "fontSize_sizes = '16/16px;24/24px;48/48px;'\nfont_names = 'Arial;Times New Roman;Verdana'")),
 868      '#wysiwyg' => FALSE,
 869    );
 870  
 871    $form['submit'] = array(
 872      '#type' => 'submit',
 873      '#value' => t('Save')
 874    );
 875  
 876    return $form;
 877  }
 878  
 879  /**
 880   * Profile validation.
 881   */
 882  function ckeditor_admin_profile_form_validate($form, &$form_state) {
 883    $edit =& $form_state['values'];
 884  
 885    //include mode and all other fields are empty, invalid
 886    if ($edit['excl_mode'] == 1 && empty($edit['excl'])) {
 887      form_set_error('excl_mode', t('Include mode selected, but no paths given. Enter at least one path where CKEditor should appear.'));
 888    }
 889    else {
 890      ckeditor_admin_profile_validate_fieldpaths('excl', $edit['excl']);
 891    }
 892  
 893    ckeditor_admin_profile_validate_fieldpaths('simple_incl', $edit['simple_incl']);
 894  
 895    if (!preg_match('/^\d+$/', trim($edit['min_rows']))) {
 896      form_set_error('min_rows', t('Minimum rows must be a valid number.'));
 897    }
 898  
 899    if ($edit['default'] == 't' && $edit['popup'] == 't') {
 900      form_set_error('popup', t('If CKEditor is enabled by default, popup window must be disabled.'));
 901    }
 902  
 903    if ($edit['show_toggle'] == 't' && $edit['popup'] == 't') {
 904      form_set_error('popup', t('If toggle is enabled, popup window must be disabled.'));
 905    }
 906  
 907    if (!$edit['name']) {
 908      form_set_error('name', t('You must give a profile name.'));
 909    }
 910    elseif (!preg_match('/^[A-Za-z0-9_]+$/', $edit['name'])) {
 911      form_set_error('name', t('Enter valid profile name. Only alphanumeric and underscore characters are allowed.'));
 912    }
 913    elseif ($edit['name'] == 'CKEditor Global Profile') {
 914      form_set_error('name', t('This profile name is reserved. Please choose a different name.'));
 915    }
 916    elseif (!isset($edit['_profile']) || ($edit['_profile']->name != $edit['name'])) {
 917      $result = ckeditor_profile_load($edit['name']);
 918      if (!empty($result)) {
 919        form_set_error('name', t('The profile name must be unique. A profile with this name already exists.'));
 920      }
 921    }
 922  
 923    if (!preg_match('/^\d+%?$/', $edit['width'])) {
 924      form_set_error('width', t('Enter valid width. Example: 400 or 100%.'));
 925    }
 926  
 927    if (!empty($edit['css_path'])) {
 928      if ($edit['css_mode'] != 'self') {
 929        form_set_error('css_path', t('CSS path is not empty. Please set the "Editor CSS" option to "define css" mode.'));
 930      }
 931      elseif (FALSE !== strpos($edit['css_path'], '"')) {
 932        form_set_error('css_path', t('Double quotes are not allowed in CSS path.'));
 933      }
 934      elseif (substr($edit['css_path'], 0, 1) == "'" && substr($edit['css_path'], -1) == "'") {
 935        form_set_error('css_path', t('Enter valid path, do not surround it with quotes.'));
 936      }
 937    }
 938  
 939    if (!empty($edit['styles_path'])) {
 940      if ($edit['css_style'] != 'self') {
 941        form_set_error('styles_path', t('Path to predefined styles is not empty. Please set the "Predefined styles" option to "define path to ckeditor.styles.js" mode.'));
 942      }
 943      elseif (FALSE !== strpos($edit['styles_path'], '"')) {
 944        form_set_error('styles_path', t('Double quotes are not allowed in path.'));
 945      }
 946      elseif (substr($edit['styles_path'], 0, 1) == "'" && substr($edit['styles_path'], -1) == "'") {
 947        form_set_error('styles_path', t('Enter valid path, do not surround it with quotes.'));
 948      }
 949    }
 950  
 951    if (!empty($edit['font_format'])) {
 952      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'])) {
 953        form_set_error('font_format', t('Enter valid, semicolon separated, list of HTML font formats (no semicolon at the end of list expected).'));
 954      }
 955    }
 956  
 957    if (variable_get('file_downloads', '') !== FILE_DOWNLOADS_PRIVATE) {
 958      if (!empty($edit['UserFilesAbsolutePath']) && empty($edit['UserFilesPath'])) {
 959        form_set_error('UserFilesPath', t('Path to uploaded files is required.'));
 960      }
 961      if (!empty($edit['UserFilesPath']) && empty($edit['UserFilesAbsolutePath'])) {
 962        form_set_error('UserFilesPath', t('Absolute path to uploaded files is required.'));
 963      }
 964    }
 965    $load_methods=_ckeditor_load_methods();
 966    if (!isset($load_methods[$edit['ckeditor_load_method']])) {
 967      form_set_error('ckeditor_load_method', t('Set valid load method.'));
 968    }
 969    if (!preg_match('#\d+#', $edit['ckeditor_load_time_out'])) {
 970      form_set_error('ckeditor_load_time_out', t('Enter valid load timeout in seconds.'));
 971    }
 972  }
 973  
 974  function ckeditor_admin_profile_form_submit($form, &$form_state) {
 975    $edit =& $form_state['values'];
 976  
 977    if (isset($edit['_profile'])) {
 978      db_query("DELETE FROM {ckeditor_settings} WHERE name = '%s'", $edit['_profile']->name);
 979      db_query("DELETE FROM {ckeditor_role} WHERE name = '%s'", $edit['_profile']->name);
 980      drupal_set_message(t('Your CKEditor profile has been updated.'));
 981    }
 982    else {
 983      drupal_set_message(t('Your CKEditor profile has been created.'));
 984    }
 985  
 986    $settings = ckeditor_admin_values_to_settings($edit);
 987    db_query("INSERT INTO {ckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], $settings);
 988    ckeditor_rebuild_selectors($edit['name']);
 989    if (!empty($edit['rids'])) {
 990      foreach (array_keys($edit['rids']) as $rid) {
 991        if ($edit['rids'][$rid]!=0) {
 992          db_query("INSERT INTO {ckeditor_role} (name, rid) VALUES ('%s', %d)", $edit['name'], $rid);
 993        }
 994      }
 995    }
 996  
 997    $form_state['redirect'] = 'admin/settings/ckeditor';
 998  }
 999  
1000  function ckeditor_admin_global_profile_form($form_state, $mode = 'add') {
1001    module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
1002    if ($mode == 'edit') {
1003      $profile = ckeditor_profile_load('CKEditor Global Profile');
1004  
1005      $form['_profile'] = array(
1006        '#type' => 'value',
1007        '#value' => $profile,
1008      );
1009    }
1010    else {
1011      $profile = new stdClass();
1012    }
1013  
1014    if ($mode == 'add') {
1015      $data = ckeditor_profile_load('CKEditor Global Profile');
1016      if (!empty($data)) {
1017        drupal_set_message(t('Global profile already exist. Only one global profile is allowed.'), 'error');
1018        drupal_not_found();
1019      }
1020  
1021      $btn = t('Create global profile');
1022    }
1023    else {
1024      $btn = t('Update global profile');
1025    }
1026  
1027    $form['common'] = array(
1028      '#type' => 'fieldset',
1029      '#title' => t('Main setup'),
1030      '#collapsible' => TRUE,
1031      '#collapsed' => TRUE
1032    );
1033  
1034    $roles = ckeditor_sorted_roles();
1035    $rids = $rtext = array();
1036    foreach ($roles as $rid => $name) {
1037      $rids[] = $rid;
1038      $rtext[] = '<strong>'. $rid .' - </strong>'. $name;
1039    }
1040    $form['common']['rank'] = array(
1041      '#type' => 'textfield',
1042      '#title' => t('Role precedence'),
1043      '#default_value' => implode('>', $rids),
1044      '#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.'),
1045    );
1046    if ($rids) {
1047      $form['common']['rank']['#description'] .= '<br />'. t('Here is the id-name pairs of roles having access to CKEditor:') .'<div>'. implode('<br />', $rtext) .'</div>';
1048    }
1049    else {
1050      $form['common']['rank']['#description'] .= '<br />'. t('You haven\'t assigned the "access ckeditor" <a href="!permissions">permissions</a> yet.', array('!permissions' => url('admin/user/permissions')));
1051    }
1052  
1053    $form['ckeditor_exclude_settings'] = array(
1054      '#type' => 'fieldset',
1055      '#title' => t('Visibility settings'),
1056      '#collapsible' => TRUE,
1057      '#collapsed' => TRUE,
1058      '#description' => t('The following settings are combined with the visibility settings of the specific profile.'),
1059    );
1060  
1061    $form['ckeditor_exclude_settings']['excl_mode'] = array(
1062      '#type' => 'radios',
1063      '#title' => t('Use inclusion or exclusion mode'),
1064      '#default_value' => (empty($profile->settings['excl_mode']) || in_array($profile->settings['excl_mode'], array(0, 2))) ? 0 : 1,
1065      '#options' => array(
1066        '0' => t('Exclude'),
1067        '1' => t('Include')
1068      ),
1069      '#description' => t('Choose the way of disabling/enabling CKEditor on selected fields/paths (see below). Use exclude to disable CKEditor on selected fields/paths. Use include if you want to load CKEditor only on selected paths/fields.'),
1070    );
1071    /**
1072     * get excluded fields - so we can have normal textareas too
1073     * split the phrase by any number of commas or space characters,
1074     * which include " ", \r, \t, \n and \f
1075     */
1076    $form['ckeditor_exclude_settings']['excl'] = array(
1077      '#type' => 'textarea',
1078      '#title' => t('Fields to exclude/include'),
1079      '#cols' => 60,
1080      '#rows' => 5,
1081      '#prefix' => '<div style="margin-left:20px">',
1082      '#suffix' => '</div>',
1083      '#default_value' => !empty($profile->settings['excl']) ? $profile->settings['excl'] : '',
1084      '#description' => t('Enter the paths to the textarea fields on which you want to enable or disable CKEditor.') .' '. t('Please see the <a href="!helppagelink">help page</a> for more information about defining field names. Short instruction is available below.', array('!helppagelink' => url('admin/help/ckeditor', array('fragment' => 'fieldinclexcl')))) .' <ul><li>'. t('Path structure: <strong>content_type@path.element_id</strong>') .'</li><li>'. t('The following wildcards are available: "*", "?".') .'</li><li>'. t('Content type is optional. You may even specify only path or field id.') .'</li><li>'. t('Examples:') .'<ul><li><em>blog@*.edit-body</em> - '. t('matches all fields of type "blog" called edit-body, on any page.') .'<li><em>node/add/*.edit-user-*</em> - '. t('matches fields starting with "edit-user-" on pages starting with "node/add/') .'</li></ul></li></ul>',
1085      '#wysiwyg' => FALSE,
1086    );
1087  
1088    $form['ckeditor_exclude_settings']['simple_incl'] = array(
1089      '#type' => 'textarea',
1090      '#title' => t('Force simplified toolbar on the following fields'),
1091      '#cols' => 60,
1092      '#rows' => 5,
1093      '#default_value' => !empty($profile->settings['simple_incl']) ? $profile->settings['simple_incl'] : '',
1094      '#description' => t('Enter the paths to the textarea fields on which you want to force the simplified toolbar (!name).', array('!name' => CKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME)) .' '. t('Please see the <a href="!helppagelink">help page</a> for more information about defining field names. Take a look at the exclusion settings (above) for short instruction.', array('!helppagelink' => url('admin/help/ckeditor', array('fragment' => 'fieldinclexcl')))),
1095      '#wysiwyg' => FALSE,
1096    );
1097  
1098    $form['ckeditor_advanced_settings'] = array(
1099      '#type' => 'fieldset',
1100      '#title' => t('Advanced settings'),
1101      '#collapsible' => TRUE,
1102      '#collapsed' => TRUE,
1103    );
1104  
1105    $module_drupal_path = drupal_get_path('module', 'ckeditor');
1106  
1107    $form['ckeditor_advanced_settings']['ckeditor_path'] = array(
1108      '#type' => 'textfield',
1109      '#title' => t('Path to CKEditor'),
1110      '#default_value' =>  !empty($profile->settings['ckeditor_path']) ? $profile->settings['ckeditor_path'] : '%m/ckeditor',
1111      '#size' => 40,
1112      '#maxlength' => 128,
1113      '#description' => t('Path to CKEditor (the HTML editor, downloaded from <a href="!ckeditorcom">ckeditor.com</a>) relative to the document root.') .
1114        '<br />'.
1115        t('Available placeholders:!b - base URL path of the Drupal installation (!base).!m - base URL path where CKEditor module is stored (!files).<br />Current path: !path',
1116        array(
1117          '!b' => '<br /><strong>%b</strong>',
1118          '!m' => '<br /><strong>%m</strong>',
1119          '!path' => ckeditor_path(FALSE),
1120          '!base' => base_path(),
1121          '!files' => base_path() . $module_drupal_path ,
1122          '!ckeditorcom' => 'http://ckeditor.com/download'
1123       )),
1124      '#required' => TRUE
1125    );
1126  
1127    $form['ckeditor_advanced_settings']['ckeditor_local_path'] = array(
1128      '#type' => 'textfield',
1129      '#title' => t('Local path to CKEditor'),
1130      '#default_value' =>  isset($profile->settings['ckeditor_local_path'])?$profile->settings['ckeditor_local_path']:'',
1131      '#size' => 40,
1132      '#maxlength' => 128,
1133      '#description' => 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.php". If empty, CKEditor module will try to find the right path.<br />Current path: !path', array('!path' => ckeditor_path(TRUE))),
1134    );
1135  
1136    $form['ckeditor_advanced_settings']['show_fieldnamehint'] = array(
1137      '#type' => 'radios',
1138      '#title' => t('Show field name hint below each rich text editor'),
1139      '#default_value' => !empty($profile->settings['show_fieldnamehint']) ? $profile->settings['show_fieldnamehint'] : 't',
1140      '#options' => array(
1141        't' => t('Yes'),
1142        'f' => t('No')
1143      ),
1144      '#description' => t('This only applies for users with "administer ckeditor" permissions.'),
1145    );
1146  
1147    if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE) {
1148      $current_private_dir = !empty($profile->settings['private_dir']) ? $profile->settings['private_dir'] : '';
1149      $form['ckeditor_advanced_settings']['private_dir'] = array(
1150        '#type' => 'textfield',
1151        '#title' => t('Location of files uploaded with CKEditor in the private folder'),
1152        '#default_value' => !empty($profile->settings['private_dir']) ? $profile->settings['private_dir'] : '',
1153        '#size' => 40,
1154        '#maxlength' => 255,
1155        '#description' => t('The path relative to the location of the private directory where CKEditor should store uploaded files.') . '<br />' . t('<strong>Warning:</strong> CKEditor 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 />' . t('System path to the private folder is: !system_path.', array('!system_path' => realpath(file_directory_path()) . DIRECTORY_SEPARATOR)) . '<br />' . t('Available wildcard characters:') . '<br/><strong>%u</strong> - ' . t('User ID') . '<br /><strong>%n</strong> - ' . t('Username') . '<br />' . t('Current path: !path', array('!path' => $current_private_dir . ' (' . file_create_path($current_private_dir) . ')')),
1156      );
1157    }
1158    if (function_exists('linktocontent_node_menu') && function_exists('pathfilter_filter')) {
1159      $form['ckeditor_advanced_settings']['linktoc'] = array(
1160      '#type' => 'select',
1161      '#options' => array('p' => t('Link to paths only'), 'n' => t('Link using internal: links'), 'pn' => t('Allow user to select between paths and internal links')),
1162      '#title' => t('Path Filter & Link To Content integration'),
1163      '#default_value' => empty($profile->settings['linktoc']) ? 'p' : $profile->settings['linktoc'],
1164      '#description' => t('With !plink extension it is possible to use internal: links. By default !link extension is linking to nodes using paths.', array('!plink' => l(t('Path Filter'), 'http://drupal.org/project/pathfilter'), '!link' => l(t('Link To Content'), 'http://drupal.org/project/linktocontent'))),
1165      );
1166    }
1167  
1168    $form['submit'] = array(
1169      '#type' => 'submit',
1170      '#value' => $btn
1171    );
1172  
1173    return $form;
1174  }
1175  
1176  function ckeditor_admin_global_profile_form_validate($form, &$form_state) {
1177    $edit =& $form_state['values'];
1178  
1179    //include mode and all other fields are empty, invalid
1180    if ($edit['excl_mode'] == 1 && empty($edit['excl'])) {
1181      form_set_error('excl_mode', t('Include mode selected, but no paths given. Enter at least one path where CKEditor should appear.'));
1182    }
1183    else {
1184      ckeditor_admin_profile_validate_fieldpaths('excl', $edit['excl']);
1185    }
1186  
1187    ckeditor_admin_profile_validate_fieldpaths('simple_incl', $edit['simple_incl']);
1188  }
1189  
1190  function ckeditor_admin_global_profile_form_submit($form, &$form_state) {
1191    module_load_include('inc', 'ckeditor', 'includes/ckeditor.lib');
1192    $edit =& $form_state['values'];
1193    $edit['name'] = 'CKEditor Global Profile';
1194  
1195    if (isset($edit['rank'])) {
1196      $edit['rank'] = explode('>', str_replace(' ', '', $edit['rank']));
1197    }
1198  
1199    if (isset($edit['_profile'])) {
1200      db_query("DELETE FROM {ckeditor_settings} WHERE name = '%s'", $edit['_profile']->name);
1201      db_query("DELETE FROM {ckeditor_role} WHERE name = '%s'", $edit['_profile']->name);
1202    }
1203  
1204    //strip whitespaces
1205    if (empty($edit['ckeditor_local_path'])) {
1206      $edit['ckeditor_local_path'] = '';
1207    }
1208    else {
1209      $edit['ckeditor_local_path'] = trim($edit['ckeditor_local_path']);
1210    }
1211  
1212    //strip slash from the end
1213    if (empty($edit['ckeditor_path'])) {
1214      $edit['ckeditor_path'] = '';
1215    }
1216    $edit['ckeditor_path'] = trim(rtrim($edit['ckeditor_path'], "/"));
1217    if ($edit['ckeditor_path'] && 0 !== strpos($edit['ckeditor_path'], "/") && 0 !== strpos($edit['ckeditor_path'], "%")) {
1218      //ensure that slash is at the beginning
1219      $edit['ckeditor_path'] = "/". $edit['ckeditor_path'];
1220    }
1221    //no slash at the end
1222    $edit['ckeditor_local_path'] = trim(rtrim($edit['ckeditor_local_path'], "/"));
1223  
1224    $settings = ckeditor_admin_values_to_settings($edit);
1225    db_query("INSERT INTO {ckeditor_settings} (name, settings) VALUES ('%s', '%s')", $edit['name'], $settings);
1226    ckeditor_rebuild_selectors($edit['name']);
1227  
1228    drupal_set_message(t('CKEditor global profile has been saved.'));
1229    $form_state['redirect'] = 'admin/settings/ckeditor';
1230  }
1231  
1232  /**
1233   * Converts an array of form values to a serialized array that does not
1234   * contain Drupal Form API values
1235   */
1236  function ckeditor_admin_values_to_settings($values) {
1237    unset($values['name'], $values['rids'], $values['_profile'], $values['op'], $values['submit'], $values['form_build_id'], $values['form_token'], $values['form_id']);
1238    return serialize($values);
1239  }
1240  
1241  function ckeditor_admin_profile_validate_fieldpaths($fieldname, $paths) {
1242    $myerrors = array();
1243  
1244    $rules = preg_split('/[\s,]+/', $paths);
1245  
1246    foreach ($rules as $rule) {
1247      $rule = trim($rule);
1248      if (!empty($rule) && strpos($rule, '.') === FALSE && strpos($rule, '/') === FALSE && strpos($rule, '-') === FALSE) {
1249        $myerrors[] = t('Rule %rule is ambiguous: please append .* if %rule is a path or prepend *. if %rule is a field', array('%rule' => $rule));
1250      }
1251    }
1252  
1253    if (!empty($myerrors)) {
1254      form_set_error($fieldname, implode('<br/>', $myerrors));
1255    }
1256  }
1257  
1258  function ckeditor_admin_profile_delete_form($form_state, $profile) {
1259    $form = array();
1260  
1261    $form['_profile'] = array(
1262      '#type' => 'value',
1263      '#value' => $profile,
1264    );
1265  
1266    $form['question'] = array(
1267      '#type' => 'item',
1268      '#value' => t('Are you sure that you want to delete the CKEditor profile %profile?', array('%profile' => $profile->name)),
1269    );
1270  
1271    $form['delete'] = array(
1272      '#type' => 'submit',
1273      '#id' => 'delete',
1274      '#value' => t('Delete'),
1275    );
1276  
1277    $form['back'] = array(
1278      '#type' => 'submit',
1279      '#id' => 'back',
1280      '#value' => t('Cancel'),
1281    );
1282  
1283    return $form;
1284  }
1285  
1286  function ckeditor_admin_profile_delete_form_submit($form, &$form_state) {
1287    $v =& $form_state['values'];
1288  
1289    if ($form_state['clicked_button']['#id'] == 'delete') {
1290      ckeditor_profile_delete($v['_profile']->name);
1291      drupal_set_message(t('Deleted CKEditor profile.'));
1292    }
1293  
1294    $form_state['redirect'] = 'admin/settings/ckeditor';
1295  }
1296  
1297  /**
1298   * Rebuilds the regular expression that is used to match the inclusion/exclusion rules
1299   * and the simplified toolbar rules
1300   *
1301   * @param string $name Name of the profile to process. If omitted, all profiles are rebuilt
1302   */
1303  function ckeditor_rebuild_selectors($name = NULL) {
1304    if ($name == NULL) {
1305      $result = db_query("SELECT * FROM {ckeditor_settings}");
1306    }
1307    else {
1308      $result = db_query("SELECT * FROM {ckeditor_settings} WHERE name = '%s'", $name);
1309    }
1310  
1311    while (($data = db_fetch_object($result))) {
1312      if ($data->settings) {
1313        $settings = unserialize($data->settings);
1314        // [#654626]
1315        if (!isset($settings['excl'])) {
1316          $settings['excl'] = '';
1317        }
1318        if (!isset($settings['simple_incl'])) {
1319          $settings['simple_incl'] = '';
1320        }
1321  
1322        foreach (array('excl', 'simple_incl') as $var) {
1323          $settings[$var .'_regex'] = '';
1324          $rules = preg_split('/[\s,]+/', $settings[$var]);
1325          $regex = array();
1326  
1327          if (!empty($rules)) {
1328            foreach ($rules as $rule) {
1329              if (!empty($rule)) {
1330                $rule = ckeditor_parse_rule($rule);
1331                $regex[] = '(?:'. ckeditor_rule_to_regex($rule) .')';
1332              }
1333            }
1334  
1335            if (!empty($regex)) {
1336              $settings[$var .'_regex'] = '#'. implode('|', $regex) .'#';
1337            }
1338          }
1339        }
1340  
1341        db_query("UPDATE {ckeditor_settings} SET settings='%s' WHERE name='%s'", serialize($settings), $data->name);
1342      }
1343    }
1344  }
1345  
1346  function ckeditor_rule_create($nodetype = '*', $path = '*', $fieldname = '*') {
1347    $rule = new stdClass();
1348    $rule->nodetype = $nodetype;
1349    $rule->path = $path;
1350    $rule->field = $fieldname;
1351  
1352    return $rule;
1353  }
1354  
1355  function ckeditor_parse_rule($rule) {
1356    $ruleobj = new stdClass();
1357  
1358    $atpos = strpos($rule, '@');
1359    if ($atpos !== FALSE) {
1360      $ruleobj->nodetype = substr($rule, 0, $atpos);
1361      $rule = substr($rule, $atpos + 1);
1362    }
1363    else {
1364      $ruleobj->nodetype = '*';
1365    }
1366  
1367    $dotpos = strpos($rule, '.');
1368    if ($dotpos === FALSE) {
1369      if (strpos($rule, '/') === FALSE && strpos($rule, '-') !== FALSE) {
1370        // assume it's a field
1371        $ruleobj->path = '*';
1372        $ruleobj->field = $rule;
1373      }
1374      elseif (strpos($rule, '/') !== FALSE) {
1375        // assume it's a path
1376        $ruleobj->path = $rule;
1377        $ruleobj->field = '*';
1378      }
1379      else {
1380        return NULL;
1381      }
1382    }
1383    else {
1384      $ruleobj->path = substr($rule, 0, $dotpos);
1385      $ruleobj->field = str_replace('\.', '.', substr($rule, $dotpos + 1));
1386    }
1387  
1388    return $ruleobj;
1389  }
1390  
1391  function ckeditor_rule_to_regex($rule) {
1392    static $replace = array('\*' => '.*', '\?' => '.');
1393  
1394    $field = str_replace('.', '\.', $rule->field);
1395    $regex = '^'. preg_quote($rule->nodetype, '#') .'@'. preg_quote($rule->path, '#') .'\.'. preg_quote($field, '#') .'$';
1396    $regex = strtr($regex, $replace);
1397  
1398    return $regex;
1399  }
1400  
1401  function ckeditor_rule_to_string($rule) {
1402    $field = str_replace('.', '\.', $rule->field);
1403    $rulestr = '';
1404    if ($rule->nodetype != '*') {
1405      $rulestr .= $rule->nodetype .'@';
1406    }
1407    return $rulestr . $rule->path .'.'. $field;
1408  }
1409  
1410  /**
1411   * Remove a profile from the database.
1412   */
1413  function ckeditor_profile_delete($name) {
1414    db_query("DELETE FROM {ckeditor_settings} WHERE name = '%s'", $name);
1415    db_query("DELETE FROM {ckeditor_role} WHERE name = '%s'", $name);
1416  }
1417  
1418  function _ckeditor_load_methods() {
1419    module_load_include('module', 'ckeditor');
1420    $result = array('ckeditor.js' => 'ckeditor.js');
1421    if (file_exists(ckeditor_path(TRUE) . '/ckeditor_basic.js')) {
1422      $result['ckeditor_basic.js'] = 'ckeditor_basic.js';
1423    }
1424    if (file_exists(ckeditor_path(TRUE) . '/ckeditor_source.js')) {
1425      $result['ckeditor_source.js'] =  'ckeditor_source.js (' . t('for developers only') . ')';
1426    }
1427    return $result;
1428  }


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7