home | career | drupal | java | mac | mysql | perl | php | scala | uml | unix

Drupal example source code file (fckeditor.module)

This example Drupal source code file (fckeditor.module) is included in the DevDaily.com "Drupal Source Code Warehouse" project. The intent of this project is to help you "Learn Drupal by Example".

PHP - Drupal tags/keywords

array, directory, element, empty, fckeditor, file, foreach, function, if, isset, js_id, php, return, string

The fckeditor.module Drupal example source code

<?php
// $Id: fckeditor.module,v 1.20.2.34.2.91 2010/03/10 07:43:32 jorrit Exp $
/**
 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
 * Copyright (C) 2003-2008 Frederico Caldeira Knabben
 *
 * == BEGIN LICENSE ==
 *
 * Licensed under the terms of any of the following licenses at your
 * choice:
 *
 *  - GNU General Public License Version 2 or later (the "GPL")
 *    http://www.gnu.org/licenses/gpl.html
 *
 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 *    http://www.gnu.org/licenses/lgpl.html
 *
 *  - Mozilla Public License Version 1.1 or later (the "MPL")
 *    http://www.mozilla.org/MPL/MPL-1.1.html
 *
 * == END LICENSE ==
 *
 * @file
 * FCKeditor Module for Drupal 6.x
 *
 * This module allows Drupal to replace textarea fields with FCKeditor.
 *
 * This HTML text editor brings to the web many of the powerful functionalities
 * of known desktop editors like Word. It's really  lightweight and doesn't
 * require any kind of installation on the client computer.
 */

/**
 * The name of simplified toolbar which should be forced
 * Be sure that this toolbar is defined in fckeditor.config.js or fckconfig.js
 */
define('FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME', 'DrupalBasic') ;

global $_fckeditor_configuration;
global $_fckeditor_js_ids;

$_fckeditor_configuration = array();
$_fckeditor_js_ids = array();

/**
 * Implementation of hook_help().
 *
 * This function delegates execution to fckeditor_help_delegate() in fckeditor.help.inc to
 * lower the amount of code in fckeditor.module
 */
function fckeditor_help($path, $arg) {
  module_load_include('help.inc', 'fckeditor');
  return module_invoke('fckeditor', 'help_delegate', $path, $arg);
}

/**
 * Implementation of hook_user().
 *
 * This function delegates execution to fckeditor_user_delegate() in fckeditor.user.inc to
 * lower the amount of code in fckeditor.module
 */
function fckeditor_user($type, $edit, &$user, $category = NULL) {
  if (($type == 'form' && $category == 'account' && user_access('access fckeditor')) || $type == 'validate') {
    module_load_include('user.inc', 'fckeditor');
    return fckeditor_user_delegate($type, $edit, $user, $category);
  }
  return NULL;
}

/*
 *  Run if there is old menu information in database
 */
function fckeditor_admin($arg = NULL) {
  drupal_set_message(t('The FCKeditor module is not installed correctly. You should run the !updatephplink immediately.', array('!updatephplink' => l(t('database update script'), 'update.php'))), 'error');
  return FALSE;
}

/**
 * Implementation of hook_perm().
 * Administer -> User management -> Permissions
 */
function fckeditor_perm() {
  return array('administer fckeditor', 'access fckeditor', 'allow fckeditor file uploads');
}

/**
 * Implementation of hook_elements().
 * Replace textarea with FCKeditor using callback function (fckeditor_process_textarea)
 */
function fckeditor_elements() {
  $type = array();
  $type['textfield'] = array(
    '#process' => array(
      'fckeditor_process_input'
    ),
  );
  if (user_access('access fckeditor')) {
    // only roles with permission get the fckeditor
    if (fckeditor_is_compatible_client()) {
      // it would be useless to dig deeper if we're not able or allowed to
      $type['textarea'] = array('#process' => array('fckeditor_process_textarea'));
      $type['form'] = array('#after_build' => array('fckeditor_process_form'));
    }
  }
  return $type;
}

/**
 * AJAX callback - XSS filter
 */
function fckeditor_filter_xss() {
  $GLOBALS['devel_shutdown'] = FALSE;

  if (!isset($_POST['text']) || !is_string($_POST['text']) || !is_array($_POST['filters'])) {
    exit;
  }

  $text = $_POST['text'];
  $text = strtr($text, array('<!--' => '__COMMENT__START__', '-->' => '__COMMENT__END__'));

  foreach ($_POST['filters'] as $module_delta) {
    $module = strtok($module_delta, "/");
    $delta = strtok("/");
    $format = strtok("/");

    if (!module_hook($module, 'filter')) {
      continue;
    }

    //built-in filter module, a special case where we would like to strip XSS and nothing more
    if ($module == 'filter' && $delta == 0) {
      preg_match_all("|</?([a-z][a-z0-9]*)(?:\b[^>]*)>|i", $text, $matches);
      if ($matches[1]) {
        $tags = array_unique($matches[1]);
        $text = filter_xss($text, $tags);
      }
    }
    else {
      $text = module_invoke($module, 'filter', 'process', $delta, $format, $text);
    }
  }

  $text = strtr($text, array('__COMMENT__START__' => '<!--', '__COMMENT__END__' => '-->'));

  echo $text;
  exit;
}

function fckeditor_process_form(&$form) {
  global $_fckeditor_configuration, $_fckeditor_js_ids;
  static $processed_textareas = array();
  static $found_textareas = array();

  //Skip if:
  // - we're not editing an element
  // - fckeditor is not enabled (configuration is empty)
  if (arg(1) == "add" || arg(1) == "reply" || !count($_fckeditor_configuration)) {
    return $form;
  }

  $fckeditor_filters = array();

  // Iterate over element children; resetting array keys to access last index.
  if (($children = array_values(element_children($form)))) {
    foreach ($children as $index => $item) {
      $element = &$form[$item];

      if (isset($element['#id']) && in_array($element['#id'], array_keys($_fckeditor_js_ids))) {
        $found_textareas[$element['#id']] = &$element;
      }

      // filter_form() always uses the key 'format'. We need a type-agnostic
      // match to prevent false positives. Also, there must have been at least
      // one element on this level.
      if ($item === 'format' && $index > 0) {

        // Make sure we either match a input format selector or input format
        // guidelines (displayed if user has access to one input format only).
        if ((isset($element['#type']) && $element['#type'] == 'fieldset') || isset($element['format']['guidelines'])) {
          // The element before this element is the target form field.
          $field = &$form[$children[$index - 1]];
          $textarea_id = $field['#id'];
          $js_id = $_fckeditor_js_ids[$textarea_id];

          array_push($processed_textareas, $js_id);

          //search for checkxss1/2 class
          if (empty($field['#attributes']['class']) || strpos($field['#attributes']['class'], "checkxss") === FALSE) {
            continue;
          }

          // Determine the available input formats. The last child element is a
          // link to "More information about formatting options". When only one
          // input format is displayed, we also have to remove formatting
          // guidelines, stored in the child 'format'.
          $formats = element_children($element);

          foreach ($formats as $format_id) {
            $format = !empty($element[$format_id]['#default_value']) ? $element[$format_id]['#default_value'] : $element[$format_id]['#value'];
            break;
          }

          $enabled = filter_list_format($format);
          $fckeditor_filters = array();

          //loop through all enabled filters
          foreach ($enabled as $id => $filter) {
            //but use only that one selected in FCKeditor profile
            if (in_array($id, array_keys($_fckeditor_configuration[$textarea_id]['filters'])) && $_fckeditor_configuration[$textarea_id]['filters'][$id]) {
              if (!isset($fckeditor_filters[$js_id])) {
                $fckeditor_filters[$js_id] = array();
              }
              $fckeditor_filters[$js_id][] = $id ."/". $format;
            }
          }

          //No filters assigned, remove xss class
          if (empty($fckeditor_filters[$js_id])) {
            $field['#attributes']['class'] = preg_replace("/checkxss(1|2)/", "", $field['#attributes']['class']);
          }
          else {
            $field['#attributes']['class'] = strtr($field['#attributes']['class'], array("checkxss1" => "filterxss1", "checkxss2" => "filterxss2"));
          }

          array_pop($formats);
          unset($formats['format']);
        }
        // If this element is 'format', do not recurse further.
        continue;
      }
      // Recurse into children.
      fckeditor_process_form($element);
    }
  }

  //We're in a form
  if (isset($form['#action'])) {
    //some textareas associated with FCKeditor has not been processed
    if (count($processed_textareas) < count($_fckeditor_js_ids)) {
      //loop through all found textfields
      foreach (array_keys($found_textareas) as $id) {
        $element = &$found_textareas[$id];
        //if not processed yet (checkxss class is before final processing)
        if (strpos($element['#attributes']['class'], "checkxss") !== FALSE && !in_array($_fckeditor_js_ids[$element['#id']], $processed_textareas) && !empty($_fckeditor_configuration[$id]['filters']) && array_sum($_fckeditor_configuration[$id]['filters'])) {
          //assign default Filtered HTML to be safe on fields that do not have input format assigned, but only if at least one security filter is enabled in Security settings
          $js_id = $_fckeditor_js_ids[$element['#id']];
          $fckeditor_filters[$js_id][] = "filter/0/1";
          $element['#attributes']['class'] = strtr($element['#attributes']['class'], array("checkxss1" => "filterxss1", "checkxss2" => "filterxss2"));
        }
      }
    }
  }

  if (!empty($fckeditor_filters)) {
    drupal_add_js(array('fckeditor_filters' => $fckeditor_filters), 'setting');
  }

  return $form;
}

/**
 * Allow more than 255 chars in Allowed HTML tags textfield
 */
function fckeditor_process_input($element) {
  if ($element['#id']=='edit-allowed-html-1') {
    $element['#maxlength'] = max($element['#maxlength'], 1024);
  }
  return $element;
}

/**
 * Implementation of hook_menu().
 */
function fckeditor_menu() {
  $items = array();

  $items['fckeditor/xss'] = array(
    'title' => 'XSS Filter',
    'description' => 'XSS Filter.',
    'page callback' => 'fckeditor_filter_xss',
    'access arguments' => array('access fckeditor'),
    'type' => MENU_CALLBACK,
  );

  $items['admin/settings/fckeditor'] = array(
    'title' => 'FCKeditor',
    'description' => 'Configure the rich text editor.',
    'page callback' => 'fckeditor_admin_main',
    'file' => 'fckeditor.admin.inc',
    'access arguments' => array('administer fckeditor'),
    'type' => MENU_NORMAL_ITEM,
  );

  $items['admin/settings/fckeditor/add'] = array(
    'title' => 'Add new FCKeditor profile',
    'description' => 'Configure the rich text editor.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('fckeditor_admin_profile_form'),
    'file' => 'fckeditor.admin.inc',
    'access arguments' => array('administer fckeditor'),
    'type' => MENU_CALLBACK,
  );

  $items['admin/settings/fckeditor/clone/%fckeditor_profile'] = array(
    'title' => 'Clone FCKeditor profile',
    'description' => 'Configure the rich text editor.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('fckeditor_admin_profile_clone_form', 4),
    'file' => 'fckeditor.admin.inc',
    'access arguments' => array('administer fckeditor'),
    'type' => MENU_CALLBACK,
  );

  $items['admin/settings/fckeditor/edit/%fckeditor_profile'] = array(
    'title' => 'Edit FCKeditor profile',
    'description' => 'Configure the rich text editor.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('fckeditor_admin_profile_form', 4),
    'file' => 'fckeditor.admin.inc',
    'access arguments' => array('administer fckeditor'),
    'type' => MENU_CALLBACK,
  );

  $items['admin/settings/fckeditor/delete/%fckeditor_profile'] = array(
    'title' => 'Delete FCKeditor profile',
    'description' => 'Configure the rich text editor.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('fckeditor_admin_profile_delete_form', 4),
    'file' => 'fckeditor.admin.inc',
    'access arguments' => array('administer fckeditor'),
    'type' => MENU_CALLBACK,
  );

  $items['admin/settings/fckeditor/addg'] = array(
    'title' => 'Add FCKeditor Global profile',
    'description' => 'Configure the rich text editor.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('fckeditor_admin_global_profile_form', 'add'),
    'file' => 'fckeditor.admin.inc',
    'access arguments' => array('administer fckeditor'),
    'type' => MENU_CALLBACK,
  );

  $items['admin/settings/fckeditor/editg'] = array(
    'title' => 'Edit FCKeditor Global profile',
    'description' => 'Configure the rich text editor.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('fckeditor_admin_global_profile_form', 'edit'),
    'file' => 'fckeditor.admin.inc',
    'access arguments' => array('administer fckeditor'),
    'type' => MENU_CALLBACK,
  );

  // img_assist integration
  $items['img_assist/load/fckeditor'] = array(
    'title' => 'Image assist',
    'page callback' => 'fckeditor_wrapper_img_assist_loader',
    'file' => 'fckeditor.user.inc',
    'access arguments' => array('access img_assist'),
    'type' => MENU_CALLBACK,
  );

  return $items;
}

/**
 * Implementation of hook_init().
 */
function fckeditor_init() {
  drupal_add_css(drupal_get_path('module', 'fckeditor') .'/fckeditor.css');
}

/**
 * Implementation of hook_file_download().
 * Support for private downloads.
 * FCKeditor does not implement any kind of potection on private files.
 */
function fckeditor_file_download($file) {
  if (($path = file_create_path($file))) {
    $result = db_query("SELECT f.* FROM {files} f WHERE filepath = '%s'", $path);
    if (db_fetch_object($result)) {
        return NULL;
    }

    //No info in DB? Probably a file uploaded with FCKeditor
    $global_profile = fckeditor_profile_load("FCKeditor Global Profile");

    //Assume that files inside of fckeditor directory belong to the FCKeditor. If private directory is set, let the decision about protection to the user.
    $private_dir = isset($global_profile->settings['private_dir']) ? trim($global_profile->settings['private_dir'], '\/') : '';
    $private_dir = preg_quote($private_dir, '#');
    $private_dir = strtr($private_dir, array('%u' => '(\d+)', '%n' => '([\x80-\xF7 \w@.-]+)')); // regex for %n taken from user_validate_name() in user.module
    $private_dir = trim($private_dir, '\/');

    $regex = '#^'. preg_quote(file_directory_path() .'/', '#') . $private_dir .'#';

    //If path to the file points to the FCKeditor private directory, allow downloading
    if (preg_match($regex, $path)) {
      $ctype = ($info = @getimagesize($path)) ? $info['mime'] : (function_exists('mime_content_type') ? mime_content_type($path) : 'application/x-download');
      return array('Content-Type: '. $ctype);
    }
  }
}

/**
 * Load all profiles. Just load one profile if $name is passed in.
 */
function fckeditor_profile_load($name = '', $clear = FALSE) {
  static $profiles = array();

  if (empty($profiles) || $clear === TRUE) {
    $result = db_query("SELECT * FROM {fckeditor_settings}");
    while (($data = db_fetch_object($result))) {
      $data->settings = unserialize($data->settings);
      $data->rids = array();

      $profiles[$data->name] = $data;
    }

    $roles = user_roles();
    $result = db_query("SELECT name, rid FROM {fckeditor_role}");
    while (($data = db_fetch_object($result))) {
      $profiles[$data->name]->rids[$data->rid] = $roles[$data->rid];
    }
  }

  return ($name ? (isset($profiles[urldecode($name)]) ? $profiles[urldecode($name)] : FALSE) : $profiles);
}

/**
 * @param int $excl_mode 1/include, exclude otherwise
 * @param string $excl_regex paths (drupal paths with ids attached)
 * @param string $element_id current ID
 * @param string $get_q current path
 *
 * @return boolean
 *    returns true if FCKeditor is enabled
 */
function fckeditor_is_enabled($excl_mode, $excl_regex, $element_id, $get_q) {
  $front = variable_get('site_frontpage', 'node');
  $excl_regex = str_replace('<front>', $front, $excl_regex);
  $nodetype = fckeditor_get_nodetype($get_q);
  $element_id = str_replace('.', '\.', $element_id);

  $match = !empty($excl_regex) && preg_match($excl_regex, $nodetype .'@'. $get_q .'.'. $element_id);

  return ($excl_mode == '0' xor $match);
}

/**
 * This function create the HTML objects required for the FCKeditor
 *
 * @param $element
 *   A fully populated form elment to add the editor to
 * @return
 *   The same $element with extra FCKeditor markup and initialization
 */
function fckeditor_process_textarea($element) {
  static $is_running = FALSE;
  static $num = 1;
  global $user, $language, $_fckeditor_configuration, $_fckeditor_js_ids;
  $enabled = TRUE;

  //hack for module developers that want to disable FCKeditor on their textareas
  if (key_exists('#wysiwyg', $element) && !$element['#wysiwyg']) {
    return $element;
  }

  if (isset($element['#access']) && !$element['#access']) {
    return $element;
  }

  //skip this one, surely nobody wants WYSIWYG here
  switch ($element['#id']) {
    case 'edit-log':
      return $element;
      break;
  }

  if (isset($element['#attributes']['disabled']) && $element['#attributes']['disabled'] == 'disabled') {
    return $element;
  }


  $global_profile = fckeditor_profile_load('FCKeditor Global Profile');
  if ($global_profile) {
    $global_conf = $global_profile->settings;
    if ($global_conf) {
      $enabled = fckeditor_is_enabled(empty($global_conf['excl_mode']) ? '0' : $global_conf['excl_mode'], empty($global_conf['excl_regex']) ? '' : $global_conf['excl_regex'], $element['#id'], $_GET['q']);
    }
  }

  if ($enabled) {
    $profile = fckeditor_user_get_profile($user, $element['#id']);
    if ($profile) {
      $conf = array();
      $conf = $profile->settings;

      if ($conf['allow_user_conf']=='t') {
        foreach (array('default', 'show_toggle', 'popup', 'skin', 'toolbar', 'expand', 'width', 'lang', 'auto_lang') as $setting) {
          $conf[$setting] = fckeditor_user_get_setting($user, $profile, $setting);
        }
      }
      if ($conf['popup'] == 't' && $conf['show_toggle'] == 't') {
        $conf['show_toggle'] = 'f';
      }
    }
    else {
      $enabled = FALSE;
    }
  }

  //old profile info, assume Filtered HTML is enabled
  if (!isset($conf['ss'])) {
    $conf['ss'] = 2;
    $conf['filters']['filter/0'] = 1;
  }
  if (!isset($conf['filters'])) {
    $conf['filters'] = array();
  }

  $themepath = fckeditor_path_to_theme() .'/';
  $host = base_path();

  if (!isset($element['#suffix'])) {
    $element['#suffix'] = '';
  }

  // only replace textarea when it has enough rows and it is enabled
  if ($enabled && (($element['#rows'] > $conf['min_rows']) || ($conf['min_rows'] <= 1 && empty($element['#rows'])))) {
    $textarea_id = $element['#id'];

    if (!isset($element['#attributes'])) {
      $element['#attributes'] = array();
    }
    if (!isset($element['#attributes']['class'])) {
      $element['#attributes']['class'] = 'fckeditor';
    }
    else {
      $element['#attributes']['class'] .= ' fckeditor';
    }

    $js_id = 'oFCK_'. $num++;
    $_fckeditor_js_ids[$element['#id']] = $js_id;
    $fckeditor_on = ($conf['default']=='t') ? 1 : 0 ;

    $xss_check = 0;
    //it's not a problem when adding new content/comment
    if (arg(1) != "add" && arg(1) != "reply") {
      $_fckeditor_configuration[$element['#id']] = $conf;

      //let FCKeditor know when perform XSS checks auto/manual
      if ($conf['ss'] == 1) {
        $xss_class = 'checkxss1';
      }
      else {
        $xss_class = 'checkxss2';
      }

      $element['#attributes']['class'] .= ' '. $xss_class;
      $xss_check = 1;
    }

    //settings are saved as strings, not booleans
    if ($conf['show_toggle'] == 't') {
      $content = '';
      if (isset($element['#post']['teaser_js'])) {
        $content .= $element['#post']['teaser_js'] .'<!--break-->';
      }
      $content .= $element['#value'];
      $wysiwyg_link = '';
      $wysiwyg_link .= "<a href=\"javascript:Toggle('{$textarea_id}','". str_replace("'", "\\'", t('Switch to plain text editor')) ."','". str_replace("'", "\\'", t('Switch to rich text editor')) ."',". $xss_check .");\" id=\"switch_{$textarea_id}\" ". ($fckeditor_on?"style=\"display:none\"":"") .">";
      $wysiwyg_link .= $fckeditor_on ? t('Switch to plain text editor') : t('Switch to rich text editor');
      $wysiwyg_link .= '</a>';

      // Make sure to append to #suffix so it isn't completely overwritten
      $element['#suffix'] .= $wysiwyg_link;
    }

    //convert contents to HTML if necessary
    if ($conf['autofixplaintext'] == 't') {
      module_load_include('lib.inc', 'fckeditor');
      if (fckeditor_is_plaintext($element['#value'])) {
        $element['#value'] = _filter_autop($element['#value']);
      }
    }

    // setting some variables
    $module_drupal_path = drupal_get_path('module', 'fckeditor');
    $module_full_path   = $host . $module_drupal_path;
    $editor_path        = fckeditor_path(FALSE);
    $editor_local_path  = fckeditor_path(TRUE);
    // get the default drupal files path
    $files_path         = $host . file_directory_path();
    // module_drupal_path:
    //  'modules/fckeditor' (length=17)
    // module_full_path:
    //  '/drupal5/modules/fckeditor' (length=26)
    // files_path:
    //  '/drupal5/files' (length=14)
    // configured in settings
    $width = $conf['width'];

    // sensible default for small toolbars
    $height = intval($element['#rows']) * 14 + 140;

    if (!$is_running) {
      drupal_add_js($module_drupal_path .'/fckeditor.utils.js');
      /* In D6 drupal_add_js() can't add external JS, in D7 use drupal_add_js(...,'external') */
      drupal_set_html_head('<script type="text/javascript" src="'. $editor_path .'/fckeditor.js?I"></script>');
      $is_running = TRUE;
    }

    $toolbar = $conf['toolbar'];
    //$height += 100; // for larger toolbars

    $force_simple_toolbar = fckeditor_is_enabled('1', empty($conf['simple_incl_regex']) ? '' : $conf['simple_incl_regex'], $element['#id'], $_GET['q']);
    if (!$force_simple_toolbar) {
      $force_simple_toolbar = fckeditor_is_enabled('1', empty($global_conf['simple_incl_regex']) ? '' : $global_conf['simple_incl_regex'], $element['#id'], $_GET['q']);
    }
    if ($force_simple_toolbar) {
      $toolbar = FCKEDITOR_FORCE_SIMPLE_TOOLBAR_NAME;
    }

    if (!empty($conf['theme_config_js']) && $conf['theme_config_js'] == 't' && file_exists($themepath .'fckeditor.config.js')) {
      $fckeditor_config_path = $host . $themepath .'fckeditor.config.js?'. @filemtime($themepath .'fckeditor.config.js');
    }
    else {
      $fckeditor_config_path = $module_full_path ."/fckeditor.config.js?". @filemtime($module_drupal_path ."/fckeditor.config.js");
    }

    $js = $js_id ." = new FCKeditor( '". $textarea_id ."' );
". $js_id .".defaultState = ". (($fckeditor_on && $conf['popup'] == 'f') ? 1 : 0) .";
". $js_id .".BasePath = '". $editor_path ."/';
". $js_id .".DrupalId = '". $js_id ."';
". $js_id .".Config['PluginsPath'] = '". $module_full_path ."/plugins/';
". $js_id .".Config['CustomConfigurationsPath'] = \"". $fckeditor_config_path ."\";
". $js_id .".Config['TextareaID'] = \"". $element['#id'] ."\";
". $js_id .".Config['BodyId'] = \"". $element['#id'] ."\";";

    //if ($conf['appearance_conf'] == 'f') {
    $js .= "\n". $js_id .".ToolbarSet = \"". $toolbar ."\";
". $js_id .".Config['SkinPath'] = ". $js_id .".BasePath + \"editor/skins/". $conf['skin'] ."/\";
". $js_id .".Config['DefaultLanguage'] = \"". $conf['lang'] ."\";
". $js_id .".Config['AutoDetectLanguage'] = ". ($conf['auto_lang']=="t"?"true":"false") .";
". $js_id .".Height = \"". $height ."\";
". $js_id .".Config['ToolbarStartExpanded'] = ". ($conf['expand']=="t"?"true":"false") .";
". $js_id .".Width = \"". $width ."\";\n";
    //}
    //if ($conf['output_conf'] == 'f') {
    $js .= "\n". $js_id .".Config['EnterMode'] = '". $conf['enter_mode'] ."';
". $js_id .".Config['ShiftEnterMode'] = \"". $conf['shift_enter_mode'] ."\";
". $js_id .".Config['FontFormats'] = \"". str_replace(",", ";", $conf['font_format']) ."\";
". $js_id .".Config['FormatSource'] = ". ($conf['format_source']=="t"?"true":"false") .";
". $js_id .".Config['FormatOutput'] = ". ($conf['format_output']=="t"?"true":"false") .";\n";
    //}

    if (defined('LANGUAGE_RTL') && $language->direction == LANGUAGE_RTL) {
      $js .= $js_id .".Config['ContentLangDirection'] = 'rtl';\n";
    }

    // add code for filebrowser for users that have access
    if (user_access('allow fckeditor file uploads')==1) {
      $filebrowser = !empty($conf['filebrowser']) ? $conf['filebrowser'] : 'none';
      if ($filebrowser == 'imce' && !module_exists('imce')) {
        $filebrowser = 'none';
      }
      if ($filebrowser == 'ib' && !module_exists('imagebrowser')) {
        $filebrowser = 'none';
      }
      if ($filebrowser == 'webfm' && !module_exists('webfm_popup')) {
        $filebrowser = 'none';
      }
      $quickupload = (!empty($conf['quickupload']) && $conf['quickupload'] == 't');

      // load variables used by both quick upload and filebrowser
      // and assure that the $_SESSION variables are loaded
      if ($quickupload || $filebrowser == 'builtin') {
        if (file_exists($editor_local_path ."/editor/filemanager/connectors/php/connector.php")) {
          $connector_path = $editor_path ."/editor/filemanager/connectors/php/connector.php" ;
        }
        elseif (file_exists($editor_local_path ."/editor/filemanager/upload/php/connector.php")) {
          $connector_path = $editor_path ."/editor/filemanager/upload/php/connector.php";
        }

        if (file_exists($editor_local_path ."/editor/filemanager/connectors/php/upload.php")) {
          $upload_path = $editor_path ."/editor/filemanager/connectors/php/upload.php" ;
        }
        elseif (file_exists($editor_local_path ."/editor/filemanager/upload/php/upload.php")) {
          $upload_path = $editor_path ."/editor/filemanager/upload/php/upload.php";
        }

        if (!empty($profile->settings['UserFilesPath'])) $_SESSION['FCKeditor']['UserFilesPath'] = strtr($profile->settings['UserFilesPath'], array("%f" => file_directory_path(), "%u" => $user->uid, "%b" => $host, "%n" => $user->name));
        if (!empty($profile->settings['UserFilesAbsolutePath'])) $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = strtr($profile->settings['UserFilesAbsolutePath'], array("%f" => file_directory_path(), "%u" => $user->uid, "%b" => base_path(), "%d" => $_SERVER['DOCUMENT_ROOT'], "%n" => $user->name));
        if (variable_get('file_downloads', '') == FILE_DOWNLOADS_PRIVATE) {
          $private_dir = isset($global_profile->settings['private_dir']) ? trim($global_profile->settings['private_dir'], '\/') : '';
          if (!empty($private_dir)) {
            $private_dir = strtr($private_dir, array('%u' => $user->uid, '%n' => $user->name));
            $_SESSION['FCKeditor']['UserFilesPath'] = url('system/files') .'/'. $private_dir .'/';
            $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = realpath(file_directory_path()) . DIRECTORY_SEPARATOR . $private_dir . DIRECTORY_SEPARATOR;
          }
          else {
            $_SESSION['FCKeditor']['UserFilesPath'] = url('system/files') .'/';
            $_SESSION['FCKeditor']['UserFilesAbsolutePath'] = realpath(file_directory_path()) . DIRECTORY_SEPARATOR;
          }
        }
      }

      if ($quickupload) {
        $js .= $js_id .".Config['LinkUpload'] = true;\n";
        $js .= $js_id .".Config['ImageUpload'] = true;\n";
        $js .= $js_id .".Config['FlashUpload'] = true;\n";
        $js .= $js_id .".Config['LinkUploadURL'] = '". $upload_path ."';\n";
        $js .= $js_id .".Config['ImageUploadURL'] = '". $upload_path ."?Type=Image';\n";
        $js .= $js_id .".Config['FlashUploadURL'] = '". $upload_path ."?Type=Flash';\n";
      }
      else {
        $js .= $js_id .".Config['LinkUpload'] = false;\n";
        $js .= $js_id .".Config['ImageUpload'] = false;\n";
        $js .= $js_id .".Config['FlashUpload'] = false;\n";
      }

      switch ($filebrowser) {
        case 'imce':
          $js .= $js_id .".Config['LinkBrowser']= true;\n";
          $js .= $js_id .".Config['ImageBrowser']= true;\n";
          $js .= $js_id .".Config['FlashBrowser']= true;\n";
          $js .= $js_id .".Config['LinkBrowserURL']= '". $host ."index.php?q=imce&app=FCKEditor|url@txtLnkUrl,txtUrl';\n";
          $js .= $js_id .".Config['ImageBrowserURL']= '". $host ."index.php?q=imce&app=FCKEditor|url@txtUrl|width@txtWidth|height@txtHeight';\n";
          $js .= $js_id .".Config['FlashBrowserURL']= '". $host ."index.php?q=imce&app=FCKEditor|url@txtUrl';\n";
          break;

        case 'webfm':
          $js .= $js_id .".Config['LinkBrowser']= true;\n";
          $js .= $js_id .".Config['ImageBrowser']= true;\n";
          $js .= $js_id .".Config['FlashBrowser']= true;\n";
          $js .= $js_id .".Config['ImageDlgHideLink']= true;\n";
          $js .= $js_id .".Config['LinkBrowserURL']= '". $host ."index.php?q=webfm_popup&url=txtUrl';\n";
          $js .= $js_id .".Config['ImageBrowserURL']= '". $host ."index.php?q=webfm_popup&url=txtUrl';\n";
          $js .= $js_id .".Config['FlashBrowserURL']= '". $host ."index.php?q=webfm_popup&url=txtUrl';\n";
          break;

        case 'builtin':
          $js .= $js_id .".Config['LinkBrowser'] = true;\n";
          $js .= $js_id .".Config['ImageBrowser'] = true;\n";
          $js .= $js_id .".Config['FlashBrowser'] = true;\n";
          $js .= $js_id .".Config['LinkBrowserURL'] = '". $editor_path ."/editor/filemanager/browser/default/browser.html?Connector=". $connector_path ."&ServerPath=". $files_path ."';\n";
          $js .= $js_id .".Config['ImageBrowserURL'] = '". $editor_path ."/editor/filemanager/browser/default/browser.html?Type=Image&Connector=". $connector_path ."&ServerPath=". $files_path ."';\n";
          $js .= $js_id .".Config['FlashBrowserURL'] = '". $editor_path ."/editor/filemanager/browser/default/browser.html?Type=Flash&Connector=". $connector_path ."&ServerPath=". $files_path ."';\n";
          break;

        case 'ib':
          $js .= $js_id .".Config['ImageBrowser']= true;\n";
          $js .= $js_id .".Config['LinkBrowser']= true;\n";
          $js .= $js_id .".Config['FlashBrowser']= false;\n";
          $js .= $js_id .".Config['ImageBrowserURL']= '". $host ."index.php?q=imagebrowser/view/browser&app=FCKEditor';\n";
          $js .= $js_id .".Config['LinkBrowserURL']= '". $host ."index.php?q=imagebrowser/view/browser&app=FCKEditor';\n";
          $js .= $js_id .".Config['ImageBrowserWindowWidth']= '680';";
          $js .= $js_id .".Config['ImageBrowserWindowHeight'] = '439';";
          $js .= $js_id .".Config['LinkBrowserWindowWidth']= '680';";
          $js .= $js_id .".Config['LinkBrowserWindowHeight'] = '439';";
          break;

        default:
        case 'none':
          $js .= $js_id .".Config['LinkBrowser'] = false;\n";
          $js .= $js_id .".Config['ImageBrowser'] = false;\n";
          $js .= $js_id .".Config['FlashBrowser'] = false;\n";
          break;
      }
    }
    else {
      $js .= $js_id .".Config['LinkBrowser'] = false;\n";
      $js .= $js_id .".Config['ImageBrowser'] = false;\n";
      $js .= $js_id .".Config['FlashBrowser'] = false;\n";
      $js .= $js_id .".Config['LinkUpload'] = false;\n";
      $js .= $js_id .".Config['ImageUpload'] = false;\n";
      $js .= $js_id .".Config['FlashUpload'] = false;\n";
    }

    if (!empty($conf['js_conf'])) {
      $lines = preg_split("/[\n\r]+/", $conf['js_conf']);
      foreach ($lines as $l) {
        if (strlen($l) > 5) {
          $eqpos = strpos($l, '=');
          if (FALSE !== $eqpos) {
            $option = str_replace('FCKConfig.', '', substr($l, 0, $eqpos));
            $js .= "\n". $js_id .".Config['". trim($option) ."'] =". substr($l, $eqpos + 1);
          }
        }
      }
    }

    // add custom xml stylesheet if it exists
    if (!empty($conf['css_style']) && $conf['css_style'] == 'theme') {
      if (file_exists($themepath .'fckstyles.xml')) {
        $styles_xml_path = $host . $themepath .'fckstyles.xml';
        $js .= $js_id .".Config['StylesXmlPath'] = \"". $styles_xml_path ."\";\n";
      }
    }
    elseif (!empty($conf['css_style']) && $conf['css_style'] == 'self') {
      $conf['styles_path'] = str_replace("%h%t", "%t", $conf['styles_path']);
      $js .=  $js_id .".Config['StylesXmlPath'] = \"". str_replace(array('%h', '%t', '%m'), array($host, $host . $themepath, $module_drupal_path), $conf['styles_path']) ."\";\n";
    }

    // add custom xml templae if it exists
    if (!empty($conf['templatefile_mode']) && $conf['templatefile_mode'] == 'theme') {
      if (file_exists($themepath .'fcktemplates.xml')) {
        $styles_xml_path = $host . $themepath .'fcktemplates.xml';
        $js .= $js_id .".Config['TemplatesXmlPath'] = \"". $styles_xml_path ."\";\n";
      }
    }
    elseif (!empty($conf['templatefile_mode']) && $conf['templatefile_mode'] == 'self') {
      $conf['templatefile_path'] = str_replace("%h%t", "%t", $conf['templatefile_path']);
      $js .=  $js_id .".Config['TemplatesXmlPath'] = \"". str_replace(array('%h', '%t', '%m'), array($host, $host . $themepath, $module_drupal_path), $conf['templatefile_path']) ."\";\n";
    }

    // add custom stylesheet if configured
    // lets hope it exists but we'll leave that to the site admin
    $cssfiles = array($module_full_path .'/fckeditor.css');
    switch ($conf['css_mode']) {
      case 'theme':
        global $language, $theme, $theme_info, $base_theme_info;

        $style_css = $themepath .'style.css';
        if (!empty($theme_info->stylesheets)) {
          $css_files = array();
          $editorcss = "\"";
          foreach ($base_theme_info as $base) { // Grab stylesheets from base theme
            if (!empty($base->stylesheets)) { // may be empty when the base theme reference in the info file is invalid
              foreach ($base->stylesheets as $type => $stylesheets) {
                if ($type != "print") {
                  foreach ($stylesheets as $name => $path) {
                    if (file_exists($path)) {
                      $css_files[$name] = $host . $path;
                    }
                  }
                }
              }
            }
          }
          if (!empty($theme_info->stylesheets)) { // Grab stylesheets from current theme
            foreach ($theme_info->stylesheets as $type => $stylesheets) {
              if ($type != "print") {
                foreach ($stylesheets as $name => $path) {
                  if (file_exists($path)) {
                    $css_files[$name] = $host . $path;
                  }
                  elseif (!empty($css_files[$name])) {
                    unset($css_files[$name]);
                  }
                }
              }
            }
          }
          if (!empty($css_files)) {
            $editorcss .= implode(",", $css_files) .",";
          }
          // Grab stylesheets from color module
          $color_paths = variable_get('color_'. $theme .'_stylesheets', array());
          if (defined('LANGUAGE_RTL') && $language->direction == LANGUAGE_RTL) {
            if (!empty($color_paths[1])) {
              $editorcss .= $host . $color_paths[1] .",";
            }
          }
          elseif (!empty($color_paths[0])) {
            $editorcss .= $host . $color_paths[0] .",";
          }
          $editorcss .= $module_full_path ."/fckeditor.css\";\n";
          $js .=  $js_id .".Config['EditorAreaCSS'] = ". $editorcss;
        }
        elseif (file_exists($style_css)) {
          $js .=  $js_id .".Config['EditorAreaCSS'] = \"". $host . $style_css .",". $module_full_path ."/fckeditor.css\";";
        }
        else {
          $js .=  $js_id .".Config['EditorAreaCSS'] = \"". $module_full_path ."/fckeditor.css\";";
        }
        break;

      case 'self':
        $conf['css_path'] = str_replace("%h%t", "%t", $conf['css_path']);
        $cssfiles[] = str_replace(array('%h', '%t'), array($host, $host . $themepath), $conf['css_path']);
        $js .=  $js_id .".Config['EditorAreaCSS'] = '". implode(',', $cssfiles) ."';\n";
        break;

      case 'none':
        $js .=  $js_id .".Config['EditorAreaCSS'] = ". $js_id .".BasePath + 'editor/css/fck_editorarea.css,' + '". implode(',', $cssfiles) ."';\n";
        break;
    }
    if ($num == 2) {
      $js .= 'var fckInstances = {};';
    }
    $js .= 'fckInstances[\''. $textarea_id .'\'] = '. $js_id .";\n";

    drupal_add_js('var '. $js_id .';if (Drupal.jsEnabled) {'. $js .'}', 'inline');

    if ($conf['popup'] == 't') {
      $element['#suffix'] .= ' <span class="fckeditor_popuplink">(<a href="#" onclick="FCKeditor_OpenPopup(\''. $module_full_path .'/fckeditor.popup.html\', \''. $js_id .'\', \''. $element['#id'] .'\', \''. $conf['width'] .'\'); return false;">'. t('Open rich text editor') ."</a>)</span>";
    }
  }

  // display the field id for administrators
  if (user_access('administer fckeditor') && (!isset($global_conf['show_fieldnamehint']) || $global_conf['show_fieldnamehint'] == 't')) {
    module_load_include('admin.inc', 'fckeditor');

    $element['#suffix'] .= '<div class="textarea-identifier description">'. t('The ID for !excludingorincludinglink this element is %fieldname.', array('!excludingorincludinglink' => l(t('excluding or including'), 'admin/settings/fckeditor'), '%fieldname' => fckeditor_rule_to_string(fckeditor_rule_create(fckeditor_get_nodetype($_GET['q']), $_GET['q'], $element['#id'])))) .'</div>';
  }

  return $element;
}

/**
 * sort roles according to precedence settings. previously sorted roles are followed by latest added roles.
 */
function fckeditor_sorted_roles($clear = FALSE) {
  static $order;
  if (isset($order) && $clear !== TRUE) {
    return $order;
  }
  $order = array();
  $roles = user_roles(0, 'access fckeditor');

  $result = db_query("SELECT settings FROM {fckeditor_settings} WHERE name='FCKeditor Global Profile'");
  $data = db_fetch_object($result);
  if (!empty($data->settings)) {
    $settings = unserialize($data->settings);
    if (isset($settings['rank']) && !empty($settings['rank']))
    foreach ($settings['rank'] as $rid) {
      if (isset($roles[$rid])) {
        $order[$rid] = $roles[$rid];
        unset($roles[$rid]);
      }
    }
  }
  krsort($roles);//sort the remaining unsorted roles by id, descending.
  $order += $roles;
  return $order;
}

/**
 * Test if client can render the FCKeditor
 * Use built-in test method in fckeditor.php
 * If fckeditor.php is not found, return false (probably in such case fckeditor is not installed correctly)
 *
 * @return
 *   TRUE if the browser is reasonably capable
 */
function fckeditor_is_compatible_client() {
  $editor_local_path    = fckeditor_path(TRUE);

  $fckeditor_main_file = $editor_local_path .'/fckeditor.php';
  if (!function_exists('version_compare') || version_compare(phpversion(), '5', '<')) {
    $fckeditor_target_file = $editor_local_path .'/fckeditor_php4.php';
  }
  else {
    $fckeditor_target_file = $editor_local_path .'/fckeditor_php5.php';
  }

  if (file_exists($fckeditor_target_file)) {
    include_once $fckeditor_target_file;
    //FCKeditor 2.6.1+
    if (function_exists('FCKeditor_IsCompatibleBrowser')) {
      return FCKeditor_IsCompatibleBrowser();
    }
    elseif (class_exists('FCKeditor')) {
      //FCKeditor 2.5.1 up to 2.6 with definition of FCKeditor_IsCompatibleBrowser() in fckeditor.php
      if (filesize($fckeditor_main_file) > 1500) {
        include_once $fckeditor_main_file;
      }
      //FCKeditor 2.5.0 and earlier
      $fck = new FCKeditor('fake');
      return $fck->IsCompatible();
    }
  }

  return FALSE;
}

/**
 * Read FCKeditor path from Global profile
 *
 * @return
 *   path to FCKeditor folder
 */
function fckeditor_path($local = FALSE) {
  static $fck_path;
  static $fck_local_path;

  if (!$fck_path) {
    $mod_path = drupal_get_path('module', 'fckeditor');
    $global_profile = fckeditor_profile_load('FCKeditor Global Profile');

    //default: path to fckeditor subdirectory in the fckeditor module directory (starting from the document root)
    //e.g. for http://example.com/drupal it will be /drupal/sites/all/modules/fckeditor/fckeditor
    $fck_path = base_path() . $mod_path .'/fckeditor';

    //default: path to fckeditor subdirectory in the fckeditor module directory (relative to index.php)
    //e.g.: sites/all/modules/fckeditor/fckeditor
    $fck_local_path = $mod_path .'/fckeditor';

    if ($global_profile) {
      $gs = $global_profile->settings;

      if (isset($gs['fckeditor_path'])) {
        $tmp_path = $gs['fckeditor_path'];
        $tmp_path = strtr($tmp_path, array("%b" => base_path(), "%m" => base_path() . $mod_path));
        $tmp_path   = str_replace('\\', '/', $tmp_path);
        $tmp_path   = str_replace('//', '/', $tmp_path);
        $tmp_path = rtrim($tmp_path, ' \/');
        if (substr($tmp_path, 0, 1) != '/') {
          $tmp_path = '/'. $tmp_path; //starts with '/'
        }
        $fck_path = $tmp_path;

        if (empty($gs['fckeditor_local_path'])) {
          //fortunately wildcards are used, we can easily get the right server path
          if (false !== strpos($gs['fckeditor_path'], "%m")) {
            $gs['fckeditor_local_path'] = strtr($gs['fckeditor_path'], array("%m" => $mod_path));
          }
          if (false !== strpos($gs['fckeditor_path'], "%b")) {
            $gs['fckeditor_local_path'] = strtr($gs['fckeditor_path'], array("%b" => "."));
          }
        }
      }

      //fckeditor_path is defined, but wildcards are not used, we need to try to find out where is
      //the document root located and append fckeditor_path to it.
      if (!empty($gs['fckeditor_local_path'])) {
        $fck_local_path = $gs['fckeditor_local_path'];
      }
      elseif (!empty($gs['fckeditor_path'])) {
        module_load_include('lib.inc', 'fckeditor');
        $local_path = fckeditor_resolve_url( $gs['fckeditor_path'] ."/" );
        if (FALSE !== $local_path) {
          $fck_local_path = $local_path;
        }
      }
    }
  }
  if ($local) {
    return $fck_local_path;
  }
  else {
    return $fck_path;
  }
}

function fckeditor_user_get_setting($user, $profile, $setting) {
  $default = array(
    'default' => 't',
    'show_toggle' => 't',
    'popup' => 'f',
    'skin' => 'default',
    'toolbar' => 'default',
    'expand' => 't',
    'width' => '100%',
    'lang' => 'en',
    'auto_lang' => 't',
  );

  if ($profile->settings['allow_user_conf']) {
    $status = isset($user->{'fckeditor_'. $setting}) ? $user->{'fckeditor_'. $setting} : (isset($profile->settings[$setting]) ? $profile->settings[$setting] : $default[$setting]);
  }
  else {
    $status = isset($profile->settings[$setting]) ? $profile->settings[$setting] : $default[$setting];
  }

  return $status;
}

function fckeditor_user_get_profile($user, $element_id = NULL) {
  $rids = array();

  // Since fckeditor_profile_load() makes a db hit, only call it when we're pretty sure
  // we're gonna render fckeditor.
  $sorted_roles = fckeditor_sorted_roles();
  foreach (array_keys($sorted_roles) as $rid) {
    if (isset($user->roles[$rid])) {
      $rids[] = $rid;
    }
  }

  if ($user->uid == 1 && !sizeof($rids)) {
    $r = db_fetch_object(db_query_range("SELECT r.rid FROM {fckeditor_role} r ORDER BY r.rid DESC", 1));
    $rids[] = $r->rid;
  }

  $profile_names = array();
  if (sizeof($rids)) {
    $result = db_query("SELECT r.rid, s.name FROM {fckeditor_settings} s INNER JOIN {fckeditor_role} r ON r.name = s.name WHERE r.rid IN (". implode(",", $rids) .")");
    while (($row = db_fetch_array($result))) {
      if (!isset($profile_names[$row['rid']])) {
        $profile_names[$row['rid']] = array();
      }
      array_push($profile_names[$row['rid']], $row['name']);
    }
  }

  foreach ($rids as $rid) {
    if (!empty($profile_names[$rid])) {
      foreach ($profile_names[$rid] as $profile_name) {
        $profile = fckeditor_profile_load($profile_name);

        $conf = $profile->settings;
        $enabled = fckeditor_is_enabled(empty($conf['excl_mode']) ? '0' : $conf['excl_mode'], empty($conf['excl_regex']) ? '' : $conf['excl_regex'], $element_id, $_GET['q']);

        if ($enabled) {
          return $profile;
        }
      }
    }
  }

  return FALSE;
}

function fckeditor_get_nodetype($get_q) {
  static $nodetype;

  if (!isset($nodetype)) {
    $menuitem = menu_get_item();
    $nodetype = '*';
    if (!empty($menuitem['page_arguments']) && is_array($menuitem['page_arguments'])) {
      foreach ($menuitem['page_arguments'] as $item) {
        if (!empty($item->nid) && !empty($item->type)) {
          // not 100% valid check if $item is a node
          $nodetype = $item->type;
          break;
        }
      }
    }

    if ($nodetype == '*') {
      $get_q = explode("/", $get_q, 3);
      if ($get_q[0] == "node" && $get_q[1] == "add" && !empty($get_q[2])) {
        $nodetype = $get_q[2];
      }
    }
  }

  return $nodetype;
}

function fckeditor_path_to_theme() {
  global $theme_key;
  static $themepath;
  
  if (empty($themepath) && !empty($theme_key)) {
    $themepath = drupal_get_path('theme', $theme_key);
  }

  // fall back
  if (empty($themepath)) {
    return path_to_theme();
  }
  
  return $themepath;
}

Other Drupal examples (source code examples)

Here is a short list of links related to this Drupal fckeditor.module source code file:

new blog posts

"Drupal" is a registered trademark of Dries Buytaert.

my drupal tutorials and examples  

Copyright 1998-2016 Alvin Alexander, alvinalexander.com
All Rights Reserved.

Beginning in 2016, a portion of the proceeds from pages under the '/drupal-code-examples/' URI will be donated to charity.