You are here

geofield.elements.inc in Geofield 7.2

Provides FormAPI element callbacks for geofield_latlon and geofield_proximity.

File

geofield.elements.inc
View source
<?php

/**
 * @file
 * Provides FormAPI element callbacks for geofield_latlon and geofield_proximity.
 */

/**
 * Diameter of the Earth in kilometers.
 */
define('GEOFIELD_KILOMETERS', 6371);

/**
 * Diameter of the Earth in meters.
 */
define('GEOFIELD_METERS', 6371000);

/**
 * Diameter of the Earth in miles.
 */
define('GEOFIELD_MILES', 3959);

/**
 * Diameter of the Earth in yards.
 */
define('GEOFIELD_YARDS', 6975175);

/**
 * Diameter of the Earth in feet.
 */
define('GEOFIELD_FEET', 20925525);

/**
 * Diameter of the Earth in nautical miles.
 */
define('GEOFIELD_NAUTICAL_MILES', 3444);

/**
 * Implements hook_element_info().
 */
function geofield_element_info() {
  return array(
    'geofield_latlon' => array(
      '#input' => TRUE,
      '#process' => array(
        'geofield_latlon_element_process',
      ),
      '#element_validate' => array(
        'geofield_latlon_element_validate',
      ),
      '#theme' => array(
        'geofield_latlon',
      ),
      '#theme_wrappers' => array(
        'fieldset',
      ),
    ),
    'geofield_bounds' => array(
      '#input' => TRUE,
      '#process' => array(
        'geofield_bounds_element_process',
      ),
      '#element_validate' => array(
        'geofield_bounds_element_validate',
      ),
      '#theme' => array(
        'geofield_bounds',
      ),
      '#theme_wrappers' => array(
        'fieldset',
      ),
    ),
    'geofield_proximity' => array(
      '#input' => FALSE,
      '#tree' => TRUE,
      '#theme_wrappers' => array(
        'geofield_proximity',
      ),
      '#process' => array(
        'geofield_proximity_element_process',
      ),
    ),
  );
}

/**
 * Process function for geofield_latlon.
 */
function geofield_latlon_element_process($element, &$form_values) {
  $element['#tree'] = TRUE;
  $element['#input'] = TRUE;
  $element['lat'] = array(
    '#type' => 'textfield',
    '#title' => t('Latitude'),
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['lat']) ? $element['#default_value']['lat'] : '',
    '#attributes' => array(
      'class' => array(
        'geofield-lat',
      ),
    ),
  );
  $element['lon'] = array(
    '#type' => 'textfield',
    '#title' => t('Longitude'),
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['lon']) ? $element['#default_value']['lon'] : '',
    '#attributes' => array(
      'class' => array(
        'geofield-lon',
      ),
    ),
  );
  unset($element['#value']);

  // Set this to false always to prevent notices.
  $element['#required'] = FALSE;
  if (!empty($element['#geolocation']) && $element['#geolocation'] == TRUE) {
    $element['#attached']['js'][] = drupal_get_path('module', 'geofield') . '/js/geolocation.js';
    $element['geocode'] = array(
      '#type' => 'button',
      '#value' => t('Find my location'),
      '#name' => 'geofield-html5-geocode-button',
    );
    $element['#attributes']['class'] = array(
      'auto-geocode',
    );
  }
  return $element;
}

/**
 * Element validation function for geofield_latlon.
 */
function geofield_latlon_element_validate($element, &$form_values) {
  $components = array(
    'lat' => array(
      'title' => 'Latitude',
      'range' => 90,
    ),
    'lon' => array(
      'title' => 'Longitude',
      'range' => 180,
    ),
  );
  $allFilled = TRUE;
  $anyFilled = FALSE;
  foreach ($components as $key => $component) {
    if (!empty($element[$key]['#value'])) {
      if (!is_numeric($element[$key]['#value'])) {
        form_error($element[$key], t('@title: @component_title is not numeric.', array(
          '@title' => $element['#title'],
          '@component_title' => $component['title'],
        )));
      }
      elseif (abs($element[$key]['#value']) > $component['range']) {
        form_error($element[$key], t('@title: @component_title is out of bounds.', array(
          '@title' => $element['#title'],
          '@component_title' => $component['title'],
        )));
      }
    }
    if ($element[$key]['#value'] == '') {
      $allFilled = FALSE;
    }
    else {
      $anyFilled = TRUE;
    }
  }
  if ($anyFilled && !$allFilled) {
    foreach ($components as $key => $component) {
      if ($element[$key]['#value'] == '') {
        form_error($element[$key], t('@title: @component_title must be filled too.', array(
          '@title' => $element['#title'],
          '@component_title' => $component['title'],
        )));
      }
    }
  }
}

/**
 * Process function for geofield_bounds.
 */
function geofield_bounds_element_process($element, &$form_values) {
  $element['#tree'] = TRUE;
  $element['top'] = array(
    '#type' => 'textfield',
    '#title' => t('Top'),
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['top']) ? $element['#default_value']['top'] : '',
    '#attributes' => array(
      'class' => array(
        'geofield-top',
      ),
    ),
  );
  $element['right'] = array(
    '#type' => 'textfield',
    '#title' => t('Right'),
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['right']) ? $element['#default_value']['right'] : '',
    '#attributes' => array(
      'class' => array(
        'geofield-right',
      ),
    ),
  );
  $element['bottom'] = array(
    '#type' => 'textfield',
    '#title' => t('Bottom'),
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['bottom']) ? $element['#default_value']['bottom'] : '',
    '#attributes' => array(
      'class' => array(
        'geofield-bottom',
      ),
    ),
  );
  $element['left'] = array(
    '#type' => 'textfield',
    '#title' => t('Left'),
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['left']) ? $element['#default_value']['left'] : '',
    '#attributes' => array(
      'class' => array(
        'geofield-left',
      ),
    ),
  );
  unset($element['#value']);

  // Set this to false always to prevent notices.
  $element['#required'] = FALSE;
  return $element;
}

/**
 * Element validation function for geofield_latlon.
 */
function geofield_bounds_element_validate($element, &$form_values) {
  $components = array(
    'top' => array(
      'title' => 'Top',
      'range' => 90,
    ),
    'right' => array(
      'title' => 'Right',
      'range' => 180,
    ),
    'bottom' => array(
      'title' => 'Bottom',
      'range' => 90,
    ),
    'left' => array(
      'title' => 'Left',
      'range' => 180,
    ),
  );
  $allFilled = TRUE;
  $anyFilled = FALSE;
  foreach ($components as $key => $component) {
    if (!empty($element[$key]['#value'])) {
      if (!is_numeric($element[$key]['#value'])) {
        form_error($element[$key], t('@title: @component_title is not numeric.', array(
          '@title' => $element['#title'],
          '@component_title' => $component['title'],
        )));
      }
      elseif (abs($element[$key]['#value']) > $component['range']) {
        form_error($element[$key], t('@title: @component_title is out of bounds.', array(
          '@title' => $element['#title'],
          '@component_title' => $component['title'],
        )));
      }
    }
    if ($element[$key]['#value'] == '') {
      $allFilled = FALSE;
    }
    else {
      $anyFilled = TRUE;
    }
  }
  if ($anyFilled && !$allFilled) {
    foreach ($components as $key => $component) {
      if ($element[$key]['#value'] == '') {
        form_error($element[$key], t('@title: @component_title must be filled too.', array(
          '@title' => $element['#title'],
          '@component_title' => $component['title'],
        )));
      }
    }
  }
}

/**
 * Process function for the proximity form element
 */
function geofield_proximity_element_process($element, &$form_state, $form) {
  $element['#attributes'] = array(
    'class' => array(
      'clearfix',
    ),
  );
  $element['#tree'] = TRUE;
  $element['#attached']['css'] = array(
    drupal_get_path('module', 'geofield') . '/css/proximity-element.css',
  );

  //Create the textfield for distance
  $element['distance'] = array(
    '#type' => 'textfield',
    '#title' => t('Distance'),
    '#default_value' => !empty($element['#default_value']['distance']) ? $element['#default_value']['distance'] : '',
    '#title_display' => 'invisible',
    // Allow decimal numbers as distances
    '#element_validate' => array(
      'element_validate_number',
    ),
  );

  // If #geofield_range is TRUE, create second option for range.
  if (!empty($element['#geofield_range']) && $element['#geofield_range'] == TRUE) {
    $element['distance2'] = array(
      '#type' => 'textfield',
      '#title' => t('Distance End'),
      '#default_value' => !empty($element['#default_value']['distance2']) ? $element['#default_value']['distance2'] : '',
      '#title_display' => 'invisible',
      '#element_validate' => array(
        'element_validate_number',
      ),
    );
  }

  //Create dropdown for units
  $element['unit'] = array(
    '#type' => 'select',
    '#options' => geofield_radius_options(),
    '#title' => t('Unit'),
    '#default_value' => !empty($element['#default_value']['unit']) ? $element['#default_value']['unit'] : GEOFIELD_KILOMETERS,
    '#title_display' => 'invisible',
  );

  //Create textfield for geocoded input
  $element['origin'] = array(
    '#type' => !empty($element['#origin_element']) ? $element['#origin_element'] : 'textfield',
    '#title' => t('Origin'),
    '#prefix' => '<span class="geofield-proximity-origin-from">' . t('from') . '</span>',
    '#title_display' => 'invisible',
    '#required' => !empty($element['#required']) ? $element['#required'] : FALSE,
    '#default_value' => !empty($element['#default_value']['origin']) ? $element['#default_value']['origin'] : FALSE,
  );
  if (!empty($element['#origin_options'])) {
    $element['origin'] = array_merge($element['origin'], $element['#origin_options']);
  }
  if (isset($element['#element_validate'])) {
    array_push($element['#element_validate'], 'geofield_proximity_search_validate');
  }
  else {
    $element['#element_validate'] = array(
      'geofield_proximity_search_validate',
    );
  }
  return $element;
}

/**
 * Validate the geofield proximity search form item
 */
function geofield_proximity_search_validate($element, &$form_state) {

  //If the origin is set, ensure the distance is set as well
  if (!empty($element['origin']['#value']) && trim($element['origin']['#value']) != '' && empty($element['distance']['#value'])) {
    form_set_error(implode('][', $element['#array_parents']) . '][distance', t('@title must be set when @origin is specified.', array(
      '@title' => $element['distance']['#title'],
      '@origin' => $element['origin']['#title'],
    )));
  }
}
function geofield_theme($existing, $type, $theme, $path) {
  return array(
    'geofield_latlon' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'render element' => 'element',
    ),
    'geofield_proximity' => array(
      'render element' => 'element',
    ),
  );
}

/**
 * Theme wrapper for form item
 */
function theme_geofield_proximity($vars) {
  $element = $vars['element'];
  $attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array(
    'class' => array(),
  );
  $attributes['class'][] = 'geofield-proximity-field-wrapper';
  $attributes['class'][] = 'clearfix';
  $wrapper_attributes = array();
  $wrapper_attributes['class'][] = 'clearfix';
  if (isset($element['#children'])) {
    $element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
  }
  $output = '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
  return $output;
}
function theme_geofield_latlon($vars) {
  return drupal_render($vars['element']['lat']) . drupal_render($vars['element']['lon']) . drupal_render($vars['element']['geocode']);
}

/**
 * Returns options for radius of the Earth.
 */
function geofield_radius_options() {
  return array(
    GEOFIELD_KILOMETERS => t('Kilometers'),
    GEOFIELD_METERS => t('Meters'),
    GEOFIELD_MILES => t('Miles'),
    GEOFIELD_YARDS => t('Yards'),
    GEOFIELD_FEET => t('Feet'),
    GEOFIELD_NAUTICAL_MILES => t('Nautical Miles'),
  );
}

Functions

Namesort descending Description
geofield_bounds_element_process Process function for geofield_bounds.
geofield_bounds_element_validate Element validation function for geofield_latlon.
geofield_element_info Implements hook_element_info().
geofield_latlon_element_process Process function for geofield_latlon.
geofield_latlon_element_validate Element validation function for geofield_latlon.
geofield_proximity_element_process Process function for the proximity form element
geofield_proximity_search_validate Validate the geofield proximity search form item
geofield_radius_options Returns options for radius of the Earth.
geofield_theme
theme_geofield_latlon
theme_geofield_proximity Theme wrapper for form item

Constants

Namesort descending Description
GEOFIELD_FEET Diameter of the Earth in feet.
GEOFIELD_KILOMETERS Diameter of the Earth in kilometers.
GEOFIELD_METERS Diameter of the Earth in meters.
GEOFIELD_MILES Diameter of the Earth in miles.
GEOFIELD_NAUTICAL_MILES Diameter of the Earth in nautical miles.
GEOFIELD_YARDS Diameter of the Earth in yards.