Skip to content

Instantly share code, notes, and snippets.

@jackrabbithanna
Last active January 24, 2017 03:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jackrabbithanna/71e407d5ffb089b4a07778b47a5629b8 to your computer and use it in GitHub Desktop.
Save jackrabbithanna/71e407d5ffb089b4a07778b47a5629b8 to your computer and use it in GitHub Desktop.
Custom FAPI multivalued element type, 2 column grid of textfields, ajax add and remove
/**
* Implements hook_theme().
*
* @return array
*/
function webform_multi_theme() {
return array(
'webform_multi_url_params_field' => array(
'render element' => 'element',
),
);
}
/**
* Implements hook_element_info().
*
* @return mixed
*/
function webform_multi_element_info() {
$elements['webform_multi_url_params'] = array(
'#default_value' => '',
'#input' => TRUE,
'#process' => array('webform_multi_url_params_element_process'),
'#theme' => array('webform_multi_url_params_field'),
'#theme_wrappers' => array('form_element'),
'#tree' => TRUE,
'#value_callback' => 'webform_multi_url_params_element_value_callback',
);
return $elements;
}
/**
* Process callback for the webform_multi_url_params FAPI element
*
* @param $element
* @param $form_state
* @param $complete_form
*/
function webform_multi_url_params_element_process($element, $form_state, $complete_form) {
$element_name = $element['#name'];
preg_match_all("/\[([^\]]*)\]/", $element_name, $matches);
if( count($matches) ) {
$temp_name = end($matches);
if(!empty($temp_name)) {
$element_name = $temp_name[0];
}
}
// get settings from either form state storage, form state values, or from stored db values or variable values
if(!empty($form_state['webform_multi_url_param_settings'][$element_name])) {
$url_param_settings = $form_state['webform_multi_url_param_settings'][$element_name];
}
else {
//first look for passed defaults
if(empty($form_state['input']) && !empty($element['#default_value'])) {
$url_param_settings = array();
if(!empty($element['#default_value'])) {
foreach($element['#default_value']['webform_multi_url_params']['url_params'] as $count => $param) {
$url_param_settings[$count] = $param['param'];
}
}
$url_param_settings[] = array('source_param' => '', 'redirect_param' => '');
}
else {
// if none, then setup a blank item
$url_param_settings = array(
0 => array('source_param' => '', 'redirect_param' => ''),
);
}
}
$element['webform_multi_url_params']['url_params'] = array(
'#type' => 'container',
'#tree' => TRUE,
'#prefix' => '<div id="webform-multi-url-params_' . $element_name . '">',
'#suffix' => '</div>',
'#attributes' => array(
'class' => array(
'webform-multi-url-params-container',
),
),
);
foreach($url_param_settings as $count => $settings) {
$element['webform_multi_url_params']['url_params'][$count]['param'] = array(
'#type' => 'container',
'#tree' => TRUE,
'#attributes' => array(
'class' => array('webform-multi-url-param-row'),
),
);
$element['webform_multi_url_params']['url_params'][$count]['param']['source_param'] = array(
'#type' => 'textfield',
'#size' => 30,
'#required' => $element['#required'],
'#title' => t('Source Parameter'),
'#title_display' => 'invisible',
'#theme_wrappers' => array(),
'#attributes' => array('placeholder' => 'source parameter'),
'#default_value' => $settings['source_param'],
);
$element['webform_multi_url_params']['url_params'][$count]['param']['redirect_param'] = array(
'#type' => 'textfield',
'#size' => 30,
'#required' => $element['#required'],
'#title' => t('Redirect Parameter'),
'#title_display' => 'invisible',
'#theme_wrappers' => array(),
'#attributes' => array('placeholder' => 'redirect parameter'),
'#default_value' => $settings['redirect_param'],
);
$element['webform_multi_url_params']['url_params'][$count]['param']['remove_param' . $count] = array(
'#parent_element_name' => $element_name,
'#parent_element_parents' => $element['#parents'],
'#name' => 'url-param-remove|' . $count . '|' . $element_name,
'#id' => 'url-param-remove-' . $count . '-' . $element_name,
'#type' => 'image_button',
'#button_type' => 'image-button',
'#src' => drupal_get_path('module', 'webform_multi') . '/img/delete.png',
'#default_value' => t('Remove'),
'#limit_validation_errors' => array(),
'#submit' => array('webform_multi_url_param_element_add_remove_value_submit'),
'#ajax' => array(
'wrapper' => 'webform-multi-url-params_' . $element_name,
'callback' => 'webform_multi_url_param_element_ajax_callback',
),
);
}
$element['webform_multi_url_params']['add_param_setting'] = array(
'#parent_element_name' => $element_name,
'#name' => 'add-param-setting' . '_' . $element_name,
'#id' => 'add-param-setting' . '_' . $element_name,
'#type' => 'submit',
'#default_value' => t('Add'),
'#submit' => array('webform_multi_url_param_element_add_remove_value_submit'),
'#ajax' => array(
'wrapper' => 'webform-multi-url-params_' . $element_name,
'callback' => 'webform_multi_url_param_element_ajax_callback',
),
);
$element['#attached']['css'][] = drupal_get_path('module', 'webform_multi') . '/css/url-param-element.css';
return $element;
}
/**
* Add and Remove button submit callback
*
* @param $form
* @param $form_state
*/
function webform_multi_url_param_element_add_remove_value_submit($form, &$form_state) {
if(!empty($_POST['_triggering_element_name'])) {
if(!preg_match('/^[a-zA-Z0-9_\-\|]+$/', $_POST['_triggering_element_name'])) {
return;
}
}
else {
$_POST['_triggering_element_name'] = $form_state['triggering_element']['#name'];
}
if (strpos($_POST['_triggering_element_name'], "url-param-remove") === 0) {
$name_array = explode('|', $_POST['_triggering_element_name']);
$index = $name_array[1];
$parent_element_name = $name_array[2];
$parents = $form_state['triggering_element']['#array_parents'];
//need this bit incase there are 2 element on the form and drupal gets the triggering_element wrong
foreach($parents as $count => $parent) {
if($parent == 'webform_multi_url_params') {
$parents[$count-1] = $parent_element_name;
break;
}
}
if($form_state['triggering_element']['#name'] == 'add-param-setting') {
array_pop($parents);
$parents[] = $parent_element_name;
}
else {
array_pop($parents);
array_pop($parents);
array_pop($parents);
}
if(isset($form_state['input'][$parents[0]])) {
$input =& drupal_array_get_nested_value($form_state['input'], $parents);
}
else {
$first_parent = array_shift($parents);
$input =& drupal_array_get_nested_value($form_state['input'], $parents);
}
unset($input[$index]);
$input = array_values($input);
drupal_array_set_nested_value($form_state['input'], $parents, $input);
$form_state['webform_multi_url_param_settings'][$parent_element_name] = array();
foreach($input as $count => $settings) {
$form_state['webform_multi_url_param_settings'][$parent_element_name][$count] = $settings['param'];
}
}
elseif(strpos($_POST['_triggering_element_name'], "add-param-setting") === 0) {
$parents = $form_state['triggering_element']['#parents'];
array_pop($parents);
$input = drupal_array_get_nested_value($form_state['input'], $parents);
$form_state['webform_multi_url_param_settings'][$form_state['triggering_element']['#parent_element_name']] = array();
foreach($input['url_params'] as $count => $settings) {
$form_state['webform_multi_url_param_settings'][$form_state['triggering_element']['#parent_element_name']][$count] = $settings['param'];
}
$form_state['webform_multi_url_param_settings'][$form_state['triggering_element']['#parent_element_name']][] = array('source_param' => '', 'redirect_param' => '');
}
$form_state['rebuild'] = TRUE;
}
/**
* Add and remove button ajax callback
*
* @param $form
* @param $form_state
* @return array
*/
function webform_multi_url_param_element_ajax_callback($form, &$form_state) {
if(!empty($_POST['_triggering_element_name'])) {
if(!preg_match('/^[a-zA-Z0-9_\-\|]+$/', $_POST['_triggering_element_name'])) {
return;
}
}
else {
$_POST['_triggering_element_name'] = $form_state['triggering_element']['#name'];
}
$commands = array();
if (strpos($_POST['_triggering_element_name'], "url-param-remove") === 0) {
$name_array = explode('|', $_POST['_triggering_element_name']);
$index = $name_array[1];
$parent_element_name = $name_array[2];
$parents = $form_state['triggering_element']['#array_parents'];
//need this bit incase there are 2 element on the form and drupal gets the triggering_element wrong
foreach($parents as $count => $parent) {
if($parent == 'webform_multi_url_params') {
$parents[$count-1] = $parent_element_name;
break;
}
}
if(strpos($form_state['triggering_element']['#name'], 'add-param-setting') === 0) {
array_pop($parents);
}
else {
array_pop($parents);
array_pop($parents);
array_pop($parents);
}
$element = drupal_array_get_nested_value($form, $parents);
if($form_state['triggering_element']['#name'] == 'add-param-setting') {
$commands[] = ajax_command_html('#webform-multi-url-params_' . $parent_element_name, render($element['url_params']));
}
else {
$commands[] = ajax_command_html('#webform-multi-url-params_' . $parent_element_name, render($element));
}
}
elseif(strpos($_POST['_triggering_element_name'], "add-param-setting") === 0) {
$parents = $form_state['triggering_element']['#array_parents'];
array_pop($parents);
$element = drupal_array_get_nested_value($form, $parents);
$commands[] = ajax_command_html('#webform-multi-url-params_' . $form_state['triggering_element']['#parent_element_name'], render($element['url_params']));
}
if (!empty($commands)) {
$commands[] = ajax_command_prepend('#webform-multi-url-params_' . $form_state['triggering_element']['#parent_element_name'], '<div id="messages">' . theme('status_messages') . '</div>');
return array('#type' => 'ajax', '#commands' => $commands);
}
}
/**
* Theme callback for the webform_multi_url_params FAPI element type
*
* @param $variables
* @return string
*/
function webform_multi_url_params_field($variables) {
$element = $variables['element'];
$output = drupal_render($element);
return $output;
}
/**
* Value callback for the webform_multi_url_params FAPI element type
*
* @param $element
* @param bool $input
* @param $form_state
* @return bool|void
*/
function webform_multi_url_params_element_value_callback($element, $input = FALSE, &$form_state) {
if ($input !== FALSE) {
foreach($input['webform_multi_url_params']['url_params'] as $count => $param) {
if ($input['webform_multi_url_params']['url_params'][$count]['param']['source_param'] && !$input['webform_multi_url_params']['url_params'][$count]['param']['redirect_param']) {
$input['webform_multi_url_params']['url_params'][$count]['param']['source_param'] = '';
}
if ($input['webform_multi_url_params']['url_params'][$count]['param']['redirect_param'] && !$input['webform_multi_url_params']['url_params'][$count]['param']['source_param']) {
$input['webform_multi_url_params']['url_params'][$count]['param']['redirect_param'] = '';
}
}
return $input;
}
elseif (!empty($element['#default_value'])) {
return $element['#default_value'];
}
return;
}
@jackrabbithanna
Copy link
Author

To use this in any form you are creating, you'd add something like this to your form definition:

$form['url_params'] = array(
    '#type' => 'webform_multi_url_params',
    '#title' => 'URL Redirect Parameters',
    '#required' => FALSE,
    '#default_value' => array(0 => array('source_param' => 'aaa', 'redirect_param' => 'aaa'), 1 => array('source_param' => 'bbb', 'redirect_param' => 'bbb')),
  );

@jackrabbithanna
Copy link
Author

You can add multiple form elements of this custom type 'webform_multi_url_params' and the ajax works right
Although this element type was created for a custom webform integration module I am writing, but doesn't make a webform component type. This is a FAPI element type, like 'textfield', or 'select'

@jackrabbithanna
Copy link
Author

jackrabbithanna commented Jan 24, 2017

Keep playing with it, works good now for being in a parent #tree or not, multiple widgets on the same page, need to format the #default_value non optimally IMO

Its because the $element['webform_multi_url_params']['url_params'] container has #tree = TRUE
and the row container, 'params' also has #tree true

I would have not had that but I needed a way to control an id so I could use the ajax, but maybe it was unnecessary?
Is the two containers that the ajaxified buttons go in with #tree = TRUE related to sometimes Drupal not getting the $form_state['triggering_element'] right? This necessitated all the logic looking at $_POST['triggering_element_name']......

$form['redirect_settings']['url_params'] = array(
    '#type' => 'webform_multi_url_params',
    '#title' => 'URL Redirect Parameters',
    '#required' => FALSE,
    '#default_value' => array(
       'webform_multi_url_params' => array(
          'url_params' => array(
            0 => array('params' => array('source_param' => 'someParam', 'redirect_param' => 'someParam')),
          ),
        ),
      ),
  );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment