Skip to content
Snippets Groups Projects
Commit 792efe9e authored by Mark Jarrell's avatar Mark Jarrell
Browse files

#693030 Added Form API integration and example module.

parent ff9cf80c
Branches
Tags 7.x-1.8
No related merge requests found
// $Id $
Description
-------
The Multiselect module defines a CCK multiple selection field widget, to allow easier multi-selection for users.
The Multiselect module defines a CCK and Form API multiple selection field widget, to allow easier
multi-selection for users.
Multiselect was redesigned for Drupal 6 and 7 by Mark W. Jarrell (attheshow) at
Austin Peay State University (http://www.apsu.edu).
Multiselect was by Mark W. Jarrell (attheshow) at
Fleet Thought (http://fleetthought.com).
Install
-------
......
......
......@@ -64,6 +64,6 @@ li.multiselect_add {
clear: both;
}
/* Hide the original label placement. */
.multiselect .form-item label {
.multiselect .form-item label, .form-type-multiselect .form-item label {
display: none;
}
\ No newline at end of file
......@@ -3,6 +3,6 @@ name = Multiselect
description = Defines a CCK multiple selection field widget, to allow easier multi-selection for users.
package = CCK
core = "7.x"
version = "7.x-1.x-dev"
version = VERSION
files[] = multiselect.module
\ No newline at end of file
......@@ -14,7 +14,12 @@ function multiselect_help($path, $arg) {
$output = '';
switch ($path) {
case 'admin/help#multiselect':
$output = '<p>' . t('Provides a CCK widget for editing fields that allows users to select from a list of options in a left box and have them visually moved into the right box when options are chosen.') . '</p>';
$output = '<p>' . t('Provides a CCK and Form API widget for editing fields that allows users to select from a list of options in a left box and have them visually moved into the right box when options are chosen.') . '</p>';
$output .= '<h2>' . t('Methods of Implementing a Multiselect Widget') . '</h2>';
$output .= '<h3>' . t('Method 1: Using CCK') . '</h3>';
$output .= '<p>' . t('When creating a new content field, select "Multiselect" as your widget type. You can use Multiselect on fields of type "list", "list_text", "list_number", "node_reference", "taxonomy_term_reference", and "user_reference".') . '</p>';
$output .= '<h3>' . t('Method 2: Coding Your Own Module') . '</h3>';
$output .= '<p>' . t('If you\'re developing a custom module and wish to use the Multiselect widget in place of a traditional "select" widget, you may use the Drupal 7 Form API. Included with the module is an example module called "multiselect_fapi_example" that creates a simple form on a page that stores the selected options in the Drupal "variables" table. The page is made available at the path: /multiselect_fapi_example.') . '</p>';
break;
}
return $output;
......@@ -38,15 +43,11 @@ function multiselect_form_alter(&$form, &$form_state, $form_id) {
// For other field types, if no 'allowed values' were set yet, add a reminder message.
if (empty($form['field']['settings']['allowed_values']['#default_value'])) {
drupal_set_message(t("You need to specify the 'allowed values' for this field."), 'warning');
dsm($form['field']);
}
}
}
}
break;
default:
//dsm($form);
break;
}
}
......@@ -66,22 +67,6 @@ function multiselect_field_widget_info() {
);
}
/**
* Implements hook_element_info().
*
* Any FAPI callbacks needed for individual widgets can be declared here,
* and the element will be passed to those callbacks for processing.
*/
/*
function multiselect_element_info() {
return array(
'multiselect' => array(
'#process' => array('multiselect_process'),
),
);
}
*/
/**
* Implements hook_field_widget_form().
* Build the form widget using Form API (as much as possible).
......@@ -106,6 +91,72 @@ function multiselect_field_widget_form(&$form, &$form_state, $field, $instance,
$default_value = _options_storage_to_form($items, $options, $value_key, $properties);
/* END copy from options.module */
$widget = _multiselect_build_widget_code($options, $items, $element, $required);
// Build the basic select box using Form API.
$element += array(
'#type' => 'select',
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $required,
'#multiple' => $multiple,
'#options' => $options,
//'#options' => $selected_options,
'#size' => 10,
'#prefix' => $widget['prefix_pre'] . $widget['prefix_options'] . $widget['prefix_post'],
'#suffix' => "\n</div>\n",
'#attributes' => array('class' => array($widget['selfield'], 'multiselect_sel'), 'id' => array($element['#field_name'])),
'#default_value' => $default_value,
'#value_key' => $value_key,
'#element_validate' => array('options_field_widget_validate'),
'#properties' => $properties,
);
return $element;
}
/**
* Implements hook_field_error().
*/
function multiselect_field_widget_error($element, $error) {
switch ($error['error']) {
case 'field_cardinality':
form_error($element, $error['message']);
break;
}
}
/**
* Copied from D6 CCK content module. Not sure where this went in D7.
* Filter out HTML from allowed values array while leaving entities unencoded.
*/
function _multiselect_allowed_values_filter_html(&$options) {
foreach ($options as $key => $opt) {
if (is_array($opt)) {
_multiselect_allowed_values_filter_html($options[$key]);
}
else {
$options[$key] = html_entity_decode(strip_tags($opt), ENT_QUOTES);
}
}
}
function _multiselect_html_for_box_options($options) {
$boxhtml = '';
foreach ($options as $value => $name) {
$boxhtml .= "<option value=\"" . $value . "\">" . $name . "</option>\n";
}
return $boxhtml;
}
/**
* Build the widget HTML code.
* @param $options = array of options available for use in the widget
* @param $items = array of previously selected options (or default values in FAPI calls)
* @param $element = the form element being created
* return $widget = an array of html items and values for use in the final presentation of widget.
*/
function _multiselect_build_widget_code($options, $items, $element, $required = FALSE) {
// Insert Javascript and CSS for this widget.
$path = drupal_get_path('module', 'multiselect');
drupal_add_js($path . '/multiselect.js');
......@@ -119,12 +170,23 @@ function multiselect_field_widget_form(&$form, &$form_state, $field, $instance,
$selected_options = array();
$unselected_options = array();
// Add selected items to the array first
// TODO: still need to get this working with field type 'taxonomy_term_reference'.
if (is_array($items)) {
foreach ($items as $key => $value) {
//$selected_options[$value] = _multiselect_allowed_values_filter_html($value);
if (is_array($value) && array_key_exists('value', $value)) { // With CCK, it's an array.
$selected_options[$value['value']] = $value['value'];
}
elseif (is_array($value) && array_key_exists('tid', $value)) { // With CCK, it's an array. Taxonomy
$selected_options[$value['tid']] = $value['tid'];
}
elseif (array_key_exists($value, $options)) { // With FAPI, it's not.
$selected_options[$value] = $options[$value];
}
}
}
else { // There's only one selected option.
if (array_key_exists($items, $options)) {
$selected_options[$items] = $options[$items];
}
}
// Add the remaining options to the arrays
foreach ($options as $key => $value) {
......@@ -135,8 +197,6 @@ function multiselect_field_widget_form(&$form, &$form_state, $field, $instance,
}
// Set up useful variables.
$addbutton = $element['#field_name'] . "_add";
$removebutton = $element['#field_name'] . "_remove";
$selfield = $element['#field_name'] . "_sel";
$unselfield = $element['#field_name'] . "_unsel";
......@@ -149,143 +209,101 @@ function multiselect_field_widget_form(&$form, &$form_state, $field, $instance,
$prefix_pre .= "<div id=\"multiselect_labels" . "_" . $element['#field_name'] . "\" class=\"multiselect_labels\"><div id=\"label_unselected" . "_" . $element['#field_name'] . "\" class=\"label_unselected\">" . t('Available Options') . ":</div>\n";
$prefix_pre .= "<div id=\"label_selected" . "_" . $element['#field_name'] . "\" class=\"label_selected\">" . t('Selected Options') . ":</div>\n</div>\n";
$prefix_pre .= "<div id=\"multiselect_available" . "_" . $element['#field_name'] . "\" class=\"multiselect_available\">";
$prefix_pre .= _multiselect_html_for_unselected_box_start($unselfield, $element['#field_name']);
$prefix_options = _multiselect_html_for_unselected_box_options($unselected_options);
if (array_key_exists('#size', $element)) {
$size = $element['#size']; // Modules can pass in the size of the select boxes.
}
else {
$size = '10'; // Default size.
}
$prefix_pre .= "<select name=\"" . $unselfield . "\" multiple=\"multiple\" class=\"form-multiselect " . $unselfield . " multiselect_unsel\" id=\"" . $element['#field_name'] . "\" size=\"" . $size . "\">\n";
$prefix_options = _multiselect_html_for_box_options($unselected_options);
$prefix_post = "</select>\n</div>\n";
$prefix_post .= _html_for_buttons($element['#field_name']);
// Build the basic select box using Form API.
$element += array(
'#type' => 'select',
'#title' => $element['#title'],
'#description' => $element['#description'],
'#required' => $required,
'#multiple' => $multiple,
'#options' => $options,
//'#options' => $selected_options,
'#size' => 10,
'#prefix' => $prefix_pre . $prefix_options . $prefix_post,
'#suffix' => "\n</div>\n",
'#attributes' => array('class' => array("$selfield multiselect_sel"), 'id' => array($element['#field_name'])),
'#default_value' => $default_value,
//'#post_render' => array('_mm_cleanup'),
'#value_key' => $value_key,
'#element_validate' => array('options_field_widget_validate'),
'#properties' => $properties,
);
$prefix_post .= "<ul id=\"multiselect_btns" . "_" . $element['#field_name'] . "\" class=\"multiselect_btns\">
<li class=\"multiselect_add\" id=\"" . $element['#field_name'] . "\"><a href=\"javascript:;\">Add</a></li>
<li class=\"multiselect_remove\" id=\"" . $element['#field_name'] . "\"><a href=\"javascript:;\">Remove</a></li>
</ul>";
return $element;
}
$widget['selected_options'] = $selected_options;
$widget['unselected_options'] = $unselected_options;
$widget['selfield'] = $selfield;
$widget['unselfield'] = $unselfield;
$widget['prefix_pre'] = $prefix_pre;
$widget['prefix_options'] = $prefix_options;
$widget['prefix_post'] = $prefix_post;
function _mm_cleanup($content, $elements) {
//drupal_set_message('elements:');
//dsm($elements);
return $content;
return $widget;
}
// ! FAPI Section
/**
* Implements hook_field_error().
* FAPI section. Add as a new FAPI element. TODO!!!Looking at form.inc and http://drupal.org/node/169815
*/
function multiselect_field_widget_error($element, $error) {
switch ($error['error']) {
case 'field_cardinality':
form_error($element, $error['message']);
break;
}
}
/**
* Implements hook_field_widget_form().
* Build the form widget using Form API (as much as possible).
* Implements hook_element_info().
*/
/*
function multiselect_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
switch ($instance['widget']['type']) {
case 'multiselect':
$element = array(
'#type' => 'multiselect',
'#default_value' => $items,
function multiselect_element_info() {
$type['multiselect'] = array(
'#input' => TRUE,
'#multiple' => TRUE,
'#process' => array('form_process_select', 'ajax_process_form'),
'#theme' => 'multiselect',
'#theme_wrappers' => array('form_element'),
);
break;
return $type;
}
return $element;
}
*/
/**
* Implements hook_theme().
*/
/*
function multiselect_theme() {
return array(
'multiselect' => array(
'arguments' => array('element' => NULL),
'render element' => 'element',
),
);
}
*/
/**
* FAPI theme for an individual elements.
* Returns HTML for a select form element.
*
* The textfield or select is already rendered by the
* textfield or select themes and the html output
* lives in $element['#children']. Override this theme to
* make custom changes to the output.
* It is possible to group options together; to do this, change the format of
* $options to an associative array in which the keys are group labels, and the
* values are associative arrays in the normal $options format.
*
* $element['#field_name'] contains the field name
* $element['#delta] is the position of this element in the group
*/
/*
function theme_multiselect($element) {
return $element['#children'];
}
*/
/**
* Copied from D6 CCK content module. Not sure where this went in D7.
* Filter out HTML from allowed values array while leaving entities unencoded.
* @param $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
* Properties used: #title, #value, #options, #description, #extra,
* #multiple, #required, #name, #attributes, #size.
*
* @see content_allowed_values()
* @see optionwidgets_select_process()
* @see content_handler_filter_many_to_one::allowed_values()
* @ingroup themeable
*/
function _multiselect_allowed_values_filter_html(&$options) {
foreach ($options as $key => $opt) {
if (is_array($opt)) {
_multiselect_allowed_values_filter_html($options[$key]);
}
else {
$options[$key] = html_entity_decode(strip_tags($opt), ENT_QUOTES);
}
}
}
function theme_multiselect($variables) {
$element = $variables['element'];
element_set_attributes($element, array('id', 'name', 'size', 'multiple', 'default_value', 'required'));
_form_set_class($element, array('form-multiselect'));
$options = $element['#options']; // All available options as defined by the element
$items = $element['#default_value']; // All selected options are referred to as "items".
$element['#field_name'] = $element['#name']; // CCK calls the #name "#field_name", so let's duplicate that..
$required = $element['#required'];
/**
* Provides html to draw the "not selected" box
*/
function _multiselect_html_for_unselected_box_start($unselfield, $fieldname) {
$boxhtml = '';
$boxhtml .= "<select name=\"" . $unselfield . "\" multiple=\"multiple\" class=\"form-select " . $unselfield . " multiselect_unsel\" id=\"" . $fieldname . "\" size=\"10\">\n";
return $boxhtml;
}
$widget = _multiselect_build_widget_code($options, $items, $element, $required);
function _multiselect_html_for_unselected_box_options($unselected_options) {
$boxhtml = '';
foreach ($unselected_options as $value => $name) {
$boxhtml .= "<option value=\"" . $value . "\">" . $name . "</option>\n";
}
return $boxhtml;
// Add a couple of things into the attributes.
$element['#attributes']['class'][] = $widget['selfield'];
$element['#attributes']['class'][] = "multiselect_sel";
$element['#attributes']['id'] = $element['#field_name'];
return $widget['prefix_pre'] . $widget['prefix_options'] . $widget['prefix_post'] . '<div class="form-item form-type-select"><select' . drupal_attributes($element['#attributes']) . '>' . _multiselect_html_for_box_options($widget['selected_options']) . '</select></div>' . "\n</div>\n";
}
/**
* Provides html to display the buttons on the form.
* Implementation of form_type_hook_value().
*/
function _html_for_buttons($fieldname) {
$buttons_code = "<ul id=\"multiselect_btns" . "_" . $fieldname . "\" class=\"multiselect_btns\">
<li class=\"multiselect_add\" id=\"" . $fieldname . "\"><a href=\"javascript:;\">Add</a></li>
<li class=\"multiselect_remove\" id=\"" . $fieldname . "\"><a href=\"javascript:;\">Remove</a></li>
</ul>";
return $buttons_code;
function form_type_multiselect_value($element, $edit = FALSE) {
if (func_num_args() == 1) {
return $element['#default_value'];
}
}
\ No newline at end of file
; $Id$
name = Multiselect FAPI Example
description = Example usage of the Multiselect module via Form API calls.
package = Example modules
core = "7.x"
version = VERSION
files[] = multiselect_fapi_example.module
\ No newline at end of file
<?php
/**
* Implements hook_menu() to set up the URLs (menu entries) for the
* form examples.
*/
function multiselect_fapi_example_menu() {
$items = array();
$items['multiselect_fapi_example'] = array(
'title' => 'Form API Example of Multiselect Widget',
'page callback' => 'drupal_get_form',
'page arguments' => array('multiselect_fapi_example_display'),
'access callback' => TRUE,
'description' => 'Simple form with a multiselect widget and a submit button. Saves to the variables table.',
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* Implementation of FAPI form.
*/
function multiselect_fapi_example_display($form, &$form_state) {
$form = array();
$form['description'] = array(
'#type' => 'item',
'#title' => t('Simple form with a multiselect widget and a submit button. Saves to the variables table.'),
);
$form['multiselector'] = array(
'#type' => 'multiselect',
'#title' => t('Here is the multiselect'),
'#options' => array(
'title' => t('Titles only'),
'teaser' => t('Titles plus teaser'),
'fulltext' => t('Full text'),
'1' => t('Option 1'),
'2' => t('Option 2'),
'3' => t('Option 3'),
'4' => t('Option 4'),
'5' => t('Option 5'),
'6' => t('Option 6'),
'7' => t('Option 7'),
'8' => t('Option 8'),
'9' => t('Option 9'),
'10' => t('Option 10'),
'11' => t('Option 11'),
'12' => t('Option 12'),
),
'#default_value' => _multiselect_fapi_example_options(),
'#multiple' => TRUE,
'#size' => 15,
'#required' => TRUE,
);
$form = system_settings_form($form);
return $form;
}
/**
* Function to get the value stored for the multiselect field from the variables table.
* Will return default values if nothing has yet been stored.
*/
function _multiselect_fapi_example_options() {
return variable_get('multiselector', array('fulltext', 'title', '4', '8'));
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment