'Wysiwyg Editor', 'page callback' => 'wysiwyg_editor_admin', 'description' => 'Configure client-side editors profiles.', 'access arguments' => array('administer site configuration'), 'file' => 'wysiwyg_editor.admin.inc', ); return $items; } /** * Implementation of hook_theme(). */ function wysiwyg_editor_theme() { return array( 'wysiwyg_editor_admin_button_table' => array('arguments' => array('form')), ); } /** * Implementation of hook_help(). */ function wysiwyg_editor_help($path, $arg) { switch ($path) { case 'admin/settings/wysiwyg/profile': case 'admin/help#wysiwyg_editor': $output = '
'. t('Profiles can be defined based on user roles. A Wysiwyg Editor profile can define which pages receive this Wysiwyg Editor capability, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor functions. Lastly, only users with the %permission user permission are able to use Wysiwyg Editor.', array('%permission' => 'access wysiwyg editor', '!url' => url('admin/user/permissions'))) .'
'; return $output; } } /** * Implementation of hook_perm(). */ function wysiwyg_editor_perm() { $array = array('access wysiwyg editor'); $wysiwyg_editor_mod_path = drupal_get_path('module', 'wysiwyg_editor'); if (is_dir($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/imagemanager/')) { $array[] = 'access tinymce imagemanager'; } if (is_dir($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/filemanager/')) { $array[] = 'access tinymce filemanager'; } return $array; } /** * Implementation of hook_elements(). * * @todo Remove #wysiwyg_style; the GUI for an editor should be solely handled * via profiles, when profiles are attached to an input format. It makes no * sense to display TinyMCE's simple GUI/theme for the user signature, when * the input format allows users to use advanced HTML and hence, editor * plugins. Fix this here, in wysiwyg_editor_process_textarea(), and lastly * in wysiwyg_editor_get_config(). */ function wysiwyg_editor_elements() { $type = array(); if (user_access('access wysiwyg editor')) { // Let Wysiwyg Editor potentially process each textarea. $type['textarea'] = array('#process' => array('wysiwyg_editor_process_textarea'), '#wysiwyg' => TRUE, '#wysiwyg_style' => 'advanced'); } return $type; } /** * Implementation of hook_form_alter(). */ function wysiwyg_editor_form_alter(&$form, &$form_state) { // Disable 'teaser' textarea. if (isset($form['body_field'])) { unset($form['body_field']['teaser_js']); $form['body_field']['teaser_include'] = array(); } } /** * Alter #wysiwyg for certain core textareas. * * @param $element * The textarea element to be processed. */ function wysiwyg_editor_filter_elements(&$element) { switch ($element['#name']) { // Disable Wysiwyg Editor for these textareas. case 'log': // Node revisions log message. case 'img_assist_pages': // Image Assist visibility settings. case 'caption': // User signature? case 'pages': // (Block) Visibility settings. case 'access_pages': // Wysiwyg Editor profile settings. case 'user_mail_welcome_body': // User settings. case 'user_mail_approval_body': // User settings. case 'user_mail_pass_body': // User settings. case 'synonyms': // Taxonomy terms. case 'description': // Taxonomy terms. $element['#wysiwyg'] = FALSE; break; // Force 'simple' theme for some smaller textareas. case 'signature': // User signature. case 'site_mission': case 'site_footer': case 'site_offline_message': case 'page_help': // Page content-type help message? case 'user_registration_help': case 'user_picture_guidelines': $element['#wysiwyg_style'] = 'simple'; break; } } /** * Process a textarea for Wysiwyg Editor. */ function wysiwyg_editor_process_textarea($element) { wysiwyg_editor_filter_elements($element); if ($element['#wysiwyg']) { $profile = wysiwyg_editor_load_profile(wysiwyg_editor_current_profile()); if ($profile && _wysiwyg_editor_page_match($profile)) { if (!wysiwyg_editor_load_editor($profile)) { // Bail out if editor could not be loaded. return $element; } // Check editor theme (and reset if needed). // Default to advanced theme if the requested one is not installed. $element['#wysiwyg_style'] = wysiwyg_editor_get_themes($profile, $element['#wysiwyg_style']); wysiwyg_editor_add_settings($profile, $element['#wysiwyg_style']); wysiwyg_editor_add_plugin_settings($profile); if (!isset($element['#attributes'])) { $element['#attributes'] = array(); } if (!isset($element['#attributes']['class'])) { $element['#attributes']['class'] = 'wysiwyg wysiwyg-'. $element['#wysiwyg_style']; } else { $element['#attributes']['class'] .= ' wysiwyg wysiwyg-'. $element['#wysiwyg_style']; } // Set resizable to false to avoid drupal.js resizable function from // taking control of the textarea $element['#resizable'] = FALSE; } } return $element; } /** * Load an editor library and initialize basic Wysiwyg settings. * * @param $profile * A wysiwyg editor profile. * * @return * TRUE if the editor has been loaded, FALSE if not. * * @see wysiwyg_editor_process_textarea() */ function wysiwyg_editor_load_editor($profile) { static $settings_added; static $loaded = array(); $name = $profile->settings['editor']; // Library files must only be loaded once. if (!isset($loaded[$name])) { // Load editor $editor = wysiwyg_get_editor($name); if ($editor) { // Determine library files to load. if (isset($profile->settings['library']) && isset($editor['libraries'][$profile->settings['library']])) { $library = $profile->settings['library']; $files = $editor['libraries'][$profile->settings['library']]['files']; } else { // Fallback to the first by default (external libraries can change). $library = key($editor['libraries']); $files = array_shift($editor['libraries']); $files = $files['files']; } foreach ($files as $file) { drupal_add_js($editor['library path'] . '/' . $file); } // Load JavaScript integration files for this editor. if (isset($editor['js files'])) { $files = $editor['js files']; } foreach ($files as $file) { drupal_add_js($editor['js path'] . '/' . $file, 'module', 'footer'); } $status = wysiwyg_editor_user_get_status($profile); drupal_add_js(array('wysiwygEditor' => array( 'configs' => array($editor['name'] => array()), 'showToggle' => $profile->settings['show_toggle'], 'status' => $status, // If JS compression is enabled, at least TinyMCE is unable to determine // its own base path and exec mode since it can't find the script name. 'editorBasePath' => base_path() . $editor['library path'], 'execMode' => $library, )), 'setting'); $loaded[$name] = TRUE; } else { $loaded[$name] = FALSE; } } // Add basic Wysiwyg settings. if (!isset($settings_added) && $loaded[$name]) { drupal_add_js(array('wysiwygEditor' => array( 'configs' => array(), 'disable' => t('Disable rich-text'), 'enable' => t('Enable rich-text'), )), 'setting'); // Add wysiwyg_editor.js to the footer to ensure it's executed after the // Drupal.settings array has been rendered and populated. Also, since editor // library initialization functions must be loaded first by the browser, // Drupal.wysiwygEditorInit() must be executed AFTER editors registered // their callbacks, and BEFORE Drupal.behaviors are applied, this must come // last. // @todo Separate into wysiwyg.init.js and wysiwyg.editor?.js, to ensure // this logic/ordering, and do not force editor integration scripts to // check and define Drupal.wysiwyg on its own. drupal_add_js(wysiwyg_get_path('wysiwyg_editor.js'), 'module', 'footer'); // Add our stylesheet to stack editor buttons into one row. drupal_add_css(wysiwyg_get_path('wysiwyg_editor.css')); $settings_added = TRUE; } return $loaded[$name]; } /** * Register a theme. */ function wysiwyg_editor_add_settings($profile, $theme) { static $themes = array(); if (!isset($themes[$theme])) { $config = wysiwyg_editor_get_config($profile, $theme); // Convert the config values into the form expected by Wysiwyg Editor. // @todo Is this conversion TinyMCE specific? foreach ($config as $key => $value) { if (is_bool($value)) { continue; } if (is_array($value)) { $config[$key] = implode(',', $config[$key]); } } drupal_add_js(array('wysiwygEditor' => array('configs' => array($profile->settings['editor'] => array($theme => $config)))), 'setting'); $themes[$theme] = TRUE; } } /** * Load external plugins. * * @param $profile * A wysiwyg editor profile. * * Note: tinyMCE.loadPlugin() need not be invoked more than once. */ function wysiwyg_editor_add_plugin_settings($profile) { static $plugins_added = array(); if (!isset($plugins_added[$profile->settings['editor']])) { $plugins = array(); $editor = wysiwyg_get_editor($profile->settings['editor']); $info = module_invoke_all('wysiwyg_plugin', $editor['name'], $editor['installed version']); if (isset($editor['plugin settings callback']) && function_exists($editor['plugin settings callback'])) { $plugins = $editor['plugin settings callback']($editor, $profile, $info); } drupal_add_js(array('wysiwygEditor' => array('plugins' => array($profile->settings['editor'] => $plugins))), 'setting'); $plugins_added[$profile->settings['editor']] = TRUE; } } /** * Grab the themes available to Wysiwyg Editor. * * Wysiwyg Editor themes control the functionality and buttons that are available to a * user. Themes are only looked for within the default Wysiwyg Editor theme directory. * * @param $profile * A wysiwyg editor profile; passed/altered by reference. * @param $selected_theme * An optional theme name that ought to be used. * * @return * An array of theme names, or a single, checked theme name if $selected_theme * was given. */ function wysiwyg_editor_get_themes(&$profile, $selected_theme = NULL) { static $themes = array(); if (!isset($themes[$profile->settings['editor']])) { $editor = wysiwyg_get_editor($profile->settings['editor']); if (isset($editor['themes callback']) && function_exists($editor['themes callback'])) { $themes[$editor['name']] = $editor['themes callback']($editor, $profile); } // Fallback to 'default' otherwise. else { $themes[$editor['name']] = array('default'); } } // Check optional $selected_theme argument, if given. if (isset($selected_theme)) { // If the passed theme name does not exist, use the first available. if (!isset($themes[$profile->settings['editor']][$selected_theme])) { $selected_theme = $profile->settings['theme'] = $themes[$profile->settings['editor']][0]; } } return isset($selected_theme) ? $selected_theme : $themes[$profile->settings['editor']]; } /** * Return plugin metadata from the plugin registry. * * @param $editor_name * The internal name of an editor to return plugins for. * * @return * An array for each plugin. */ function wysiwyg_editor_get_plugins($editor_name) { $plugins = array(); if (!empty($editor_name)) { $editor = wysiwyg_get_editor($editor_name); if (isset($editor['plugin callback']) && function_exists($editor['plugin callback'])) { $plugins = $editor['plugin callback']($editor); } // Load our own plugins. include_once drupal_get_path('module', 'wysiwyg_editor') .'/wysiwyg_editor.plugins.inc'; $plugins = array_merge($plugins, module_invoke_all('wysiwyg_plugin', $editor['name'], $editor['installed version'])); } return $plugins; } /** * Return an array of initial Wysiwyg Editor config options from the current role. */ function wysiwyg_editor_get_config($profile, $theme) { $editor = wysiwyg_get_editor($profile->settings['editor']); $settings = array(); if (!empty($editor['settings callback']) && function_exists($editor['settings callback'])) { $settings = $editor['settings callback']($editor, $profile->settings, $theme); } return $settings; } /** * Return the name of the current user's default profile. */ function wysiwyg_editor_current_profile() { global $user; static $profile_name; if (!isset($profile_name)) { $profile_name = db_result(db_query_range('SELECT p.name FROM {wysiwyg_editor_profile} p INNER JOIN {wysiwyg_editor_role} r ON r.name = p.name WHERE r.rid IN (%s) ORDER BY plugin_count DESC', implode(',', array_keys($user->roles)), 0, 1)); } return $profile_name; } /** * Load all profiles. Just load one profile if $name is passed in. */ function wysiwyg_editor_load_profile($name = '') { static $profiles; // If $name is passed from wysiwyg_editor_current_profile(), it may be FALSE, // which means the user is not allowed to use a wysiwyg editor. if ($name === FALSE) { return FALSE; } if (!isset($profiles)) { $profiles = array(); $roles = user_roles(); $result = db_query('SELECT * FROM {wysiwyg_editor_profile}'); while ($profile = db_fetch_object($result)) { $profile->settings = unserialize($profile->settings); $result2 = db_query("SELECT rid FROM {wysiwyg_editor_role} WHERE name = '%s'", $profile->name); $profile_roles = array(); while ($role = db_fetch_object($result2)) { $profile_roles[$role->rid] = $roles[$role->rid]; } $profile->rids = $profile_roles; $profiles[$profile->name] = $profile; } } return ($name && isset($profiles[$name]) ? $profiles[$name] : ($name ? FALSE : $profiles)); } /** * Determine if Wysiwyg Editor has permission to be used on the current page. * * @return * TRUE if can render, FALSE if not allowed. */ function _wysiwyg_editor_page_match($profile) { $page_match = FALSE; if (!is_object($profile)) { return FALSE; } // Kill Wysiwyg Editor if we're editing a textarea with PHP in it! if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == 'edit') { $node = node_load(arg(1)); $filters = filter_list_format($node->format); foreach ($filters as $filter) { if ($filter->module == 'php') { return FALSE; } } } if ($profile->settings['access_pages']) { // If the PHP option wasn't selected if ($profile->settings['access'] < 2) { $path = drupal_get_path_alias($_GET['q']); $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\