Newer
Older
<?php
// $Id$
// A collaborative project by Matt Westgate <drupal at asitis dot org>
// and Richard Bennett <richard.b@gritechnologies.com>
/**
* @file
* Integrate the TinyMCE editor (http://tinymce.moxiecode.com/) into Drupal.
*/
/**
* Implementation of hook_menu().
*
* Add the JavaScript file to the page head. Doing this in a menu hook is a
* little less expensive that in *_init since we don't need to load the head for
* Drupal-cached pages.
*
*/
function tinymce_menu($may_cache) {
if (!$may_cache) {
// For some crazy reason IE will only load this JS file if the absolute reference is given to it.
drupal_set_html_head('<script language="javascript" type="text/javascript" src="'. $base_url . '/'. drupal_get_path('module', 'tinymce') .'/tinymce/jscripts/tiny_mce/tiny_mce.js"></script>');
//We may need this so TinyMCE has the right path to Drupal to invoke drupal tinymce plugins.
//drupal_set_html_head('<script language="javascript" type="text/javascript"> var baseUrl = "'. $base_url .'"; </script>');
Matt Westgate
committed
// We have to do this becuase 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>');
}
}
/**
* Implementation of hook_help().
*/
function tinymce_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('The TinyMCE Javascript HTML WYSIWYG editor.');
case 'admin/settings/tinymce#pages':
return "node/*\nuser/*\ncomment/*";
}
}
/**
* Implementation of hook_perm().
*/
function tinymce_perm() {
Matt Westgate
committed
return array('access tinymce', 'choose own tinymce theme');
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/**
* Implementation of hook_img_assist_head().
*/
function tinymce_img_assist_head() {
$popup_path = drupal_get_path('module', 'tinymce'). '/tinymce/jscripts/tiny_mce';
$output = <<<EOD
<script language="javascript" src="$popup_path/tiny_mce_popup.js"></script>
<script language="javascript">
function insertImage(form) {
if (window.opener) {
var thumb = (form['edit-thumb'].checked) ? 1 : 0;
if (thumb == 1) {
var src = form['edit[thumbpath]'].value;
var width = form['edit[thumbWidth]'].value;
var height = form['edit[thumbHeight]'].value;
}
else {
var src = form['edit[filepath]'].value;
var width = form['edit[width]'].value != '' ? form['edit[width]'].value : form['edit[origWidth]'].value;
var height = form['edit[height]'].value != '' ? form['edit[height]'].value : form['edit[origHeight]'].value;
}
var alt = form['edit[alt]'].value;
window.opener.tinyMCE.insertImage(src, alt, '', '', '', width, height);
}
}
</script>
EOD;
return $output;
}
/**
* Implementation of hook_img_assist_on_submit().
*/
function tinymce_img_assist_on_submit() {
return 'parent.insertImage(this.form);';
}
/**
* Implementation of hook_settings().
*/
function tinymce_settings() {
drupal_set_title(t('TinyMCE settings (%revision)', array('%revision' => '$Revision$')));
Matt Westgate
committed
//Check if TinyMCE is installed.
$tinymce_loc = drupal_get_path('module', 'tinymce') .'/tinymce/';
if (!is_dir($tinymce_loc)) {
drupal_set_message(t('Could not find the TinyMCE engine installed at <strong>%tinymce-directory</strong>. Please <a href="http://tinymce.moxiecode.com/">download TinyMCE</a>, uncompress it and copy the folder into %tinymce-path.', array('%tinymce-path' => drupal_get_path('module', 'tinymce'), '%tinymce-directory' => drupal_get_path('module', 'tinymce'). '/tinymce/')), 'error');
}
$group = form_radios(t('Default theme'), 'tinymce_theme', variable_get('tinymce_theme', 'simple'), _tinymce_get_themes());
Matt Westgate
committed
$output = form_group(t('Themes'), $group);
Matt Westgate
committed
$group = form_radios(t('access tinymce'), 'tinymce_all', variable_get('tinymce_all', 1), array(t('on specific pages'), t('on all textareas')));
if (!variable_get('tinymce_all', 1)) {
$group .= form_textarea(t('Pages'), 'tinymce_pages', variable_get('tinymce_pages', tinymce_help('admin/settings/tinymce#pages')), 40, 5, t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are '<em>blog</em>' for the blog page and '<em>blog/*</em>' for every personal blog. '<em><front></em>' is the front page."));
}
$output .= form_group('', $group);
return $output;
}
/**
* Implementation of hook_textarea().
*/
function tinymce_textarea($op, $name) {
Matt Westgate
committed
static $is_running = FALSE;
if (!user_access('access tinymce')) return NULL;
global $user;
$theme_name = $user->tinymce_theme ? $user->tinymce_theme : variable_get('tinymce_theme', 'simple');
$user_status = $user->tinymce_status != NULL ? $user->tinymce_status : TRUE;
if ($op == 'pre' && _tinymce_page_match() && $user_status) {
global $base_url;
// Build a default list of TinyMCE settings.
$init['mode'] = 'textareas';
$init['theme'] = $theme_name;
$init['document_base_url'] = "$base_url/";
// Merge and overrivide user-defined TinyMCE settings.
Matt Westgate
committed
$init = array_merge($init, (array) theme('tinymce_theme', $init, $textarea_name, $theme_name, $is_running));
foreach ($init as $k => $v) {
$settings[] = $k. ' : "'. $v. '"';
}
$output = <<<EOD
<script language="javascript" type="text/javascript">
tinyMCE.init({
$tinymce_settings
});
</script>
EOD;
Matt Westgate
committed
// We only invoke TinyMCE once per request, not once per textarea. We could
// do this check earlier in the conditional, but it's probably wise to let
// the themed functions know what's going on.
if (!$is_running) {
$is_running = TRUE;
Matt Westgate
committed
}
}
}
/**
* Implementation of hook_user().
*/
function tinymce_user($type, &$edit, &$user, $category = NULL) {
Matt Westgate
committed
if ($type == 'form' && $category == 'account' && user_access('access tinymce')) {
$user_status = $edit['tinymce_status'] != NULL ? $edit['tinymce_status'] : ($user->tinymce_status != NULL ? $user->tinymce_status : 1);
Matt Westgate
committed
$form = form_radios(t('Status'), 'tinymce_status', $user_status, array(t('Disabled'), t('Enabled')), t('Would you like to enable rich-text editing of your content?'));
if ($user_status && user_access('choose own tinymce theme')) {
$form .= form_radios(t('Default theme'), 'tinymce_theme', $edit['tinymce_theme'] ? $edit['tinymce_theme'] : variable_get('tinymce_theme', 'simple'), _tinymce_get_themes());
}
return array(array('title' => t('TinyMCE settings'), 'data' => $form));
}
if ($type == 'validate') {
return array('tinymce_theme' => $edit['tinymce_theme'], 'tinymce_status' => $edit['tinymce_status']);
}
}
/**
* @addtogroup themeable
* @{
*/
/**
Matt Westgate
committed
* Customize a TinyMCE theme.
*
* @param init
Matt Westgate
committed
* An array of settings TinyMCE should invoke a theme. You may override any
* of the TinyMCE settings. Details here:
*
* http://tinymce.moxiecode.com/wrapper.php?url=tinymce/docs/using.htm
Matt Westgate
committed
*
* @param textarea_name
* The name of the textarea TinyMCE wants to enable.
*
* @param theme_name
* The default theme name to be enabled for this textarea. The sitewide
* default is 'simple', but the user may also override this.
Matt Westgate
committed
*
* @param is_running
* A boolean flag that identifies id TinyMCE is currently running for this
* request life cycle. If it's already running then anything returned by this
* will be ignored. This is necessary since TinyMCE works by being invoked
* once per request and not once per textarea.
Matt Westgate
committed
function theme_tinymce_theme($init, $textarea_name, $theme_name, $is_running) {
Matt Westgate
committed
switch ($theme_name) {
case 'advanced':
$init['extended_valid_elements'] = 'a[href|target|name]';
$init['theme_advanced_buttons3_add_before'] = 'tablecontrols,separator';
Matt Westgate
committed
$init['plugins'] = module_exist('img_assist') ? 'drupalimage,table,emotions,print' : 'table,emotions,print';
$init['theme_advanced_buttons3_add'] = 'emotions,separator,print';
Matt Westgate
committed
return $init;
}
}
/** @} End of addtogroup themeable */
/**
* Grab the themes available to TinyMCE.
*
* TinyMCE themes control the functionality and buttons that are available to a
* user. Themes are only looked for within the default TinyMCE theme directory.
*
* @return
* An array of theme names.
*/
function _tinymce_get_themes() {
static $themes = array();
if (!$themes) {
$theme_loc = drupal_get_path('module', 'tinymce') .'/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)) {
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
$themes[$file] = $file;
}
}
closedir($dh);
asort($themes);
}
}
return $themes;
}
/**
* Determine if TinyMCE can render the current page.
*
* @return
* TRUE if can render, FALSE if not allowed.
*/
function _tinymce_page_match() {
$edit = $_POST['edit'];
//Kill TinyMCE if we're editing a textarea with PHP in it!
if ($edit) {
if ($edit['format'] == 2) {
return FALSE;
}
}
else {
// PHP input formats are #2 in the filters table.
preg_match("|^node/(\d+)(/edit)$|", $_GET['q'], $match);
if (intval($match[1]) > 0) {
if (db_result(db_query('SELECT format FROM {node} WHERE nid = %d AND format = 2', $match[1]))) {
return FALSE;
}
}
}
if (variable_get('tinymce_all', 1)) {
return TRUE;
}
else {
$page_match = FALSE;
$pages = variable_get('tinymce_pages', tinymce_help('admin/settings/tinymce#pages'));
if ($pages) {
$path = drupal_get_path_alias($_GET['q']);
$regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. variable_get('site_frontpage', 'node') .'\2'), preg_quote($pages, '/')) .')$/';
$page_match = preg_match($regexp, $path);
}
return $page_match;
}
}