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__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("|]*)>|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__' => '')); 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']; // The following condition may fail when there are textareas with formats that do not have FCKeditor enabled. if (isset($_fckeditor_js_ids[$textarea_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, $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'] .''; } $content .= $element['#value']; $wysiwyg_link = ''; $wysiwyg_link .= ""; $wysiwyg_link .= $fckeditor_on ? t('Switch to plain text editor') : t('Switch to rich text editor'); $wysiwyg_link .= ''; // 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(''); $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'; } if ($filebrowser == 'ckfinder' && !file_exists(_fckeditor_ckfinder_path())) { $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; case 'ckfinder': $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'] = '". $module_full_path ."/ckfinder/ckfinder.html';\n"; $js .= $js_id .".Config['ImageBrowserURL'] = '". $module_full_path ."/ckfinder/ckfinder.html?type=Images';\n"; $js .= $js_id .".Config['FlashBrowserURL'] = '". $module_full_path ."/ckfinder/ckfinder.html?type=Flash';\n"; 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'] .= ' ('. t('Open rich text editor') .")"; } } // 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'] .= '
'. 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'])))) .'
'; } 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)) { $nodetypes = node_get_types('names'); $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]; // underscores are translated to dashes in node/add/ urls. try to translate it back if (!isset($nodetypes[$nodetype])) { foreach (array_keys($nodetypes) as $nt) { if (strtr($nt, '_', '-') === $nodetype) { $nodetype = $nt; break; } } } } } // Sanity check if (!isset($nodetypes[$nodetype])) { $nodetype = NULL; } } 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; }