You are here

leaflet_widget.module in Leaflet Widget for Geofield 7

Same filename and directory in other branches
  1. 7.2 leaflet_widget.module

File

leaflet_widget.module
View source
<?php

/**
 * Implements hook_field_widget_info().
 */
function leaflet_widget_field_widget_info() {
  $widgets = array();
  $base_layers = leaflet_widget_base_layers();
  $urls = array_keys($base_layers);
  $widgets['leaflet_widget_widget'] = array(
    'label' => 'Leaflet.widget',
    'description' => 'Provides a map powered by Leaflet and Leaflet.widget.',
    'field types' => array(
      'geofield',
    ),
    'settings' => array(
      'map' => array(
        'base_url' => array_shift($urls),
        'center' => array(
          'lat' => 0.0,
          'lng' => 0.0,
        ),
        'auto_center' => TRUE,
        'zoom' => 10,
      ),
    ),
    'behaviors' => array(
      'multiple values' => FIELD_BEHAVIOR_CUSTOM,
      'default value' => FIELD_BEHAVIOR_NONE,
    ),
  );
  return $widgets;
}

/**
 * Implements hook_field_widget_settings_form().
 */
function leaflet_widget_field_widget_settings_form($field, $instance) {
  $form = array();
  $settings = $instance['widget']['settings'];
  switch ($instance['widget']['type']) {
    case 'leaflet_widget_widget':
      $form['map'] = array(
        '#type' => 'fieldset',
        '#title' => 'Default map settings',
      );
      $form['map']['base_url'] = array(
        '#type' => 'select',
        '#title' => 'Leaflet.draw widget settings',
        '#default_value' => $settings['map']['base_url'],
        '#options' => leaflet_widget_base_layers(),
      );
      $form['map']['center'] = array(
        '#type' => 'fieldset',
        '#collapsed' => TRUE,
        '#collapsible' => TRUE,
        '#title' => 'Default map center',
      );
      $form['map']['center']['lat'] = array(
        '#type' => 'textfield',
        // 'hidden',
        '#title' => 'Latitude',
        '#default_value' => $settings['map']['center']['lat'],
        '#required' => TRUE,
      );
      $form['map']['center']['lng'] = array(
        '#type' => 'textfield',
        // 'hidden',
        '#title' => 'Longtitude',
        '#default_value' => $settings['map']['center']['lng'],
        '#required' => TRUE,
      );
      $form['map']['auto_center'] = array(
        '#type' => 'checkbox',
        '#title' => 'Automatically center map on existing features',
        '#description' => "This option overrides the widget's default center.",
        '#default_value' => $settings['map']['auto_center'],
      );
      $form['map']['zoom'] = array(
        '#type' => 'textfield',
        // 'hidden',
        '#title' => 'Default zoom level',
        '#default_value' => $settings['map']['zoom'],
        '#required' => TRUE,
      );
      break;
  }
  return $form;
}

/**
 * Implements hook_field_widget_form().
 */
function leaflet_widget_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $settings = $instance['widget']['settings'];
  $widget = geofield_get_base_element($element, $items, $delta);
  $widget['#type'] = 'fieldset';
  switch ($instance['widget']['type']) {
    case 'leaflet_widget_widget':
      $id = 'leaflet-widget_' . str_replace('_', '-', $instance['field_name']);
      $class = 'leaflet-widget';
      $style = 'height: 300px;';
      $settings['map']['widget'] = array();
      $settings['map']['widget']['attach'] = "{$id}-input";
      $settings['map']['widget']['multiple'] = FALSE;
      $settings['map']['widget']['autoCenter'] = $settings['map']['auto_center'];
      if ($field['cardinality'] != 1) {
        $settings['map']['widget']['multiple'] = TRUE;

        // Leaflet.widget treats multiple == true && !cardinality as 'unlimited'.
        $settings['map']['widget']['cardinality'] = $field['cardinality'] > 0 ? $field['cardinality'] : 0;
      }

      // Provide container markup for map form element.
      $container = "<div id=\"{$id}\" class=\"{$class}\" style=\"{$style}\"></div>";
      $widget['leaflet_widget'] = array(
        '#markup' => $container,
      );

      // Overriding Geofield's validation handler.
      $widget['#element_validate'] = array(
        'leaflet_widget_widget_validate',
      );

      // Tell Geofield to expect GeoJSON instead of WKT.
      $widget['input_format']['#value'] = 'geojson';

      // Prepare existing field values to be rendered in widget.
      $collection = leaflet_widget_widget_prepare_items($items);

      // Set default value incase form is submitted without javascript enabled.
      $widget['wkt']['#default_value'] = drupal_json_encode($collection);
      $widget['wkt']['#attributes']['id'] = $settings['map']['widget']['attach'];

      // Include javascript.
      $widget['#attached']['library'][] = array(
        'leaflet_widget',
        'widget',
      );

      // Settings and geo-data are passed to the widget keyed by field id.
      $widget['#attached']['js'][] = array(
        'type' => 'setting',
        'data' => array(
          'leaflet_widget_widget' => array(
            $id => $settings,
          ),
        ),
      );
      break;
  }
  return $widget;
}
function leaflet_widget_widget_prepare_items($items) {
  $features = array();
  foreach ($items as $item) {
    if (isset($item['wkt'])) {
      $features[] = leaflet_widget_geojson_feature($item['wkt']);
    }
  }
  return leaflet_widget_geojson_feature_collection($features);
}
function leaflet_widget_widget_validate($element, &$form_state) {
  $geophp = geophp_load();
  if (!$geophp) {
    return FALSE;
  }
  $geojson = json_decode($element['wkt']['#value']);
  $results = array();
  if ($geojson->type === 'FeatureCollection') {
    foreach ($geojson->features as $feature) {
      $results[] = array_merge($results, leaflet_widget_process_geojson($feature));
    }
  }
  else {
    $results = array(
      leaflet_widget_process_geojson($geojson),
    );
  }
  form_set_value($element, $results, $form_state);
}
function leaflet_widget_process_geojson($geojson) {
  $geom = geoPHP::load($geojson, 'json');
  $type = $geom
    ->geometryType();
  $result = array(
    'wkt' => $geom
      ->out('wkt'),
  );
  geofield_compute_values($result, 'wkt');
  return $result;
}

/**
 * Implements hook_library().
 */
function leaflet_widget_library() {
  $path = drupal_get_path('module', 'leaflet_widget');
  $leaflet_widget = libraries_get_path('Leaflet.widget');
  $libraries = array();
  $libraries['widget'] = array(
    'title' => 'Widget behavior',
    'version' => '1.x',
    'js' => array(
      "{$path}/js/widget.js" => array(),
    ),
    'dependencies' => array(
      array(
        'leaflet_widget',
        'Leaflet.widget',
      ),
    ),
  );
  $libraries['Leaflet.widget'] = array(
    'title' => 'Leaflet.widget',
    'version' => '1.x',
    'css' => array(
      "{$leaflet_widget}/dist/Leaflet.widget.min.css" => array(),
    ),
    'js' => array(
      "{$leaflet_widget}/dist/Leaflet.widget.js" => array(),
    ),
    'dependencies' => array(
      array(
        'leaflet_widget',
        'Leaflet.draw',
      ),
    ),
  );
  $libraries['Leaflet.draw'] = array(
    'title' => 'Leaflet.draw',
    'version' => '1.x',
    'css' => array(
      "{$leaflet_widget}/lib/Leaflet.draw/leaflet.draw.css" => array(),
    ),
    'js' => array(
      "{$leaflet_widget}/lib/Leaflet.draw/leaflet.draw-src.js" => array(),
    ),
    'dependencies' => array(
      array(
        'leaflet_widget',
        'Leaflet',
      ),
    ),
  );

  // If available, use the same Leaflet as Leaflet module. Otherwise use the
  // one bundled with Leaflet.widget.
  $leaflet = libraries_get_path('leaflet');
  $leaflet = !empty($leaflet) ? "{$leaflet}/dist/" : "{$leaflet_widget}/lib/Leaflet/";
  $libraries['Leaflet'] = array(
    'title' => 'Leaflet (Leaflet Widget)',
    'version' => '0.4.5',
    'css' => array(
      "{$leaflet}/leaflet.css" => array(),
      "{$leaflet}/leaflet.ie.css" => array(
        'browsers' => array(
          'IE' => 'lte IE 8',
        ),
      ),
    ),
    'js' => array(
      "{$leaflet}/leaflet-src.js" => array(),
    ),
  );
  return $libraries;
}
function leaflet_widget_geojson_feature_collection($features, $properties = array()) {
  if (!is_array($features)) {
    $features = array(
      $features,
    );
  }
  return array(
    'type' => 'FeatureCollection',
    'features' => $features,
  );
}
function leaflet_widget_geojson_feature($wkt, $properties = array()) {
  $geophp = geophp_load();
  if (!$geophp) {
    return FALSE;
  }
  $geometry = geoPHP::load($wkt, 'wkt');
  return array(
    'type' => 'Feature',
    'geometry' => json_decode($geometry
      ->out('json')),
    'properties' => $properties,
  );
}

/**
 * Implements hook_leaflet_widget_base_layers().
 */
function leaflet_widget_leaflet_widget_base_layers() {
  return array(
    'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' => 'OSM Mapnik',
  );
}
function leaflet_widget_base_layers() {
  $options = array();
  if (module_exists('leaflet')) {
    foreach (leaflet_map_get_info() as $id => $map) {
      foreach ($map['layers'] as $layer_id => $layer) {
        $options[$layer['urlTemplate']] = "{$id} - {$layer_id}";
      }
    }
  }
  return array_merge($options, module_invoke_all('leaflet_widget_base_layers'));
}