| 1 |
<?php |
<?php |
| 2 |
// $Id: hierarchical_select.module,v 1.142 2008/11/30 01:15:01 wimleers Exp $ |
// $Id: hierarchical_select.module,v 1.143 2008/11/30 01:56:35 wimleers Exp $ |
| 3 |
|
|
| 4 |
/** |
/** |
| 5 |
* @file |
* @file |
| 18 |
/** |
/** |
| 19 |
* Implementation of hook_menu(). |
* Implementation of hook_menu(). |
| 20 |
*/ |
*/ |
| 21 |
function hierarchical_select_menu($may_cache) { |
function hierarchical_select_menu() { |
| 22 |
if ($may_cache) { |
$items['hierarchical_select_json'] = array( |
| 23 |
$items[] = array( |
'page callback' => 'hierarchical_select_json', |
| 24 |
'path' => 'hierarchical_select_json', |
'type' => MENU_CALLBACK, |
| 25 |
'callback' => 'hierarchical_select_json', |
// TODO: Needs improvements. Ideally, this would inherit the permissions |
| 26 |
'type' => MENU_CALLBACK, |
// of the form the Hierarchical Select was in. |
| 27 |
// TODO: Needs improvements. Ideally, this would inherit the permissions |
'access callback' => TRUE, |
| 28 |
// of the form the Hierarchical Select was in. |
); |
| 29 |
'access' => TRUE, |
$items['admin/settings/hierarchical_select'] = array( |
| 30 |
); |
'title' => 'Hierarchical Select', |
| 31 |
$items[] = array( |
'description' => 'Configure site-wide settings for the Hierarchical Select form element.', |
| 32 |
'path' => 'admin/settings/hierarchical_select', |
'access arguments' => array('administer site configuration'), |
| 33 |
'title' => t('Hierarchical Select'), |
'page callback' => 'drupal_get_form', |
| 34 |
'description' => t('Configure site-wide settings for the Hierarchical Select form element.'), |
'page arguments' => array('hierarchical_select_admin_settings'), |
| 35 |
'callback' => 'drupal_get_form', |
'type' => MENU_NORMAL_ITEM, |
| 36 |
'callback arguments' => array('hierarchical_select_admin_settings'), |
'file' => 'hierarchical_select.admin.inc', |
| 37 |
'type' => MENU_NORMAL_ITEM, |
); |
| 38 |
); |
$items['admin/settings/hierarchical_select/settings'] = array( |
| 39 |
$items[] = array( |
'title' => 'Site-wide settings', |
| 40 |
'path' => 'admin/settings/hierarchical_select/settings', |
'access arguments' => array('administer site configuration'), |
| 41 |
'title' => t('Site-wide settings'), |
'weight' => -10, |
| 42 |
'weight' => -10, |
'type' => MENU_DEFAULT_LOCAL_TASK, |
| 43 |
'type' => MENU_DEFAULT_LOCAL_TASK, |
'file' => 'hierarchical_select.admin.inc', |
| 44 |
); |
); |
| 45 |
$items[] = array( |
$items['admin/settings/hierarchical_select/configs'] = array( |
| 46 |
'path' => 'admin/settings/hierarchical_select/configs', |
'title' => 'Configurations', |
| 47 |
'title' => t('Configurations'), |
'description' => 'All available Hierarchical Select configurations.', |
| 48 |
'description' => t('All available Hierarchical Select configurations.'), |
'access arguments' => array('administer site configuration'), |
| 49 |
'callback' => 'hierarchical_select_admin_configs', |
'page callback' => 'hierarchical_select_admin_configs', |
| 50 |
'type' => MENU_LOCAL_TASK, |
'type' => MENU_LOCAL_TASK, |
| 51 |
); |
'file' => 'hierarchical_select.admin.inc', |
| 52 |
$items[] = array( |
); |
| 53 |
'path' => 'admin/settings/hierarchical_select/implementations', |
$items['admin/settings/hierarchical_select/implementations'] = array( |
| 54 |
'title' => t('Implementations'), |
'title' => 'Implementations', |
| 55 |
'description' => t('Features of each Hierarchical Select implementation.'), |
'description' => 'Features of each Hierarchical Select implementation.', |
| 56 |
'callback' => 'hierarchical_select_admin_implementations', |
'access arguments' => array('administer site configuration'), |
| 57 |
'type' => MENU_LOCAL_TASK, |
'page callback' => 'hierarchical_select_admin_implementations', |
| 58 |
); |
'type' => MENU_LOCAL_TASK, |
| 59 |
} |
'file' => 'hierarchical_select.admin.inc', |
| 60 |
else { |
); |
| 61 |
// Work-around for bug in Drupal 5 (fixed in Drupal 5.8). |
$items['admin/settings/hierarchical_select/export/%hierarchical_select_config_id'] = array( |
| 62 |
// See http://drupal.org/node/109459. |
'title' => 'Export', |
| 63 |
global $user; |
'access arguments' => array('administer site configuration'), |
| 64 |
if (!isset($user->theme)) { |
'page callback' => 'drupal_get_form', |
| 65 |
$user->theme = variable_get('theme_default', 'garland'); |
'page arguments' => array('hierarchical_select_admin_export', 4), |
| 66 |
} |
'type' => MENU_LOCAL_TASK, |
| 67 |
|
'file' => 'hierarchical_select.admin.inc', |
| 68 |
if (arg(0) == 'admin' && arg(1) == 'settings' && arg(2) == 'hierarchical_select') { |
); |
| 69 |
require_once(drupal_get_path('module', 'hierarchical_select') .'/hierarchical_select.admin.inc'); |
$items['admin/settings/hierarchical_select/import/%hierarchical_select_config_id'] = array( |
| 70 |
|
'title' => 'Import', |
| 71 |
if (in_array(arg(3), array('export', 'import'))) { |
'access arguments' => array('administer site configuration'), |
| 72 |
require_once(drupal_get_path('module', 'hierarchical_select') .'/includes/common.inc'); |
'page callback' => 'drupal_get_form', |
| 73 |
$items[] = array( |
'page arguments' => array('hierarchical_select_admin_import', 4), |
| 74 |
'path' => 'admin/settings/hierarchical_select/export/'. arg(4), |
'type' => MENU_LOCAL_TASK, |
| 75 |
'title' => t('Export'), |
'file' => 'hierarchical_select.admin.inc', |
| 76 |
'callback' => 'drupal_get_form', |
); |
| 77 |
'callback arguments' => array('hierarchical_select_admin_export', arg(4)), |
|
|
'type' => MENU_LOCAL_TASK, |
|
|
); |
|
|
$items[] = array( |
|
|
'path' => 'admin/settings/hierarchical_select/import/'. arg(4), |
|
|
'title' => t('Import'), |
|
|
'callback' => 'drupal_get_form', |
|
|
'callback arguments' => array('hierarchical_select_admin_import', arg(4)), |
|
|
'type' => MENU_LOCAL_TASK, |
|
|
); |
|
|
} |
|
|
} |
|
|
} |
|
| 78 |
return $items; |
return $items; |
| 79 |
} |
} |
| 80 |
|
|
| 81 |
/** |
/** |
| 82 |
* Implementation of hook_form_alter(). |
* Implementation of hook_form_alter(). |
| 83 |
*/ |
*/ |
| 84 |
function hierarchical_select_form_alter($form_id, &$form) { |
function hierarchical_select_form_alter(&$form, &$form_state, $form_id) { |
| 85 |
if (_hierarchical_select_form_has_hierarchical_select($form)) { |
if (_hierarchical_select_form_has_hierarchical_select($form)) { |
| 86 |
$form['#after_build'][] = 'hierarchical_select_after_build'; |
$form['#after_build'][] = 'hierarchical_select_after_build'; |
| 87 |
} |
} |
| 93 |
function hierarchical_select_elements() { |
function hierarchical_select_elements() { |
| 94 |
$type['hierarchical_select'] = array( |
$type['hierarchical_select'] = array( |
| 95 |
'#input' => TRUE, |
'#input' => TRUE, |
| 96 |
'#process' => array('hierarchical_select_process' => array()), |
'#process' => array('hierarchical_select_process'), |
| 97 |
'#config' => array( |
'#config' => array( |
| 98 |
'module' => 'some_module', |
'module' => 'some_module', |
| 99 |
'params' => array(), |
'params' => array(), |
| 141 |
$current = drupal_get_installed_schema_version('hierarchical_select'); |
$current = drupal_get_installed_schema_version('hierarchical_select'); |
| 142 |
|
|
| 143 |
$up_to_date = (end($updates) == $current); |
$up_to_date = (end($updates) == $current); |
| 144 |
$jquery_update_v2 = (file_exists(drupal_get_path('module', 'jquery_update') .'/compat.js')); |
|
|
$jquery_interface = module_exists('jquery_interface'); |
|
| 145 |
$hierarchical_select_weight = db_result(db_query("SELECT weight FROM {system} WHERE type = 'module' AND name = 'hierarchical_select'")); |
$hierarchical_select_weight = db_result(db_query("SELECT weight FROM {system} WHERE type = 'module' AND name = 'hierarchical_select'")); |
| 146 |
$core_overriding_modules = array('hs_book', 'hs_menu', 'hs_taxonomy'); |
$core_overriding_modules = array('hs_book', 'hs_menu', 'hs_taxonomy'); |
| 147 |
$path_errors = array(); |
$path_errors = array(); |
| 161 |
$weight_errors[] = t('!module (!weight)', array('!module' => $module_info['name'], '!weight' => $weight)); |
$weight_errors[] = t('!module (!weight)', array('!module' => $module_info['name'], '!weight' => $weight)); |
| 162 |
} |
} |
| 163 |
} |
} |
|
|
|
| 164 |
|
|
| 165 |
if ($up_to_date && $jquery_update_v2 && !$jquery_interface && !count($path_errors) && !count($weight_errors)) { |
if ($up_to_date && !count($path_errors) && !count($weight_errors)) { |
| 166 |
$value = t('All updates installed. jQuery Update 2.x installed. Implementation modules are installed correctly.'); |
$value = t('All updates installed. Implementation modules are installed correctly.'); |
| 167 |
$description = ''; |
$description = ''; |
| 168 |
$severity = REQUIREMENT_OK; |
$severity = REQUIREMENT_OK; |
| 169 |
} |
} |
|
elseif (!$up_to_date) { |
|
|
$value = t('Not all updates installed!'); |
|
|
$description = t('Please run update.php to install the latest updates! |
|
|
You have installed update !installed_update, but the latest update is |
|
|
!latest_update!', |
|
|
array( |
|
|
'!installed_update' => $current, |
|
|
'!latest_update' => end($updates), |
|
|
) |
|
|
); |
|
|
$severity = REQUIREMENT_ERROR; |
|
|
} |
|
|
elseif (!$jquery_update_v2) { |
|
|
$value = t('jQuery Update 1.x installed!'); |
|
|
$description = t('Please upgrade to jQuery Update 2.x! jQuery Update |
|
|
1.x contains jQuery 1.1.x, which is incompatible with the Javascript |
|
|
code of Hierarchical Select!' |
|
|
); |
|
|
$severity = REQUIREMENT_ERROR; |
|
|
} |
|
|
elseif ($jquery_interface) { |
|
|
$value = t('jQuery Interface installed!'); |
|
|
$description = t('Please disable and uninstall jQuery Interface, as it |
|
|
is incompatible with jQuery Update 2. It is very buggy anyway and any |
|
|
module that uses it should upgrade to jQuery UI.' |
|
|
); |
|
|
$severity = REQUIREMENT_ERROR; |
|
|
} |
|
| 170 |
elseif ($path_errors) { |
elseif ($path_errors) { |
| 171 |
$value = t('Modules incorrectly installed!'); |
$value = t('Modules incorrectly installed!'); |
| 172 |
$description = t( |
$description = t( |
| 187 |
) .':'. theme('item_list', $weight_errors); |
) .':'. theme('item_list', $weight_errors); |
| 188 |
$severity = REQUIREMENT_ERROR; |
$severity = REQUIREMENT_ERROR; |
| 189 |
} |
} |
| 190 |
|
else { |
| 191 |
|
$value = t('Not all updates installed!'); |
| 192 |
|
$description = t('Please run update.php to install the latest updates! |
| 193 |
|
You have installed update !installed_update, but the latest update is |
| 194 |
|
!latest_update!', |
| 195 |
|
array( |
| 196 |
|
'!installed_update' => $current, |
| 197 |
|
'!latest_update' => end($updates), |
| 198 |
|
) |
| 199 |
|
); |
| 200 |
|
$severity = REQUIREMENT_ERROR; |
| 201 |
|
} |
| 202 |
|
|
| 203 |
$requirements['hierarchical_select'] = array( |
$requirements['hierarchical_select'] = array( |
| 204 |
'title' => t('Hierarchical Select'), |
'title' => t('Hierarchical Select'), |
| 211 |
return $requirements; |
return $requirements; |
| 212 |
} |
} |
| 213 |
|
|
| 214 |
|
/** |
| 215 |
|
* Implementation of hook_theme(). |
| 216 |
|
*/ |
| 217 |
|
function hierarchical_select_theme() { |
| 218 |
|
return array( |
| 219 |
|
'hierarchical_select' => array( |
| 220 |
|
'file' => 'includes/theme.inc', |
| 221 |
|
'arguments' => array('element' => NULL), |
| 222 |
|
), |
| 223 |
|
'hierarchical_select_select' => array( |
| 224 |
|
'file' => 'includes/theme.inc', |
| 225 |
|
'arguments' => array('element' => NULL), |
| 226 |
|
), |
| 227 |
|
'hierarchical_select_textfield' => array( |
| 228 |
|
'file' => 'includes/theme.inc', |
| 229 |
|
'arguments' => array('element' => NULL), |
| 230 |
|
), |
| 231 |
|
'hierarchical_select_dropbox_table' => array( |
| 232 |
|
'file' => 'includes/theme.inc', |
| 233 |
|
'arguments' => array('element' => NULL), |
| 234 |
|
), |
| 235 |
|
'hierarchical_select_common_config_form_level_labels' => array( |
| 236 |
|
'file' => 'includes/theme.inc', |
| 237 |
|
'arguments' => array('form' => NULL), |
| 238 |
|
), |
| 239 |
|
'hierarchical_select_common_config_form_editability' => array( |
| 240 |
|
'file' => 'includes/theme.inc', |
| 241 |
|
'arguments' => array('form' => NULL), |
| 242 |
|
), |
| 243 |
|
); |
| 244 |
|
} |
| 245 |
|
|
| 246 |
|
|
| 247 |
//---------------------------------------------------------------------------- |
//---------------------------------------------------------------------------- |
| 248 |
// Menu callbacks. |
// Menu system callbacks. |
| 249 |
|
|
| 250 |
|
/** |
| 251 |
|
* Wildcard loader for Hierarchical Select config ID's. |
| 252 |
|
*/ |
| 253 |
|
function hierarchical_select_config_id_load($config_id) { |
| 254 |
|
if (empty($config_id)) { |
| 255 |
|
return FALSE; |
| 256 |
|
} |
| 257 |
|
|
| 258 |
|
// E.g.: extract "content_taxonomy" from "content-taxonomy_field_somefield". |
| 259 |
|
$parts = explode('_', $config_id); |
| 260 |
|
$module = str_replace(array('-'), array('_'), $parts[0]); |
| 261 |
|
return in_array($config_id, array_keys(module_invoke($module, 'hierarchical_select_config_info'))); |
| 262 |
|
} |
| 263 |
|
|
| 264 |
/** |
/** |
| 265 |
* Menu callback; format=text/json; generates and outputs the appropriate HTML. |
* Menu callback; format=text/json; generates and outputs the appropriate HTML. |
| 273 |
|
|
| 274 |
// Collect all necessary variables. |
// Collect all necessary variables. |
| 275 |
$cached = cache_get($hs_form_build_id, 'cache'); |
$cached = cache_get($hs_form_build_id, 'cache'); |
| 276 |
$storage = unserialize($cached->data); |
$storage = $cached->data; |
| 277 |
|
|
| 278 |
// Ensure that the form id in the POST array is the same as the one of the |
// Ensure that the form id in the POST array is the same as the one of the |
| 279 |
// stored parameters of the original form. For 99% of the forms, this step |
// stored parameters of the original form. For 99% of the forms, this step |
| 287 |
} |
} |
| 288 |
|
|
| 289 |
// Retrieve and process the form. |
// Retrieve and process the form. |
| 290 |
|
$form_state = &$storage['parameters'][1]; |
| 291 |
|
if (!empty($storage['file'])) { |
| 292 |
|
require_once($storage['file']); |
| 293 |
|
} |
| 294 |
$form = call_user_func_array('drupal_retrieve_form', $storage['parameters']); |
$form = call_user_func_array('drupal_retrieve_form', $storage['parameters']); |
| 295 |
drupal_prepare_form($form_id, $form); |
drupal_prepare_form($form_id, $form, $form_state); |
| 296 |
|
$form['#post'] = $_POST; |
| 297 |
|
$form = form_builder($form_id, $form, $form_state); |
| 298 |
|
|
| 299 |
// Render only the relevant part of the form (i.e. the hierarchical_select |
// Render only the relevant part of the form (i.e. the hierarchical_select |
| 300 |
// form item that has triggered this AJAX callback). |
// form item that has triggered this AJAX callback). |
| 330 |
/** |
/** |
| 331 |
* Hierarchical select form element type #process callback. |
* Hierarchical select form element type #process callback. |
| 332 |
*/ |
*/ |
| 333 |
function hierarchical_select_process($element) { |
function hierarchical_select_process($element, $edit, $form_state, $form) { |
| 334 |
static $hsid; |
static $hsid; |
| 335 |
|
|
| 336 |
if (!isset($hsid)) { |
if (!isset($hsid)) { |
| 604 |
// is set to 'label_0' after an "Add" operation. When $element['#post'] is |
// is set to 'label_0' after an "Add" operation. When $element['#post'] is |
| 605 |
// NOT unset, the corresponding value in $element['#post'] will be used |
// NOT unset, the corresponding value in $element['#post'] will be used |
| 606 |
// instead of the default value that was set. This is undesired behavior. |
// instead of the default value that was set. This is undesired behavior. |
| 607 |
unset($element['#post']); |
// TODO: find a work-around for this in D6. |
| 608 |
|
// unset($element['#post']); |
| 609 |
|
|
| 610 |
// Finally, calculate the return value of this hierarchical_select form |
// Finally, calculate the return value of this hierarchical_select form |
| 611 |
// element. This will be set in _hierarchical_select_validate(). (If we'd |
// element. This will be set in _hierarchical_select_validate(). (If we'd |
| 615 |
// Add a validate callback, which will: |
// Add a validate callback, which will: |
| 616 |
// - validate that the dropbox limit was not exceeded. |
// - validate that the dropbox limit was not exceeded. |
| 617 |
// - set the return value of this form element. |
// - set the return value of this form element. |
| 618 |
$element['#validate'] = array('_hierarchical_select_validate' => array()); |
$element['#element_validate'] = array('_hierarchical_select_validate'); |
| 619 |
|
|
| 620 |
if (HS_DEVELOPER_MODE) { |
if (HS_DEVELOPER_MODE) { |
| 621 |
$element['log'] = array('#type' => 'value', '#value' => _hierarchical_select_log(NULL, TRUE)); |
$element['log'] = array('#type' => 'value', '#value' => _hierarchical_select_log(NULL, TRUE)); |
| 640 |
return $element; |
return $element; |
| 641 |
} |
} |
| 642 |
|
|
| 643 |
/** |
/** |
| 644 |
* Hierarchical select form element type #after_build callback. |
* Hierarchical select form element type #after_build callback. |
| 645 |
*/ |
*/ |
| 646 |
function hierarchical_select_after_build($form, $form_values) { |
function hierarchical_select_after_build($form, &$form_state) { |
| 647 |
$names = _hierarchical_select_store_name(NULL, NULL, TRUE); |
$names = _hierarchical_select_store_name(NULL, NULL, TRUE); |
| 648 |
|
|
| 649 |
if (!isset($_POST['hs_form_build_id']) && count($names)) { |
if (!isset($_POST['hs_form_build_id']) && count($names)) { |
| 650 |
$parameters = (isset($form['#parameters'])) ? $form['#parameters'] : array(); |
$parameters = (isset($form['#parameters'])) ? $form['#parameters'] : array(); |
| 651 |
|
$menu_item = menu_get_item(); |
| 652 |
|
|
| 653 |
// Collect information in this array, which will be used in dynamic form |
// Collect information in this array, which will be used in dynamic form |
| 654 |
// updates, to … |
// updates, to … |
| 657 |
'parameters' => $parameters, |
'parameters' => $parameters, |
| 658 |
// … determine which part of $form should be rendered. |
// … determine which part of $form should be rendered. |
| 659 |
'#names' => $names, |
'#names' => $names, |
| 660 |
|
// … include the file in which the form function lives. |
| 661 |
|
'file' => $menu_item['file'], |
| 662 |
); |
); |
| 663 |
|
|
| 664 |
// Store the information needed for dynamic form updates in the cache, so |
// Store the information needed for dynamic form updates in the cache, so |
| 666 |
// render part of the form). |
// render part of the form). |
| 667 |
$expire = max(ini_get('session.cookie_lifetime'), 86400); |
$expire = max(ini_get('session.cookie_lifetime'), 86400); |
| 668 |
$hs_form_build_id = 'hs_form_'. md5(mt_rand()); |
$hs_form_build_id = 'hs_form_'. md5(mt_rand()); |
| 669 |
cache_set($hs_form_build_id, 'cache', serialize($storage), $expire); |
cache_set($hs_form_build_id, $storage, 'cache', $expire); |
|
|
|
| 670 |
} |
} |
| 671 |
elseif (isset($_POST['hs_form_build_id'])) { |
elseif (isset($_POST['hs_form_build_id'])) { |
| 672 |
// Don't generate a new hs_form_build_id if this is a re-rendering of the |
// Don't generate a new hs_form_build_id if this is a re-rendering of the |
| 683 |
// form_builder() has all info it needs to generate #name and #id. |
// form_builder() has all info it needs to generate #name and #id. |
| 684 |
'#parents' => array('hs_form_build_id'), |
'#parents' => array('hs_form_build_id'), |
| 685 |
); |
); |
| 686 |
$form['hs_form_build_id'] = form_builder($form['form_id']['#value'], $form_element); |
$form['hs_form_build_id'] = form_builder($form['form_id']['#value'], $form_element, $form_state); |
| 687 |
|
|
| 688 |
// Pass the hs_form_build_id to a custom submit function that will clear |
// Pass the hs_form_build_id to a custom submit function that will clear |
| 689 |
// the associated values from the cache. |
// the associated values from the cache. |
| 690 |
$form['#submit']['_hierarchical_select_submit'] = array($_POST['hs_form_build_id']); |
$form_state['hs_form_build_id'] = $_POST['hs_form_build_id']; |
| 691 |
|
$form['#submit'][] = '_hierarchical_select_submit'; |
| 692 |
|
|
| 693 |
return $form; |
return $form; |
| 694 |
} |
} |
| 695 |
|
|
| 696 |
/** |
/** |
| 697 |
* Hierarchical select form element #validate callback. |
* Hierarchical select form element #element_validate callback. |
| 698 |
*/ |
*/ |
| 699 |
function _hierarchical_select_validate(&$element) { |
function _hierarchical_select_validate(&$element, &$form_state) { |
| 700 |
// If the dropbox is enabled and a dropbox limit is configured, check if |
// If the dropbox is enabled and a dropbox limit is configured, check if |
| 701 |
// this limit is not exceeded. |
// this limit is not exceeded. |
| 702 |
$config = $element['#config']; |
$config = $element['#config']; |
| 703 |
if ($config['dropbox']['status']) { |
if ($config['dropbox']['status']) { |
| 704 |
if ($config['dropbox']['limit'] > 0) { // Zero as dropbox limit means no limit. |
if ($config['dropbox']['limit'] > 0) { // Zero as dropbox limit means no limit. |
| 705 |
// TRICKY: #validate is not called upon the initial rendering (i.e. it |
// TRICKY: #element_validate is not called upon the initial rendering |
| 706 |
// is assumed that the default value is valid). However, Hierarchical |
// (i.e. it is assumed that the default value is valid). However, |
| 707 |
// Select's config can influence the validity (i.e. how many selections |
// Hierarchical Select's config can influence the validity (i.e. how |
| 708 |
// may be added to the dropbox). This means it's possible the user has |
// many selections may be added to the dropbox). This means it's |
| 709 |
// actually selected too many items without being notified of this. |
// possible the user has actually selected too many items without being |
| 710 |
|
// notified of this. |
| 711 |
$lineage_count = count($element['#value']['dropbox']['hidden']['lineages_selections']); |
$lineage_count = count($element['#value']['dropbox']['hidden']['lineages_selections']); |
| 712 |
if ($lineage_count > $config['dropbox']['limit']) { |
if ($lineage_count > $config['dropbox']['limit']) { |
| 713 |
// TRICKY: this should propagate the error down to the children, but |
// TRICKY: this should propagate the error down to the children, but |
| 736 |
// detects as an empty form value. |
// detects as an empty form value. |
| 737 |
$value = (empty($element['#return_value'])) ? 0 : $element['#return_value']; |
$value = (empty($element['#return_value'])) ? 0 : $element['#return_value']; |
| 738 |
$element['#value'] = $value; |
$element['#value'] = $value; |
| 739 |
form_set_value($element, $value); |
form_set_value($element, $value, $form_state); |
| 740 |
|
|
| 741 |
// We have to check again for errors. This line is taken litterally from |
// We have to check again for errors. This line is taken litterally from |
| 742 |
// form.inc, so it works in an identical way. |
// form.inc, so it works in an identical way. |
| 748 |
/** |
/** |
| 749 |
* Hierarchical select form element #submit callback. |
* Hierarchical select form element #submit callback. |
| 750 |
*/ |
*/ |
| 751 |
function _hierarchical_select_submit($form_id, $form_values, $hs_form_build_id) { |
function _hierarchical_select_submit($form, &$form_state) { |
| 752 |
// Delete the stored form information when the form is submitted. |
// Delete the stored form information when the form is submitted. |
| 753 |
cache_clear_all($hs_form_build_id, 'cache'); |
cache_clear_all($form_state['hs_form_build_id'], 'cache'); |
| 754 |
} |
} |
| 755 |
|
|
| 756 |
|
|
| 989 |
'#type' => 'select', |
'#type' => 'select', |
| 990 |
'#options' => $hierarchy->levels[$depth], |
'#options' => $hierarchy->levels[$depth], |
| 991 |
'#default_value' => $selected_item, |
'#default_value' => $selected_item, |
|
// We need to skip the check of valid options, because they may be |
|
|
// modified after each update. |
|
|
'#DANGEROUS_SKIP_CHECK' => TRUE, |
|
| 992 |
// Use a #theme callback to prevent the select from being wrapped in a |
// Use a #theme callback to prevent the select from being wrapped in a |
| 993 |
// div. This simplifies the CSS and JS code. Also sets a special class |
// div. This simplifies the CSS and JS code. Also sets a special class |
| 994 |
// on the level label option, if any, to make level label styles |
// on the level label option, if any, to make level label styles |
| 2027 |
function _hierarchical_select_dropbox_lineage_item_get_value($item) { |
function _hierarchical_select_dropbox_lineage_item_get_value($item) { |
| 2028 |
return $item['value']; |
return $item['value']; |
| 2029 |
} |
} |
|
|
|
|
/** |
|
|
* This is an altered clone of form_select_options(). The reason: I need to be |
|
|
* able to set a class on an option element if it contains a level label, to |
|
|
* allow for level label styles. |
|
|
* Secondly, I need to be able to mark childless items (i.e. "option" |
|
|
* elements). |
|
|
*/ |
|
|
function _hierarchical_select_options($element) { |
|
|
if (!isset($choices)) { |
|
|
$choices = $element['#options']; |
|
|
} |
|
|
// array_key_exists() accommodates the rare event where $element['#value'] is NULL. |
|
|
// isset() fails in this situation. |
|
|
$value_valid = isset($element['#value']) || array_key_exists('#value', $element); |
|
|
$value_is_array = is_array($element['#value']); |
|
|
$options = ''; |
|
|
foreach ($choices as $key => $choice) { |
|
|
$key = (string)$key; |
|
|
if ($value_valid && (!$value_is_array && (string)$element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) { |
|
|
$selected = ' selected="selected"'; |
|
|
} |
|
|
else { |
|
|
$selected = ''; |
|
|
} |
|
|
|
|
|
// If an option DOES NOT have child info, then it's a special option: |
|
|
// - label_\d+ (level label) |
|
|
// - none ("<none>") |
|
|
// - create_new_item ("<create new item>") |
|
|
// Only when it's a level label, we have to add a class to this option. |
|
|
if (!isset($element['#childinfo'][$key])) { |
|
|
$class = (preg_match('/label_\d+/', $key)) ? ' level-label' : ''; |
|
|
} |
|
|
else { |
|
|
$class = ($element['#childinfo'][$key] == 0) ? 'has-no-children' : 'has-children'; |
|
|
} |
|
|
|
|
|
$options .= '<option value="'. check_plain($key) .'" class="'. $class .'"'. $selected .'>'. check_plain($choice) .'</option>'; |
|
|
} |
|
|
return $options; |
|
|
} |
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------- |
|
|
// Theming callbacks. |
|
|
|
|
|
/** |
|
|
* @ingroup themeable |
|
|
* @{ |
|
|
*/ |
|
|
|
|
|
/** |
|
|
* Format a hierarchical select. |
|
|
* |
|
|
* @param $element |
|
|
* An associative array containing the properties of the element. |
|
|
* @return |
|
|
* A themed HTML string representing the form element. |
|
|
*/ |
|
|
function theme_hierarchical_select($element) { |
|
|
$output = ''; |
|
|
|
|
|
// Update $element['#attributes']['class']. |
|
|
$hsid = $element['hsid']['#value']; |
|
|
$level_labels_style = variable_get('hierarchical_select_level_labels_style', 'none'); |
|
|
$classes = array( |
|
|
'hierarchical-select-wrapper', |
|
|
"hierarchical-select-level-labels-style-$level_labels_style", |
|
|
); |
|
|
$element['#attributes']['class'] .= ' '. implode(' ', $classes); |
|
|
$element['#attributes']['id'] = "hierarchical-select-$hsid-wrapper"; |
|
|
|
|
|
$output .= theme( |
|
|
'form_element', |
|
|
array( |
|
|
'#title' => $element['#title'], |
|
|
'#description' => $element['#description'], |
|
|
'#id' => $element['#id'], |
|
|
'#required' => $element['#required'], |
|
|
'#error' => $element['#error'], |
|
|
), |
|
|
'<div '. drupal_attributes($element['#attributes']) .'>'. $element['#children'] .'</div>' |
|
|
); |
|
|
|
|
|
return $output; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Format a select in the .hierarchial-select div: prevent it from being |
|
|
* wrapped in a div. This simplifies the CSS and JS code. |
|
|
* |
|
|
* @param $element |
|
|
* An associative array containing the properties of the element. |
|
|
* @return |
|
|
* A themed HTML string representing the form element. |
|
|
*/ |
|
|
function theme_hierarchical_select_select($element) { |
|
|
$select = ''; |
|
|
$size = $element['#size'] ? ' size="'. $element['#size'] .'"' : ''; |
|
|
_form_set_class($element, array('form-select')); |
|
|
$multiple = isset($element['#multiple']) && $element['#multiple']; |
|
|
return '<select name="'. $element['#name'] .''. ($multiple ? '[]' : '') .'"'. ($multiple ? ' multiple="multiple" ' : '') . drupal_attributes($element['#attributes']) .' id="'. $element['#id'] .'" '. $size .'>'. _hierarchical_select_options($element) .'</select>'; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Format a textfield in the .hierarchial-select div: prevent it from being |
|
|
* wrapped in a div. This simplifies the CSS and JS code. |
|
|
* |
|
|
* @param $element |
|
|
* An associative array containing the properties of the element. |
|
|
* @return |
|
|
* A themed HTML string representing the form element. |
|
|
*/ |
|
|
function theme_hierarchical_select_textfield($element) { |
|
|
$size = $element['#size'] ? ' size="'. $element['#size'] .'"' : ''; |
|
|
$class = array('form-text'); |
|
|
$extra = ''; |
|
|
$output = ''; |
|
|
|
|
|
if ($element['#autocomplete_path']) { |
|
|
drupal_add_js('misc/autocomplete.js'); |
|
|
$class[] = 'form-autocomplete'; |
|
|
$extra = '<input class="autocomplete" type="hidden" id="'. $element['#id'] .'-autocomplete" value="'. check_url(url($element['#autocomplete_path'], NULL, NULL, TRUE)) .'" disabled="disabled" />'; |
|
|
} |
|
|
_form_set_class($element, $class); |
|
|
|
|
|
if (isset($element['#field_prefix'])) { |
|
|
$output .= '<span class="field-prefix">'. $element['#field_prefix'] .'</span> '; |
|
|
} |
|
|
|
|
|
$output .= '<input type="text" maxlength="'. $element['#maxlength'] .'" name="'. $element['#name'] .'" id="'. $element['#id'] .'" '. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .' />'; |
|
|
|
|
|
if (isset($element['#field_suffix'])) { |
|
|
$output .= ' <span class="field-suffix">'. $element['#field_suffix'] .'</span>'; |
|
|
} |
|
|
|
|
|
return $output . $extra; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Forms API theming callback for the dropbox. Renders the dropbox as a table. |
|
|
* |
|
|
* @param $element |
|
|
* An element for which the #theme property was set to this function. |
|
|
* @return |
|
|
* A themed HTML string. |
|
|
*/ |
|
|
function theme_hierarchical_select_dropbox_table($element) { |
|
|
$output = ''; |
|
|
|
|
|
|
|
|
$title = $element['title']['#value']; |
|
|
$separator = $element['separator']['#value']; |
|
|
$is_empty = $element['is_empty']['#value']; |
|
|
|
|
|
$separator_html = '<span class="hierarchical-select-item-separator">'. $separator .'</span>'; |
|
|
|
|
|
$output .= '<div class="dropbox">'; |
|
|
$output .= '<table>'; |
|
|
$output .= '<caption class="dropbox-title">'. $title .'</caption>'; |
|
|
$output .= '<tbody>'; |
|
|
|
|
|
if (!$is_empty) { |
|
|
// Each lineage in the dropbox corresponds to an entry in the dropbox table. |
|
|
$lineage_count = count(element_children($element['lineages'])); |
|
|
for ($x = 0; $x < $lineage_count; $x++) { |
|
|
$db_entry = $element['lineages'][$x]; |
|
|
$zebra = $db_entry['#zebra']; |
|
|
$first = $db_entry['#first']; |
|
|
$last = $db_entry['#last']; |
|
|
// The deepest level is the number of child levels minus one. This "one" |
|
|
// is the element for the "Remove" checkbox. |
|
|
$deepest_level = count(element_children($db_entry)) - 1; |
|
|
|
|
|
$output .= '<tr class="dropbox-entry '. $first .' '. $last .' '. $zebra .'">'; |
|
|
$output .= '<td>'; |
|
|
// Each item in a lineage is separated by the separator string. |
|
|
for ($depth = 0; $depth < $deepest_level; $depth++) { |
|
|
$output .= drupal_render($db_entry[$depth]); |
|
|
|
|
|
if ($depth < $deepest_level - 1) { |
|
|
$output .= $separator_html; |
|
|
} |
|
|
} |
|
|
$output .= '</td>'; |
|
|
$output .= '<td class="dropbox-remove">'. drupal_render($db_entry['remove']) .'</td>'; |
|
|
$output .= '</tr>'; |
|
|
} |
|
|
} |
|
|
else { |
|
|
$output .= '<tr class="dropbox-entry first last dropbox-is-empty"><td>'; |
|
|
$output .= t('Nothing has been selected.'); |
|
|
$output .= '</td></tr>'; |
|
|
} |
|
|
|
|
|
$output .= '</tbody>'; |
|
|
$output .= '</table>'; |
|
|
$output .= '</div>'; |
|
|
|
|
|
return $output; |
|
|
} |
|
|
|
|
|
/** |
|
|
* @} End of "ingroup themeable". |
|
|
*/ |
|