Newer
Older
* Integrate Wysiwyg editors into Drupal.
*/
/**
* Implementation of hook_menu().
*/
function wysiwyg_editor_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/settings/wysiwyg/profile',
'title' => t('Wysiwyg Editor'),
'callback' => 'wysiwyg_editor_admin',
'description' => t('Configure the rich editor.'),
'access' => user_access('administer site configuration'),
);
}
return $items;
}
/**
* Implementation of hook_help().
*/
function wysiwyg_editor_help($section) {
case 'admin/settings/wysiwyg/profile#pages':
return "node/*\nuser/*\ncomment/*";
case 'admin/settings/wysiwyg/profile':
case 'admin/help#wysiwyg_editor':
return t('<p style="font-size:x-small">$Revision$ $Date$</p>'.
'<p>Wysiwyg Editor adds what-you-see-is-what-you-get (WYSIWYG) html editing to textareas. This editor can be enabled/disabled without reloading the page by clicking a link below each textarea.</p>
<p>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.</p>
<p>Lastly, only users with the <code>access wysiwyg editor</code> <a href="!url">permission</a> will be able to use Wysiwyg Editor.</p>', array('!url' => url('admin/user/access'))
}
}
/**
* 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;
}
/**
* Callback handler for admin pages; menu callback.
*/
function wysiwyg_editor_admin($arg = NULL) {
require_once drupal_get_path('module', 'wysiwyg_editor') .'/wysiwyg_editor.admin.inc';
$op = isset($_POST['op']) ? $_POST['op'] : NULL;
$op = ($arg && !$op ? $arg : $op);
return _wysiwyg_editor_admin($op);
}
/**
* Implementation of hook_elements().
*/
function wysiwyg_editor_elements() {
if (user_access('access wysiwyg editor')) {
// Let Wysiwyg Editor potentially process each textarea.
$type['textarea'] = array('#process' => array('wysiwyg_editor_process_textarea' => array()), '#wysiwyg' => TRUE, '#wysiwyg_style' => 'advanced');
}
return $type;
}
/**
* Load Wysiwyg Editor files and send configuration data.
function wysiwyg_editor_load() {
global $user;
static $loaded = FALSE;
// We only load the Wysiwyg Editor js file once per page request.
$profile = wysiwyg_editor_profile_load(wysiwyg_editor_current_profile());
$enable = t('enable rich-text');
$disable = t('disable rich-text');
$status = wysiwyg_editor_user_get_status($user, $profile);
$no_wysiwyg = t('Your current web browser does not support WYSIWYG editing.');
$wysiwyg_editor_mod_path = drupal_get_path('module', 'wysiwyg_editor');
if (is_dir($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/imagemanager/') && user_access('access tinymce imagemanager')) {
// if tinymce imagemanager is installed
drupal_add_js($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/imagemanager/jscripts/mcimagemanager.js');
if (is_dir($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/filemanager/') && user_access('access tinymce filemanager')) {
// if tinymce filemanager is installed
drupal_add_js($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/filemanager/jscripts/mcfilemanager.js');
}
// TinyMCE Compressor >= 1.0.9
if (file_exists($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/tiny_mce_gzip.js')) {
drupal_add_js($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/tiny_mce_gzip.js');
}
// TinyMCE Compressor < 1.0.9
elseif (file_exists($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/tiny_mce_gzip.php')) {
drupal_add_js($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/tiny_mce_gzip.php');
}
else {
// For some crazy reason IE will only load this JS file if the absolute reference is given to it.
drupal_add_js($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/tiny_mce.js');
// Add wysiwyg_editor.js to the footer to ensure it's executed after the Drupal.settings array has been rendered and populated.
drupal_add_js($wysiwyg_editor_mod_path .'/wysiwyg_editor.js', 'footer');
drupal_add_js(array('wysiwygEditor' => array('configs' => array(), 'showToggle' => ($profile->settings['show_toggle'] == 'true'), 'disable' => $disable, 'enable' => $enable, 'noWysiwyg' => $no_wysiwyg, 'linkText' => $link_text, 'status' => $status)), 'setting');
// We have to do this because of some unfocused CSS in certain themes. See http://drupal.org/node/18879 for details
drupal_set_html_head('<style type="text/css" media="all">.mceEditor img { display: inline; }</style>');
$loaded = TRUE;
}
}
/**
* Process a textarea for Wysiwyg Editor.
function wysiwyg_editor_process_textarea($element) {
wysiwyg_editor_filter_elements($element);
if ($element['#wysiwyg']) {
$profile = wysiwyg_editor_profile_load(wysiwyg_editor_current_profile());
if (_wysiwyg_editor_page_match($profile)) {
// Default to advanced theme if the requested one is not installed.
$themes = _wysiwyg_editor_get_themes();
if (!isset($themes[$element['#wysiwyg_style']])) {
$element['#wysiwyg_style'] = 'advanced';
}
wysiwyg_editor_load();
_wysiwyg_editor_set_config($element['#wysiwyg_style']);
if (!isset($element['#attributes'])) {
$element['#attributes'] = array();
}
if (!isset($element['#attributes']['class'])) {
$element['#attributes']['class'] = 'wysiwyg wysiwyg-'. $element['#wysiwyg_style'];
$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;
}
/**
* Register a theme.
*/
function _wysiwyg_editor_set_config($theme) {
static $themes = array();
// Only sent a theme's configuration data once.
if (!in_array($theme, $themes)) {
$profile = wysiwyg_editor_profile_load(wysiwyg_editor_current_profile());
$config = wysiwyg_editor_config($profile, $theme);
// Convert the config values into the form expected by Wysiwyg Editor.
foreach ($config as $key => $value) {
switch ($value) {
case 'true':
$config[$key] = TRUE;
break;
case 'false':
$config[$key] = FALSE;
break;
}
if (is_array($value)) {
$config[$key] = implode(',', $config[$key]);
}
}
drupal_add_js('Drupal.settings.wysiwygEditor.configs["'. $theme .'"] = '. drupal_to_js($config) .';', 'inline');
$themes[] = $theme;
}
}
/**
* Implementation of hook_user().
*/
function wysiwyg_editor_user($type, &$edit, &$user, $category = NULL) {
if ($type == 'form' && $category == 'account' && user_access('access wysiwyg editor')) {
$profile = wysiwyg_editor_user_get_profile($user);
// because the settings are saved as strings we need to test for the string 'true'
if ($profile->settings['user_choose'] == 'true') {
$form['wysiwyg'] = array(
'#title' => t('Wysiwyg Editor rich-text settings'),
'#weight' => 10,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
$form['wysiwyg']['wysiwyg_status'] = array(
'#type' => 'select',
'#title' => t('Default state'),
'#default_value' => isset($user->wysiwyg_editor_status) ? $user->wysiwyg_editor_status : (isset($profile->settings['default']) ? $profile->settings['default'] : 'false'),
'#options' => array('false' => t('disabled'), 'true' => t('enabled')),
'#description' => t('Should rich-text editing be enabled or disabled by default in textarea fields?'),
return array('wysiwyg_editor' => $form);
}
}
if ($type == 'validate') {
return array('wysiwyg_editor_status' => $edit['wysiwyg_editor_status']);
}
}
/**
* Filter for core text fields.
*
* @param $element
* The textarea element to be filtered.
*/
function wysiwyg_editor_filter_elements(&$element) {
switch ($element['#name']) {
// Disable Wysiwyg Editor for these textareas.
case 'log': // book and page log
case 'img_assist_pages':
case 'caption': // signature
case 'pages':
case 'access_pages': //Wysiwyg Editor profile settings.
case 'user_mail_welcome_body': // user config settings
case 'user_mail_approval_body': // user config settings
case 'user_mail_pass_body': // user config settings
case 'synonyms': // taxonomy terms
case 'description': // taxonomy terms
$element['#wysiwyg'] = FALSE;
break;
// Force the 'simple' theme for some of the smaller textareas.
case 'signature':
case 'site_mission':
case 'site_footer':
case 'site_offline_message':
case 'page_help':
case 'user_registration_help':
case 'user_picture_guidelines':
$element['#wysiwyg_style'] = 'simple';
break;
}
}
/**
* 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.
*
* @return
* An array of theme names.
*/
function _wysiwyg_editor_get_themes() {
static $themes = array();
if (!$themes) {
$theme_loc = drupal_get_path('module', 'wysiwyg_editor') .'/tinymce/jscripts/tiny_mce/themes/';
if (is_dir($theme_loc) && $dh = opendir($theme_loc)) {
while (($file = readdir($dh)) !== false) {
if (!in_array($file, array('.', '..', 'CVS')) && is_dir($theme_loc . $file)) {
$themes[$file] = $file;
}
}
closedir($dh);
asort($themes);
}
}
return $themes;
}
/**
* Return plugin metadata from the plugin registry.
*
* We also scrape each plugin's *.js file for the human friendly name and help
* text URL of each plugin.
*
* @return
* An array for each plugin.
*/
function _wysiwyg_editor_get_buttons($skip_metadata = TRUE) {
include_once drupal_get_path('module', 'wysiwyg_editor') .'/wysiwyg_editor.plugins.inc';
$plugins = _wysiwyg_editor_plugins();
if ($skip_metadata == FALSE && is_array($plugins)) {
foreach ($plugins as $name => $plugin) {
$file = drupal_get_path('module', 'wysiwyg_editor') .'/tinymce/jscripts/tiny_mce/plugins/'. $name .'/editor_plugin_src.js';
// Grab the plugin metadata by scanning the *.js file.
if (file_exists($file)) {
$lines = file($file);
$has_infourl = FALSE;
foreach ($lines as $line) {
if ($has_longname && $has_infourl) {
break;
}
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
if (strstr($line, 'longname')) {
$start = strpos($line, "'") + 1;
$end = strrpos($line, "'") - $start;
$metadata[$name]['longname'] = substr($line, $start, $end);
$has_longname = TRUE;
}
elseif (strstr($line, 'infourl')) {
$start = strpos($line, "'") + 1;
$end = strrpos($line, "'") - $start;
$metadata[$name]['infourl'] = substr($line, $start, $end);
$has_infourl = TRUE;
}
}
}
// Find out the buttons a plugin has.
foreach ($plugin as $k => $v) {
if (strstr($k, 'theme_advanced_buttons')) {
$metadata[$name]['buttons'] = array_merge((array) $metadata[$name]['buttons'], $plugin[$k]);
}
}
}
return $metadata;
}
return $plugins;
}
/**
* Return an array of initial Wysiwyg Editor config options from the current role.
function wysiwyg_editor_config($profile, $theme) {
global $user;
// Drupal theme path.
$themepath = path_to_theme() .'/';
$host = base_path();
$settings = $profile->settings;
// Build a default list of Wysiwyg Editor settings.
$init['mode'] = 'none';
$init['theme'] = $theme;
$init['relative_urls'] = 'false';
$init['document_base_url'] = "$host";
$init['language'] = $settings['language'] ? $settings['language'] : 'en';
$init['safari_warning'] = $settings['safari_message'] ? $settings['safari_message'] : 'false';
$init['entity_encoding'] = 'raw';
$init['verify_html'] = $settings['verify_html'] ? $settings['verify_html'] : 'false';
$init['preformatted'] = $settings['preformatted'] ? $settings['preformatted'] : 'false';
$init['convert_fonts_to_spans'] = $settings['convert_fonts_to_spans'] ? $settings['convert_fonts_to_spans'] : 'false';
$init['remove_linebreaks'] = $settings['remove_linebreaks'] ? $settings['remove_linebreaks'] : 'true';
$init['apply_source_formatting'] = $settings['apply_source_formatting'] ? $settings['apply_source_formatting'] : 'true';
$init['theme_advanced_resize_horizontal'] = 'false';
$init['theme_advanced_resizing_use_cookie'] = 'false';
$wysiwyg_editor_mod_path = drupal_get_path('module', 'wysiwyg_editor');
if (is_dir($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/imagemanager/') && user_access('access tinymce imagemanager')) {
// we probably need more security than this
$init['file_browser_callback'] = "mcImageManager.filebrowserCallBack";
}
if (is_dir($wysiwyg_editor_mod_path .'/tinymce/jscripts/tiny_mce/plugins/filemanager/') && user_access('access tinymce filemanager')) {
// we probably need more security than this
$init['file_browser_callback'] = "mcImageManager.filebrowserCallBack";
}
if ($settings['css_classes']) {
$init['theme_advanced_styles'] = $settings['css_classes'];
}
if ($settings['css_setting'] == 'theme') {
$css = $themepath .'style.css';
if (file_exists($css)) {
$init['content_css'] = $host . $css;
}
}
else if ($settings['css_setting'] == 'self') {
$init['content_css'] = str_replace(array('%h', '%t'), array($host, $themepath), $settings['css_path']);
}
// Add theme-specific settings.
switch ($theme) {
case 'advanced':
$init['theme_advanced_resize_horizontal'] = 'false';
$init['theme_advanced_resizing_use_cookie'] = 'false';
$init['plugins'] = array();
$init['theme_advanced_toolbar_location'] = $settings['toolbar_loc'] ? $settings['toolbar_loc'] : 'bottom';
$init['theme_advanced_toolbar_align'] = $settings['toolbar_align'] ? $settings['toolbar_align'] : 'left';
$init['theme_advanced_path_location'] = $settings['path_loc'] ? $settings['path_loc'] : 'bottom';
$init['theme_advanced_resizing'] = $settings['resizing'] ? $settings['resizing'] : 'true';
$init['theme_advanced_blockformats'] = $settings['block_formats'] ? $settings['block_formats'] : 'p,address,pre,h1,h2,h3,h4,h5,h6';
if (is_array($settings['buttons'])) {
// This gives us the $plugins variable.
$plugins = _wysiwyg_editor_get_buttons();
// Find the enabled buttons and the mce row they belong on. Also map the
// plugin metadata for each button.
$plugin_tracker = array();
// Plugin name
foreach ($plugins as $rname => $rplugin) {
// Wysiwyg Editor key
foreach ($rplugin as $mce_key => $mce_value) {
// Buttons
foreach ($mce_value as $k => $v) {
if (isset($settings['buttons'][$rname .'-'. $v])) {
// Font isn't a true plugin, rather it's buttons made available by the advanced theme
if (!in_array($rname, $plugin_tracker) && $rname != 'font') {
$plugin_tracker[] = $rname;
}
$init[$mce_key][] = $v;
}
}
}
// Some advanced plugins only have an $rname and no buttons
if (isset($settings['buttons'][$rname])) {
if (!in_array($rname, $plugin_tracker)) {
$plugin_tracker[] = $rname;
}
// Add the rest of the Wysiwyg Editor config options to the $init array for each button.
if (is_array($plugin_tracker)) {
foreach ($plugin_tracker as $pname) {
if ($pname != 'default') {
$init['plugins'][] = $pname;
}
foreach ($plugins[$pname] as $mce_key => $mce_value) {
// Don't overwrite buttons or extended_valid_elements
if ($mce_key == 'extended_valid_elements') {
// $mce_value is an array for extended_valid_elements so just grab the first element in the array (never more than one)
$init[$mce_key][] = $mce_value[0];
}
else if (!strstr($mce_key, 'theme_advanced_buttons')) {
$init[$mce_key] = $mce_value;
}
}
}
}
// Cleanup
foreach ($init as $mce_key => $mce_value) {
if (is_array($mce_value)) {
$mce_value = array_unique($mce_value);
}
$init[$mce_key] = $mce_value;
}
// Shuffle buttons around so that row 1 always has the most buttons,
// followed by row 2, etc. Note: These rows need to be set to NULL otherwise
// Wysiwyg Editor loads its own buttons inherited from the theme.
if (!isset($init['theme_advanced_buttons1'])) {
$init['theme_advanced_buttons1'] = array();
}
if (!isset($init['theme_advanced_buttons2'])) {
$init['theme_advanced_buttons2'] = array();
}
if (!isset($init['theme_advanced_buttons3'])) {
$init['theme_advanced_buttons3'] = array();
}
// Minimum number of buttons per row.
$min_btns = 5;
$num1 = count($init['theme_advanced_buttons1']);
$num2 = count($init['theme_advanced_buttons2']);
$num3 = count($init['theme_advanced_buttons3']);
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
if ($num3 < $min_btns) {
$init['theme_advanced_buttons2'] = array_merge($init['theme_advanced_buttons2'], $init['theme_advanced_buttons3']);
$init['theme_advanced_buttons3'] = array();
$num2 = count($init['theme_advanced_buttons2']);
}
if ($num2 < $min_btns) {
$init['theme_advanced_buttons1'] = array_merge($init['theme_advanced_buttons1'], $init['theme_advanced_buttons2']);
// Squish the rows together, since row 2 is empty
$init['theme_advanced_buttons2'] = $init['theme_advanced_buttons3'];
$init['theme_advanced_buttons3'] = array();
$num1 = count($init['theme_advanced_buttons1']);
}
if ($num1 < $min_btns) {
$init['theme_advanced_buttons1'] = array_merge($init['theme_advanced_buttons1'], $init['theme_advanced_buttons2']);
// Squish the rows together, since row 2 is empty
$init['theme_advanced_buttons2'] = $init['theme_advanced_buttons3'];
$init['theme_advanced_buttons3'] = array();
}
}
break;
}
return $init;
}
/**
* Return the name of the current user's default profile.
*/
function wysiwyg_editor_current_profile() {
static $profile_name;
if (!$profile_name) {
global $user;
$profile_name = db_result(db_query('SELECT s.name FROM {wysiwyg_editor_profile} s INNER JOIN {wysiwyg_editor_role} r ON r.name = s.name WHERE r.rid IN (%s)', implode(',', array_keys($user->roles))));
}
return $profile_name;
}
/**
* Load all profiles. Just load one profile if $name is passed in.
*/
function wysiwyg_editor_profile_load($name = '') {
static $profiles = array();
if (!$profiles) {
$roles = user_roles();
$result = db_query('SELECT * FROM {wysiwyg_editor_profile}');
while ($data = db_fetch_object($result)) {
$data->settings = unserialize($data->settings);
$result2 = db_query("SELECT rid FROM {wysiwyg_editor_role} WHERE name = '%s'", $data->name);
$role = array();
while ($r = db_fetch_object($result2)) {
$role[$r->rid] = $roles[$r->rid];
}
$data->rids = $role;
$profiles[$data->name] = $data;
}
}
return ($name ? $profiles[$name] : $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($edit) {
// Kill Wysiwyg Editor if we're editing a textarea with PHP in it!
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
// PHP input formats are #2 in the filters table.
if (is_numeric(arg(1)) && arg(2) == 'edit') {
$node = node_load(arg(1));
if ($node->format == 2) {
return FALSE;
}
}
if ($edit->settings['access_pages']) {
// If the PHP option wasn't selected
if ($edit->settings['access'] < 2) {
$path = drupal_get_path_alias($_GET['q']);
$regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'), '/') .'\2'), preg_quote($edit->settings['access_pages'], '/')) .')$/';
$page_match = !($edit->settings['access'] xor preg_match($regexp, $path));
}
else {
$page_match = drupal_eval($edit->settings['access_pages']);
}
}
// No pages were specified to block so show on all
else {
$page_match = TRUE;
}
return $page_match;
}
function wysiwyg_editor_user_get_profile($account) {
$profile_name = db_result(db_query('SELECT s.name FROM {wysiwyg_editor_profile} s INNER JOIN {wysiwyg_editor_role} r ON r.name = s.name WHERE r.rid IN (%s)', implode(',', array_keys($account->roles))));
if ($profile_name) {
return wysiwyg_editor_profile_load($profile_name);
}
else {
return FALSE;
}
}
function wysiwyg_editor_user_get_status($user, $profile) {
$settings = $profile->settings;
if ($settings['user_choose']) {
$status = isset($user->wysiwyg_editor_status) ? $user->wysiwyg_editor_status : (isset($settings['default']) ? $settings['default'] : 'false');
}
else {
$status = isset($settings['default']) ? $settings['default'] : 'false';
}
return $status == 'true' ? TRUE : FALSE;
}