'', 'form_key' => NULL, 'required' => 0, 'mandatory' => 0, 'pid' => 0, 'weight' => 0, 'value' => '', 'extra' => array( 'title_display' => 0, 'width' => '', 'disabled' => FALSE, 'private' => FALSE, 'attributes' => array(), 'description' => '', 'placeholder' => '', 'country' => 'ca', 'phone_country_code' => 0, 'phone_default_country_code' => 1, 'phone_int_max_length' => 15, 'ca_phone_separator' => '-', 'ca_phone_parentheses' => 1, ), ); } /** * Implements _webform_theme_component(). */ function _webform_theme_phone() { return array( 'webform_display_phonefield' => array( 'render element' => 'element' ) ); } /** * Generate the form for editing a component. * Create a set of form elements to be displayed on the form for editing this * component. Use care naming the form items, as this correlates directly to the * database schema. The component "Name" and "Description" fields are added to * every component type and are not necessary to specify here (although they * may be overridden if desired). * * @param $component * A Webform component array. * * @return * An array of form items to be displayed on the edit component page */ function _webform_edit_phone($component) { $form = array(); // General Options $form['extra']['country'] = array( '#type' => 'select', '#title' => t('Country'), '#options' => phone_countries(), '#default_value' => $component['extra']['country'], '#description' => t('Which country-specific rules should this field be validated against and formatted according to.'), '#required' => TRUE, ); $form['extra']['phone_country_code'] = array( '#type' => 'checkbox', '#title' => t('Add the country code if not filled by the user'), '#default_value' => $component['extra']['phone_country_code'], ); // International Options $form['extra']['phone_int_help'] = array( '#type' => 'markup', '#value' => t('International phone numbers are in the form +XX YYYYYYY where XX is a country code and YYYYYYY is the local number. This field type is based off of the E.123 specification.'), '#states' => array( 'visible' => array( ':input[name="extra[country]"]' => array( 'value' => 'int' ), ), ), ); $form['extra']['phone_default_country_code'] = array( '#type' => 'textfield', '#title' => t('Default country code to add to international numbers without one (omit + sign)'), '#default_value' => $component['extra']['phone_default_country_code'], '#states' => array( 'visible' => array( ':input[name="extra[country]"]' => array( 'value' => 'int' ), ), ), ); $form['extra']['phone_int_max_length'] = array( '#type' => 'textfield', '#title' => t('Maximum length of international numbers, according to the ITU this is 15'), '#default_value' => $component['extra']['phone_int_max_length'], '#states' => array( 'visible' => array( ':input[name="extra[country]"]' => array( 'value' => 'int' ), ), ), ); // US/Canada Options $form['extra']['ca_phone_separator'] = array( '#type' => 'textfield', '#title' => t('Separator'), '#default_value' => $component['extra']['ca_phone_separator'], '#size' => 2, '#states' => array( 'visible' => array( ':input[name="extra[country]"]' => array( 'value' => 'ca' ), ), ), ); $form['extra']['ca_phone_parentheses'] = array( '#type' => 'checkbox', '#title' => t('Use parentheses around area code'), '#default_value' => $component['extra']['ca_phone_parentheses'], '#states' => array( 'visible' => array( ':input[name="extra[country]"]' => array( 'value' => 'ca' ), ), ), ); $form['value'] = array( '#type' => 'textfield', '#title' => t('Default value'), '#default_value' => $component['value'], '#description' => t('The default value of the field.') . theme('webform_token_help'), '#size' => 60, '#maxlength' => 1024, '#weight' => 0, ); $form['display']['width'] = array( '#type' => 'textfield', '#title' => t('Width'), '#default_value' => $component['extra']['width'], '#description' => t('Width of the textfield.') . ' ' . t('Leaving blank will use the default size.'), '#size' => 5, '#maxlength' => 10, '#weight' => 0, '#parents' => array( 'extra', 'width' ), ); $form['display']['placeholder'] = array( '#type' => 'textfield', '#title' => t('Placeholder'), '#default_value' => $component['extra']['placeholder'], '#description' => t('The text will be shown in the field until the user starts entering a value.'), '#weight' => 1, '#parents' => array( 'extra', 'placeholder' ), ); $form['display']['disabled'] = array( '#type' => 'checkbox', '#title' => t('Disabled'), '#return_value' => 1, '#description' => t('Make this field non-editable. Useful for setting an unchangeable default value.'), '#weight' => 11, '#default_value' => $component['extra']['disabled'], '#parents' => array( 'extra', 'disabled' ), ); return $form; } /** * Render a Webform component to be part of a form. * * @param $component * A Webform component array. * @param $value * If editing an existing submission or resuming a draft, this will contain * an array of values to be shown instead of the default in the component * configuration. This value will always be an array, keyed numerically for * each value saved in this field. * @param $filter * Whether or not to filter the contents of descriptions and values when * rendering the component. Values need to be unfiltered to be editable by * Form Builder. * * @see _webform_client_form_add_component() */ function _webform_render_phone($component, $value = NULL, $filter = TRUE) { //TODO: change these to use non-private functions (no _) if/when webform 3.x is entirely deprecated $form_item = array( '#type' => module_exists('elements') ? 'telfield' : 'textfield', // '#default_value' => $filter ? webform_replace_tokens($component['value'], NULL, NULL, NULL, TRUE) : $component['value'], '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'], '#attributes' => $component['extra']['attributes'], '#theme_wrappers' => array( 'webform_element' ), // '#description' => $filter ? webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'], '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'], '#element_validate' => array( 'webform_validate_phone' ), '#maxlength' => ( $component['extra']['country'] == 'int' ? ( isset( $component['extra']['phone_int_max_length'] ) ? $component['extra']['phone_int_max_length'] : NULL ) : NULL ), '#required' => $component['required'] || $component['mandatory'], //Either one being true will could as required...because webform changed in 4.x-alpha8 '#size' => 17, // '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'], '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'], '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before', '#weight' => $component['weight'], '#translatable' => array( 'title', 'description' ), ); if (isset( $value )) { $form_item['#default_value'] = $value[0]; } // Change the 'width' option to the correct 'size' option. if ($component['extra']['width'] > 0) { $form_item['#size'] = $component['extra']['width']; } // Show the placeholder text if used. if ($component['extra']['placeholder']) { $form_item['#attributes']['placeholder'] = $component['extra']['placeholder']; } if ($component['extra']['disabled']) { if ($filter) { $form_item['#attributes']['readonly'] = 'readonly'; } else { $form_item['#disabled'] = TRUE; } } if (isset( $value[0] )) { $form_item['#default_value'] = $value[0]; } return $form_item; } /** * Validation Callback for phone field */ function webform_validate_phone($element, $form_state) { $value = $element['#value']; if (isset( $value ) && $value != '') { $ccode = $element['#webform_component']['extra']['country']; //run through 'phone' module's validation if (!valid_phone_number($ccode, $value)) { $country = phone_country_info($ccode); form_error($element, t($country['error'], array( '%value' => $value ))); } } } /** * Display the result of a submission for a component. * The output of this function will be displayed under the "Results" tab then * "Submissions". This should output the saved data in some reasonable manner. * * @param $component * A Webform component array. * @param $value * An array of information containing the submission result, directly * correlating to the webform_submitted_data database table schema. * @param $format * Either 'html' or 'text'. Defines the format that the content should be * returned as. Make sure that returned content is run through check_plain() * or other filtering functions when returning HTML. * * @return * A renderable element containing at the very least these properties: * - #title * - #weight * - #component * - #format * - #value * Webform also uses #theme_wrappers to output the end result to the user, * which will properly format the label and content for use within an e-mail * (such as wrapping the text) or as HTML (ensuring consistent output). */ function _webform_display_phone($component, $value, $format = 'html') { return array( '#title' => $component['name'], '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before', '#weight' => $component['weight'], '#theme' => 'webform_display_phonefield', '#theme_wrappers' => $format == 'html' ? array( 'webform_element' ) : array( 'webform_element_text' ), '#post_render' => array( 'webform_element_wrapper' ), '#component' => $component, '#format' => $format, '#value' => isset( $value[0] ) ? $value[0] : '', '#translatable' => array( 'title', 'description' ), ); } /** * Format the output of data for this component. */ function theme_webform_display_phonefield($variables) { $element = $variables['element']; $plain_value = check_plain($element['#value']); if ($element['#format'] == 'html') { //Use smarter detection if available for formatting the output $is_mobile_device = module_exists('mobile_tools') ? mobile_tools_is_mobile_device() : strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') !== FALSE || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== FALSE; $value = ( $is_mobile_device ) ? '' . $plain_value . '' : $plain_value; } else { $value = $plain_value; } return $value; } /** * A hook for changing the input values before saving to the database. * Webform expects a component to consist of a single field, or a single array * of fields. If you have a component that requires a deeper form tree * you must flatten the data into a single array using this callback * or by setting #parents on each field to avoid data loss and/or unexpected * behavior. * Note that Webform will save the result of this function directly into the * database. * * @param $component * A Webform component array. * @param $value * The POST data associated with the user input. * * @return * An array of values to be saved into the database. Note that this should be * a numerically keyed array. */ function _webform_submit_phone($component, $value) { $ccode = $component['extra']['country']; if (phone_countries($ccode) !== NULL) { if (isset( $value ) && !empty( $value )) { //Use 'phone' module to format the number return format_phone_number($ccode, $value, $component['extra']); } } return FALSE; //If we haven't returned already, something failed. } /** * Calculate and returns statistics about results for this component. * This takes into account all submissions to this webform. The output of this * function will be displayed under the "Results" tab then "Analysis". * * @param $component * An array of information describing the component, directly correlating to * the webform_component database schema. * @param $sids * An optional array of submission IDs (sid). If supplied, the analysis will * be limited to these sids. * @param $single * Boolean flag determining if the details about a single component are being * shown. May be used to provided detailed information about a single * component's analysis, such as showing "Other" options within a select list. * * @return * An array of data rows, each containing a statistic for this component's * submissions. */ function _webform_analysis_phone($component, $sids = array(), $single = FALSE) { // Generate the list of options and questions. $query = db_select('webform_submitted_data', 'wsd', array( 'fetch' => PDO::FETCH_ASSOC ))->fields('wsd', array( 'data' ))->condition('nid', $component['nid'])->condition('cid', $component['cid']); if (count($sids)) { $query->condition('sid', $sids, 'IN'); } $non_blanks = 0; $submissions = 0; $result = $query->execute(); foreach ($result as $data) { if (drupal_strlen(trim($data['data'])) > 0) { $non_blanks++; } $submissions++; } $rows[0] = array( t('Left Blank'), ( $submissions - $non_blanks ) ); $rows[1] = array( t('User entered value'), $non_blanks ); return $rows; } /** * Return the result of a component value for display in a table. * The output of this function will be displayed under the "Results" tab then * "Table". * * @param $component * A Webform component array. * @param $value * An array of information containing the submission result, directly * correlating to the webform_submitted_data database schema. * * @return * Textual output formatted for human reading. */ function _webform_table_phone($component, $value) { return check_plain(empty( $value[0] ) ? '' : $value[0]); } /** * Return the header for this component to be displayed in a CSV file. * The output of this function will be displayed under the "Results" tab then * "Download". * * @param $component * A Webform component array. * @param $export_options * An array of options that may configure export of this field. * * @return * An array of data to be displayed in the first three rows of a CSV file, not * including either prefixed or trailing commas. */ function _webform_csv_headers_phone($component, $export_options) { $header = array(); $header[0] = ''; $header[1] = ''; $header[2] = $export_options['header_keys'] ? $component['form_key'] : $component['name']; return $header; } /** * Format the submitted data of a component for CSV downloading. * The output of this function will be displayed under the "Results" tab then * "Download". * * @param $component * A Webform component array. * @param $export_options * An array of options that may configure export of this field. * @param $value * An array of information containing the submission result, directly * correlating to the webform_submitted_data database schema. * * @return * An array of items to be added to the CSV file. Each value within the array * will be another column within the file. This function is called once for * every row of data. */ function _webform_csv_data_phone($component, $export_options, $value) { return !isset( $value[0] ) ? '' : $value[0]; } /** * The first hook provides the name and position of the field in the Form Builder palette, as well as a default element to display when the field is pulled out of the palette. * The second hook maps the component properties and options to FormAPI properties that Form Builder can manipulate. * Form Builder then will manage pulling the form out of the normal Webform configuration form, loading configuration, and saving it. * There are plenty of examples in the form_builder_webform.components.inc file that other modules (such as Webform Phone Number) can use as templates. * I'm moving this request over to that module's queue, and changing to a feature request. */ /** * @defgroup form-builder-webform-phone-callbacks Callbacks for the Phone component * @{ */ /** * Implements _form_builder_webform_form_builder_types_component(). */ function _form_builder_webform_form_builder_types_phone() { drupal_add_css(drupal_get_path('module', 'webform_phone') . '/webform_phone.css'); $fields = array(); $fields['phone'] = array( 'title' => t('Phone Number'), 'properties' => array( 'country', 'phone_country_code', 'phone_default_country_code', 'phone_int_max_length', 'ca_phone_separator', 'ca_phone_parentheses', ), 'weight' => -17, //Doesn't make sense that modules get to weight themselves, why wouldn't everyone want to be first? ); $defaults = _webform_defaults_phone(); $fields['phone']['default'] = _form_builder_webform_default('phone'); $fields['phone']['default']['#title'] = t('New Phone Number Field'); $fields['phone']['default']['#country'] = $defaults['extra']['country']; $fields['phone']['default']['#phone_country_code'] = $defaults['extra']['phone_country_code']; $fields['phone']['default']['#phone_default_country_code'] = $defaults['extra']['phone_default_country_code']; $fields['phone']['default']['#phone_int_max_length'] = $defaults['extra']['phone_int_max_length']; $fields['phone']['default']['#ca_phone_separator'] = $defaults['extra']['ca_phone_separator']; $fields['phone']['default']['#ca_phone_parentheses'] = $defaults['extra']['ca_phone_parentheses']; return $fields; } /** * Implements _form_builder_webform_form_builder_map_component(). */ function _form_builder_webform_form_builder_map_phone() { return array( 'form_builder_type' => 'phone', 'properties' => array( 'country' => array( 'form_parents' => array( 'extra', 'country' ), 'storage_parents' => array( 'extra', 'country' ), ), 'phone_country_code' => array( 'form_parents' => array( 'extra', 'phone_country_code' ), 'storage_parents' => array( 'extra', 'phone_country_code' ), ), 'phone_default_country_code' => array( 'form_parents' => array( 'extra', 'phone_default_country_code' ), 'storage_parents' => array( 'extra', 'phone_default_country_code' ), ), 'phone_int_max_length' => array( 'form_parents' => array( 'extra', 'phone_int_max_length' ), 'storage_parents' => array( 'extra', 'phone_int_max_length' ), ), 'ca_phone_separator' => array( 'form_parents' => array( 'extra', 'ca_phone_separator' ), 'storage_parents' => array( 'extra', 'ca_phone_separator' ), ), 'ca_phone_parentheses' => array( 'form_parents' => array( 'extra', 'ca_phone_parentheses' ), 'storage_parents' => array( 'extra', 'ca_phone_parentheses' ), ), ), ); } /** * @} End of "defgroup form-builder-webform-phone-callbacks" */