| 1 |
<?php
|
| 2 |
/* $Id: htmlbox.module,v 1.1.2.2 2008/07/04 09:33:00 poetro Exp $ */
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file HTMLBox WYSIWYG editor
|
| 6 |
*/
|
| 7 |
|
| 8 |
/**
|
| 9 |
* Implementation of hook_menu().
|
| 10 |
*/
|
| 11 |
function htmlbox_menu($may_cache) {
|
| 12 |
$items = array();
|
| 13 |
|
| 14 |
if ($may_cache) {
|
| 15 |
$items[] = array(
|
| 16 |
'path' => 'admin/settings/htmlbox',
|
| 17 |
'title' => t('HTMLBox settings'),
|
| 18 |
'description' => t('Visibility and button configuration for the HTMLBox.'),
|
| 19 |
'callback' => 'drupal_get_form',
|
| 20 |
'callback arguments' => 'htmlbox_admin_settings',
|
| 21 |
'type' => MENU_NORMAL_ITEM,
|
| 22 |
);
|
| 23 |
}
|
| 24 |
|
| 25 |
return $items;
|
| 26 |
}
|
| 27 |
|
| 28 |
/**
|
| 29 |
* Implementation of hook_perm().
|
| 30 |
*/
|
| 31 |
function htmlbox_perm() {
|
| 32 |
return array('access htmlbox');
|
| 33 |
}
|
| 34 |
|
| 35 |
/**
|
| 36 |
* Menu callback; display settings form.
|
| 37 |
* @return Form array.
|
| 38 |
*/
|
| 39 |
function htmlbox_admin_settings() {
|
| 40 |
$form = array();
|
| 41 |
|
| 42 |
$form['display'] = array(
|
| 43 |
'#type' => 'fieldset',
|
| 44 |
'#title' => t('Display Settings'),
|
| 45 |
'#collapsible' => TRUE,
|
| 46 |
'#collapsed' => FALSE,
|
| 47 |
);
|
| 48 |
|
| 49 |
$form['display']['node_forms'] = array(
|
| 50 |
'#type' => 'fieldset',
|
| 51 |
'#title' => t('Node forms'),
|
| 52 |
'#collapsible' => TRUE,
|
| 53 |
'#collapsed' => FALSE,
|
| 54 |
);
|
| 55 |
$form['display']['node_forms']['htmlbox_node_forms'] = array(
|
| 56 |
'#type' => 'checkboxes',
|
| 57 |
'#title' => t('Node forms'),
|
| 58 |
'#description' => t('Display the HTMLBox on the node forms above.'),
|
| 59 |
'#options' => node_get_types('names'),
|
| 60 |
'#default_value' => variable_get('htmlbox_node_forms', array()),
|
| 61 |
);
|
| 62 |
$form['display']['node_forms']['htmlbox_node_forms_body_only'] = array(
|
| 63 |
'#type' => 'checkbox',
|
| 64 |
'#title' => t('Body only'),
|
| 65 |
'#description' => t('Display the HTMLBox only on the Body element.'),
|
| 66 |
'#default_value' => variable_get('htmlbox_node_forms_body_only', 0),
|
| 67 |
);
|
| 68 |
|
| 69 |
$form['display']['htmlbox_other_forms'] = array(
|
| 70 |
'#type' => 'checkboxes',
|
| 71 |
'#title' => t('Other forms'),
|
| 72 |
'#options' => array(
|
| 73 |
'comment_form' => t('Comment form'),
|
| 74 |
'contact_mail_page' => t('Site contact form'),
|
| 75 |
'contact_mail_user' => t('User contact form'),
|
| 76 |
'taxonomy_form_vocabulary' => t('Category Vocabulary form'),
|
| 77 |
'taxonomy_form_term' => t('Category Vocabulary term form'),
|
| 78 |
'any' => t('Any other textarea'),
|
| 79 |
),
|
| 80 |
'#default_value' => variable_get('htmlbox_other_forms', array()),
|
| 81 |
);
|
| 82 |
|
| 83 |
$form['display']['htmlbox_custom_fields'] = array(
|
| 84 |
'#type' => 'textarea',
|
| 85 |
'#title' => t('Custom fields'),
|
| 86 |
'#description' => t('Comma separated textarea ids of the textareas to be converted to HTMLBox, specify it\'s ID. For example: <p><code><textarea class="form-textarea" id="edit-comment" name="comment" rows="15" cols="60"/></code></p> the id is <em>edit-comment</em>.'),
|
| 87 |
'#default_value' => variable_get('htmlbox_custom_fields', ''),
|
| 88 |
);
|
| 89 |
|
| 90 |
|
| 91 |
$buttons = _htmlbox_available_buttons();
|
| 92 |
$form['display']['htmlbox_buttons_order'] = array(
|
| 93 |
'#type' => 'textarea',
|
| 94 |
'#title' => t('Button Order'),
|
| 95 |
'#description' => t('Comma separated items from the options below. Use the words right next to the icons.') . theme('htmlbox_settings_item', $buttons),
|
| 96 |
'#default_value' => variable_get('htmlbox_buttons_order', 'bold, italic, separator_dots, hyperlink, separator_dots, ul, ol, code, separator_dots, indent, outdent, separator_dots'),
|
| 97 |
);
|
| 98 |
|
| 99 |
$form['options'] = array(
|
| 100 |
'#type' => 'fieldset',
|
| 101 |
'#title' => t('Options'),
|
| 102 |
'#collapsible' => TRUE,
|
| 103 |
'#collapsed' => TRUE,
|
| 104 |
);
|
| 105 |
|
| 106 |
$parser_available = is_readable(drupal_get_path('module', 'htmlbox') .'/htmlparser.js');
|
| 107 |
$form['options']['htmlbox_xhtml_parser'] = array(
|
| 108 |
'#type' => 'checkbox',
|
| 109 |
'#title' => t('Enable HTML to XHTML converter'),
|
| 110 |
'#description' => t('Allow the JavaScript HTML to XHTML converter. It can require more CPU power to convert the content from HTML to XHTML, which may cause the system to be less stable. Some browsers may do the conversion without using the client side JavaScript. !parser_available',
|
| 111 |
array(
|
| 112 |
'!parser_available' => $parser_available ? '' : t('To enable the XHTML converter, <a href="@download_link">donwload</a> it, and place it in the HTMLBox module\'s directory.', array('@download_link' => 'http://ejohn.org/files/htmlparser.js')),
|
| 113 |
)
|
| 114 |
),
|
| 115 |
'#default_value' => variable_get('htmlbox_xhtml_parser', 0),
|
| 116 |
'#attributes' => $parser_available ? array() : array('disabled' => 'disabled'),
|
| 117 |
);
|
| 118 |
$form['options']['htmlbox_newline_removal'] = array(
|
| 119 |
'#type' => 'checkbox',
|
| 120 |
'#title' => t('Enable newline removal'),
|
| 121 |
'#description' => t('Allow new lines (line breaks) to be removed from the (X)HTML output of the HTMLBox area. HTML new lines (<br>) will not be removed.'),
|
| 122 |
'#default_value' => variable_get('htmlbox_newline_removal', 1),
|
| 123 |
'#attributes' => $parser_available ? array() : array('disabled' => 'disabled'),
|
| 124 |
);
|
| 125 |
|
| 126 |
drupal_add_css(drupal_get_path('module', 'htmlbox') .'/htmlbox-admin.css');
|
| 127 |
drupal_add_js(drupal_get_path('module', 'htmlbox') .'/htmlbox-admin.js');
|
| 128 |
drupal_add_js(array('htmlbox' => array('order_description' => t('Drag and drop items into, and out of the box. The items can also be rearranged. The items inside the box will be used as the buttons of the HTMLBox in the same order as they appear in there.'))), 'setting');
|
| 129 |
return system_settings_form($form);
|
| 130 |
}
|
| 131 |
|
| 132 |
/**
|
| 133 |
* Helper function; get available buttons.
|
| 134 |
* @return Available HTMLBox buttons in an array.
|
| 135 |
*/
|
| 136 |
function _htmlbox_available_buttons() {
|
| 137 |
return array(
|
| 138 |
// Inline formatting
|
| 139 |
'bold' => t('Bold'),
|
| 140 |
'italic' => t('Italic'),
|
| 141 |
'underline' => t('Underline'),
|
| 142 |
'sup' => t('Superscript'),
|
| 143 |
'sub' => t('Subscript'),
|
| 144 |
|
| 145 |
// Clipboard related
|
| 146 |
'cut' => t('@option (may not work in every browser, experimental)', array('@option' => t('Cut'))),
|
| 147 |
'copy' => t('@option (may not work in every browser, experimental)', array('@option' => t('Copy'))),
|
| 148 |
'paste' => t('@option (may not work in every browser, experimental)', array('@option' => t('Paste'))),
|
| 149 |
'undo' => t('@option (may not work in every browser, experimental)', array('@option' => t('Undo'))),
|
| 150 |
'redo' => t('@option (may not work in every browser, experimental)', array('@option' => t('Redo'))),
|
| 151 |
|
| 152 |
// Align
|
| 153 |
'left' => t('Superscript'),
|
| 154 |
'right' => t('Subscript'),
|
| 155 |
'center' => t('Superscript'),
|
| 156 |
'justify' => t('Subscript'),
|
| 157 |
|
| 158 |
// Lists / blocks
|
| 159 |
'ol' => t('Ordered list'),
|
| 160 |
'ul' => t('Unordered list'),
|
| 161 |
'indent' => t('Indent'),
|
| 162 |
'outdent' => t('Outdent'),
|
| 163 |
'p' => t('Paragraph'),
|
| 164 |
'pre' => t('Preformatted'),
|
| 165 |
'code' => t('Code'),
|
| 166 |
'headers' => t('Headers (H1-H6)'),
|
| 167 |
|
| 168 |
// Inline elements
|
| 169 |
'hyperlink' => t('Link'),
|
| 170 |
'image' => t('Image'),
|
| 171 |
|
| 172 |
// Font changes
|
| 173 |
'fontsize' => t('Font size'),
|
| 174 |
'fontfamily' => t('Font family'),
|
| 175 |
'fontcolor' => t('Text color'),
|
| 176 |
'highlight' => t('Background color'),
|
| 177 |
|
| 178 |
// Misc
|
| 179 |
'html' => t('HTML source'),
|
| 180 |
'separator_basic' => t('Basic Separators'),
|
| 181 |
'separator_dots' => t('Dotted Separators'),
|
| 182 |
);
|
| 183 |
}
|
| 184 |
|
| 185 |
/**
|
| 186 |
* Render HTMLBox settings page item listing.
|
| 187 |
* @param $buttons Associated array of available buttons.
|
| 188 |
* @return Themed list of items.
|
| 189 |
*/
|
| 190 |
function theme_htmlbox_settings_item($buttons) {
|
| 191 |
$output = '<div class="htmlbox-buttons"><dl>';
|
| 192 |
foreach ($buttons as $item => $desc) {
|
| 193 |
$output .= '<dt><span class="htmlbox-'. $item .'" title="'. $desc .'"></span> '. $item .'</dt>';
|
| 194 |
$output .= '<dd>'. $desc .'</dd>';
|
| 195 |
}
|
| 196 |
$output .= '</dl></div>';
|
| 197 |
return $output;
|
| 198 |
}
|
| 199 |
|
| 200 |
/**
|
| 201 |
* Prepare the JavaScript to be added for each element.
|
| 202 |
* @return JavaScript code.
|
| 203 |
*/
|
| 204 |
function htmlbox_js_settings() {
|
| 205 |
$options = explode(',', variable_get('htmlbox_buttons_order',
|
| 206 |
'bold, italic, separator_dots, hyperlink, separator_dots, ul, ol, html, separator_dots, indent, outdent, separator_dots'));
|
| 207 |
if (count($options)) {
|
| 208 |
$js = '';
|
| 209 |
$buttons = _htmlbox_available_buttons();
|
| 210 |
foreach ($options as $option) {
|
| 211 |
$option = trim($option);
|
| 212 |
// Only add valid buttons
|
| 213 |
if (array_key_exists($option, $buttons)) {
|
| 214 |
$js .= '.button("'. $option .'")';
|
| 215 |
}
|
| 216 |
}
|
| 217 |
if (!empty($js)) {
|
| 218 |
$js = '$(this).htmlbox()'. $js .'.init();';
|
| 219 |
return $js;
|
| 220 |
}
|
| 221 |
}
|
| 222 |
return '';
|
| 223 |
}
|
| 224 |
|
| 225 |
/**
|
| 226 |
* Prepare HTMLBox attachment.
|
| 227 |
* @param $area Id of form element to attach the editor to.
|
| 228 |
* @return Array of ids the HTMLBox is attached to.
|
| 229 |
*/
|
| 230 |
function htmlbox_js_attach_editor($area = NULL) {
|
| 231 |
static $areas;
|
| 232 |
// Add the needed CSS and JS files.
|
| 233 |
if (!isset($areas)) {
|
| 234 |
drupal_add_css(drupal_get_path('module', 'htmlbox') .'/htmlbox.css');
|
| 235 |
drupal_add_js(drupal_get_path('module', 'htmlbox') .'/htmlbox.js');
|
| 236 |
if (variable_get('htmlbox_xhtml_parser', 0)) {
|
| 237 |
$parser = drupal_get_path('module', 'htmlbox') .'/htmlparser.js';
|
| 238 |
if (is_readable($parser)) {
|
| 239 |
drupal_add_js($parser);
|
| 240 |
}
|
| 241 |
}
|
| 242 |
drupal_add_js(array('htmlbox' => array('newline_removal' => variable_get('htmlbox_newline_removal', 1) == 1)), 'setting');
|
| 243 |
|
| 244 |
// Add custom textareas, as this is the initial point to add any
|
| 245 |
$areas = array();
|
| 246 |
if ($fields = variable_get('htmlbox_custom_fields', '')) {
|
| 247 |
$fields = explode(',', $fields);
|
| 248 |
foreach ($fields as $field) {
|
| 249 |
$field = trim($field);
|
| 250 |
// Add only valid IDs
|
| 251 |
if ($field && preg_match('!^[a-z][a-z\pL0-9:.\[\]_\-]*$!i', $field)) {
|
| 252 |
$areas[] = $field;
|
| 253 |
}
|
| 254 |
}
|
| 255 |
|
| 256 |
}
|
| 257 |
}
|
| 258 |
if (!empty($area)) {
|
| 259 |
$areas[] = $area;
|
| 260 |
}
|
| 261 |
return $areas;
|
| 262 |
}
|
| 263 |
|
| 264 |
/**
|
| 265 |
* Implementation of hook_form_alter().
|
| 266 |
* Attach HTMLBox to various textareas.
|
| 267 |
*/
|
| 268 |
function htmlbox_form_alter($form_id, &$form) {
|
| 269 |
if (user_access('access htmlbox')) {
|
| 270 |
$attach_to = '';
|
| 271 |
$other_forms = array_filter(variable_get('htmlbox_other_forms', array()));
|
| 272 |
$node_forms = array_filter(variable_get('htmlbox_node_forms', array()));
|
| 273 |
$possible_forms = array(
|
| 274 |
'comment_form',
|
| 275 |
'contact_mail_page',
|
| 276 |
'contact_mail_user',
|
| 277 |
'taxonomy_form_vocabulary',
|
| 278 |
'taxonomy_form_term',
|
| 279 |
);
|
| 280 |
|
| 281 |
if ($other_forms['any'] && $form['#id'] != 'node-form' && !in_array($form_id, $possible_forms)) {
|
| 282 |
// Prepare the form for build to have all the names we need.
|
| 283 |
$built = form_builder($form_id, $form);
|
| 284 |
$attach_to = _htmlbox_textarea_search($built);
|
| 285 |
}
|
| 286 |
else if ($form['#id'] == 'node-form' && array_key_exists($form['type']['#value'], $node_forms)) {
|
| 287 |
if (variable_get('htmlbox_node_forms_body_only', 0)) {
|
| 288 |
$attach_to = 'edit-body';
|
| 289 |
}
|
| 290 |
else {
|
| 291 |
// Prepare the form for build to have all the names we need.
|
| 292 |
$built = form_builder($form_id, $form);
|
| 293 |
$attach_to = _htmlbox_textarea_search($built);
|
| 294 |
}
|
| 295 |
}
|
| 296 |
else if (array_key_exists($form_id, $other_forms)) {
|
| 297 |
// Prepare to handle custom forms
|
| 298 |
switch ($form_id) {
|
| 299 |
case 'comment_form':
|
| 300 |
$attach_to = 'edit-comment';
|
| 301 |
break;
|
| 302 |
case 'contact_mail_page':
|
| 303 |
case 'contact_mail_user':
|
| 304 |
$attach_to = 'edit-message';
|
| 305 |
break;
|
| 306 |
case 'taxonomy_form_vocabulary':
|
| 307 |
case 'taxonomy_form_term':
|
| 308 |
$attach_to = 'edit-description';
|
| 309 |
default:
|
| 310 |
break;
|
| 311 |
}
|
| 312 |
}
|
| 313 |
|
| 314 |
if (!empty($attach_to)) {
|
| 315 |
if (is_array($attach_to)) {
|
| 316 |
foreach ($attach_to as $item) {
|
| 317 |
htmlbox_js_attach_editor($item);
|
| 318 |
}
|
| 319 |
}
|
| 320 |
else {
|
| 321 |
htmlbox_js_attach_editor($attach_to);
|
| 322 |
}
|
| 323 |
}
|
| 324 |
}
|
| 325 |
}
|
| 326 |
|
| 327 |
/**
|
| 328 |
* Search for textareas in the form.
|
| 329 |
* @return Array of textarea ids.
|
| 330 |
*/
|
| 331 |
function _htmlbox_textarea_search($elements) {
|
| 332 |
$textareas = array();
|
| 333 |
if (!isset($elements['#children'])) {
|
| 334 |
// If we have children, do a recursive search
|
| 335 |
$children = element_children($elements);
|
| 336 |
foreach ($children as $key) {
|
| 337 |
if ($areas = _htmlbox_textarea_search($elements[$key])) {
|
| 338 |
$textareas = array_merge($textareas, $areas);
|
| 339 |
}
|
| 340 |
}
|
| 341 |
|
| 342 |
// Add the found textare IDs to the list
|
| 343 |
if ($elements['#type'] == 'textarea') {
|
| 344 |
$textareas[] = $elements['#id'];
|
| 345 |
}
|
| 346 |
}
|
| 347 |
return $textareas;
|
| 348 |
}
|
| 349 |
|
| 350 |
/**
|
| 351 |
* Implementation of hook_footer().
|
| 352 |
*/
|
| 353 |
function htmlbox_footer() {
|
| 354 |
if ($areas = htmlbox_js_attach_editor()) {
|
| 355 |
if (count($areas) && $js = htmlbox_js_settings()) {
|
| 356 |
// Prepare CSS IDs from the given list of textareas, only include unique IDs
|
| 357 |
$items = '#'. implode(', #', array_unique($areas));
|
| 358 |
drupal_add_js('$(function () { $("'. $items .'").each(function () {'. $js .'})});', 'inline', 'footer');
|
| 359 |
}
|
| 360 |
}
|
| 361 |
}
|