diff --git a/leaflet.drupal.js b/leaflet.drupal.js
index 36097f9..d33844b 100644
--- a/leaflet.drupal.js
+++ b/leaflet.drupal.js
@@ -1,39 +1,53 @@
 (function($) {
 
 Drupal.behaviors.leaflet = {
+
   attach: function (context, settings) {
+    var maps = {}, bounds = {};
 
     $(settings.leaflet).each(function() {
-      // bail if the map already exists
-      var container = L.DomUtil.get(this.mapId);
-      if (container._leaflet) {
-        return false;
-      }
+      var lMap;
 
       // load a settings object with all of our map settings
       var settings = {};
-      var bounds = [];
       for (var setting in this.map.settings) {
         settings[setting] = this.map.settings[setting];
       }
-      
-      // instantiate our new map
-      var lMap = new L.Map(this.mapId, settings);
 
-      // add map layers
-      var layers = {}, overlays = {};
-      var i = 0;
-      for (var key in this.map.layers) {
-				var layer = this.map.layers[key];
-        var map_layer = Drupal.leaflet.create_layer(layer, key);
+      // instantiate our new map if not adding features to existing
+      if (maps[this.mapId] && !this.render) {
+        lMap = maps[this.mapId];
+      } else {
+        lMap = new L.Map(this.mapId, settings);
+        maps[this.mapId] = lMap;
+        bounds[this.mapId] = [];
+
+        // add map layers
+        var layers = {}, overlays = {};
+        var i = 0;
+        for (var key in this.map.layers) {
+          var layer = this.map.layers[key];
+          var map_layer = Drupal.leaflet.create_layer(layer, key);
+
+          layers[key] = map_layer;
+
+          // add the  layer to the map
+          if (i == 0) {
+            lMap.addLayer(map_layer);
+          }
+          i++;
+        }
 
-        layers[key] = map_layer;
+        // add layer switcher
+        if (this.map.settings.layerControl) {
+          lMap.addControl(new L.Control.Layers(layers, overlays));
+        }
 
-        // add the  layer to the map
-        if (i == 0) {
-          lMap.addLayer(map_layer);
+        // add attribution
+        if (this.map.settings.attributionControl && this.map.attribution) {
+          lMap.attributionControl.setPrefix(this.map.attribution.prefix);
+          lMap.attributionControl.addAttribution(this.map.attribution.text);
         }
-        i++;
       }
 
       // add features
@@ -48,8 +62,8 @@ Drupal.behaviors.leaflet = {
             var groupFeature = feature.features[groupKey];
             lFeature = leaflet_create_feature(groupFeature, bounds);
             if (groupFeature.popup) {
-     	        lFeature.bindPopup(groupFeature.popup);
-     	      }
+               lFeature.bindPopup(groupFeature.popup);
+             }
             lGroup.addLayer(lFeature);
           }
 
@@ -59,32 +73,21 @@ Drupal.behaviors.leaflet = {
           lMap.addLayer(lGroup);
         }
         else {
-          lFeature = leaflet_create_feature(feature, bounds);
+          lFeature = leaflet_create_feature(feature, bounds[this.mapId]);
           lMap.addLayer(lFeature);
 
           if (feature.popup) {
-   	        lFeature.bindPopup(feature.popup);
-   	      }
+             lFeature.bindPopup(feature.popup);
+           }
         }
       }
 
-      // add layer switcher
-      if (this.map.settings.layerControl) {
-        lMap.addControl(new L.Control.Layers(layers, overlays));
-      }
-
       // either center the map or set to bounds
       if (this.map.center) {
         lMap.setView(new L.LatLng(this.map.center.lat, this.map.center.lon), this.map.settings.zoom);
       }
       else {
-        lMap.fitBounds(new L.LatLngBounds(bounds));
-      }
-
-      // add attribution
-      if (this.map.settings.attributionControl && this.map.attribution) {
-        lMap.attributionControl.setPrefix(this.map.attribution.prefix);
-        lMap.attributionControl.addAttribution(this.map.attribution.text);
+        lMap.fitBounds(new L.LatLngBounds(bounds[this.mapId]));
       }
 
       // add the leaflet map to our settings object to make it accessible
@@ -148,28 +151,28 @@ Drupal.behaviors.leaflet = {
       return lFeature;
     }
 
-		function leaflet_create_point(marker, bounds) {
+    function leaflet_create_point(marker, bounds) {
       var latLng = new L.LatLng(marker.lat, marker.lon);
       bounds.push(latLng);
-			var lMarker;
+      var lMarker;
       if (marker.icon) {
         var icon = new L.Icon(marker.icon.iconUrl);
 
         // override applicable marker defaults
         if (marker.icon.iconSize) {
-          icon.iconSize = new L.Point(parseInt(marker.icon.iconSize.x), parseInt(marker.icon.iconSize.y));
+          icon.iconSize = new L.Point(parseInt(marker.icon.iconSize.x, 10), parseInt(marker.icon.iconSize.y, 10));
         }
         if (marker.icon.iconAnchor) {
-          icon.iconAnchor = new L.Point(parseFloat(marker.icon.iconAnchor.x), parseFloat(marker.icon.iconAnchor.y));
+          icon.iconAnchor = new L.Point(parseInt(marker.icon.iconAnchor.x, 10), parseFloat(marker.icon.iconAnchor.y, 10));
         }
         if (marker.icon.popupAnchor) {
-          icon.popupAnchor = new L.Point(parseFloat(marker.icon.popupAnchor.x), parseFloat(marker.icon.popupAnchor.y));
+          icon.popupAnchor = new L.Point(parseInt(marker.icon.popupAnchor.x, 10), parseFloat(marker.icon.popupAnchor.y, 10));
         }
         if (marker.icon.shadowUrl !== undefined) {
           icon.shadowUrl = marker.icon.shadowUrl;
         }
         if (marker.icon.shadowSize) {
-          icon.shadowSize = new L.Point(parseInt(marker.icon.shadowSize.x), parseInt(marker.icon.shadowSize.y));
+          icon.shadowSize = new L.Point(parseInt(marker.icon.shadowSize.x, 10), parseInt(marker.icon.shadowSize.y, 10));
         }
 
         lMarker = new L.Marker(latLng, {icon: icon});
@@ -177,28 +180,28 @@ Drupal.behaviors.leaflet = {
       else {
         lMarker = new L.Marker(latLng);
       }
-      return lMarker;		
-		}
-		
-		function leaflet_create_linestring(polyline, bounds) {
-			var latlngs = [];
-			for (var i=0; i < polyline.points.length; i++) {
-				var latlng = new L.LatLng(polyline.points[i].lat, polyline.points[i].lon);
+      return lMarker;
+    }
+
+    function leaflet_create_linestring(polyline, bounds) {
+      var latlngs = [];
+      for (var i=0; i < polyline.points.length; i++) {
+        var latlng = new L.LatLng(polyline.points[i].lat, polyline.points[i].lon);
         latlngs.push(latlng);
         bounds.push(latlng);
-			}
-			return new L.Polyline(latlngs);			
-		}
-		
-		function leaflet_create_polygon(polygon, bounds) {
-			var latlngs = [];
-			for (var i=0; i < polygon.points.length; i++) {
-				var latlng = new L.LatLng(polygon.points[i].lat, polygon.points[i].lon);
+      }
+      return new L.Polyline(latlngs);
+    }
+
+    function leaflet_create_polygon(polygon, bounds) {
+      var latlngs = [];
+      for (var i=0; i < polygon.points.length; i++) {
+        var latlng = new L.LatLng(polygon.points[i].lat, polygon.points[i].lon);
         latlngs.push(latlng);
         bounds.push(latlng);
-			}
-			return new L.Polygon(latlngs);
-		}
+      }
+      return new L.Polygon(latlngs);
+    }
 
     function leaflet_create_multipoly(multipoly, bounds) {
       var polygons = [];
diff --git a/leaflet.formatters.inc b/leaflet.formatters.inc
index f145391..d9e16ef 100644
--- a/leaflet.formatters.inc
+++ b/leaflet.formatters.inc
@@ -6,11 +6,11 @@
 function leaflet_field_formatter_info() {
   $formatters = array();
 
-  if (module_exists('geofield')) {  
+  if (module_exists('geofield')) {
     $formatters['geofield_leaflet'] = array(
       'label' => t('Leaflet'),
       'field types' => array('geofield'),
-      'settings' => array('leaflet_map' => '', 'icon' => ''),
+      'settings' => array('leaflet_map' => '', 'icon' => '', 'popup_text' => '', 'marker_icon' => '', 'merge_multiple' => FALSE),
     );
   }
 
@@ -28,7 +28,7 @@ function leaflet_field_formatter_settings_form($field, $instance, $view_mode, $f
 
   if ($display['type'] == 'geofield_leaflet') {
     $options = array('' => t('-- Select --'));
-    foreach(leaflet_map_get_info() as $key => $map) {
+    foreach (leaflet_map_get_info() as $key => $map) {
       $options[$key] = t($map['label']);
     }
 
@@ -39,98 +39,44 @@ function leaflet_field_formatter_settings_form($field, $instance, $view_mode, $f
       '#default_value' => $settings['leaflet_map'],
       '#required' => TRUE,
     );
-    $element['icon'] = array(
-      '#title' => t('Map Icon'),
-      '#type' => 'fieldset',
-      '#collapsible' => TRUE,
-      '#collapsed' => !isset($settings['icon']['iconUrl']),
-    );
-    $element['icon']['iconUrl'] = array(
-      '#title' => t('Icon URL'),
-      '#description' => t('Can be an absolute or relative URL.'),
-      '#type' => 'textfield',
-      '#maxlength' => 999,
-      '#default_value' => $settings['icon']['iconUrl'],
-      '#element_validate' => array('leaflet_icon_validate')
-    );
-    $element['icon']['shadowUrl'] = array(
-      '#title' => t('Icon Shadow URL'),
-      '#type' => 'textfield',
-      '#maxlength' => 999,
-      '#default_value' => $settings['icon']['shadowUrl'],
-      '#element_validate' => array('leaflet_icon_validate')
-    );
 
-    $element['icon']['iconSize'] = array(
-      '#title' => t('Icon Size'),
-      '#type' => 'fieldset',
-      '#collapsible' => FALSE,
-      '#description' => t('Size of the icon image in pixels.')
-    );
-    $element['icon']['iconSize']['x'] = array(
-      '#title' => t('Width'),
-      '#type' => 'textfield',
-      '#maxlength' => 3,
-      '#size' => 3,
-      '#default_value' => isset($settings['icon']['iconSize']['x']) ? $settings['icon']['iconSize']['x'] : '',
-      '#element_validate' => array('element_validate_integer_positive'),
-    );
-    $element['icon']['iconSize']['y'] = array(
-      '#title' => t('Height'),
-      '#type' => 'textfield',
-      '#maxlength' => 3,
-      '#size' => 3,
-      '#default_value' => isset($settings['icon']['iconSize']['y']) ? $settings['icon']['iconSize']['y'] : '',
-      '#element_validate' => array('element_validate_integer_positive'),
-    );
+    $entity_fields = field_info_instances($instance['entity_type'], $instance['bundle']);
+    $field_options = array('' => t('-- Select --'));
+    foreach ($entity_fields as $name => $field) {
+      if ($field['widget']['module'] == 'text' &&  $name != $this_field['field_name']) {
+        $field_options[$name] = $field['label'];
+      }
+    }
 
-    $element['icon']['iconAnchor'] = array(
-      '#title' => t('Icon Anchor'),
-      '#type' => 'fieldset',
-      '#collapsible' => FALSE,
-      '#description' => t('The coordinates of the "tip" of the icon (relative to
-        its top left corner). The icon will be aligned so that this point is at the marker\'s geographical location.')
-    );
-    $element['icon']['iconAnchor']['x'] = array(
-      '#title' => t('X'),
-      '#type' => 'textfield',
-      '#maxlength' => 3,
-      '#size' => 3,
-      '#default_value' => isset($settings['icon']['iconAnchor']['x']) ? $settings['icon']['iconAnchor']['x'] : '',
-      '#element_validate' => array('element_validate_number'),
-    );
-    $element['icon']['iconAnchor']['y'] = array(
-      '#title' => t('Y'),
-      '#type' => 'textfield',
-      '#maxlength' => 3,
-      '#size' => 3,
-      '#default_value' => isset($settings['icon']['iconAnchor']['y']) ? $settings['icon']['iconAnchor']['y'] : '',
-      '#element_validate' => array('element_validate_number'),
+    $element['popup_text'] = array(
+      '#title' => t('Popup content'),
+      '#type' => 'select',
+      '#options' => $field_options,
+      '#default_value' => $settings['popup_text'],
+      '#required' => FALSE,
     );
 
-    $element['icon']['popupAnchor'] = array(
-      '#title' => t('Popup Anchor'),
-      '#type' => 'fieldset',
-      '#collapsible' => FALSE,
-      '#description' => t('The point from which the marker popup opens, relative
-        to the anchor point.')
+    $pin_options = array_merge(
+      array('' => t('-- Select --')),
+      drupal_map_assoc(array_keys(leaflet_icon_get_info()))
     );
-    $element['icon']['popupAnchor']['x'] = array(
-      '#title' => t('X'),
-      '#type' => 'textfield',
-      '#maxlength' => 3,
-      '#size' => 3,
-      '#default_value' => isset($settings['icon']['popupAnchor']['x']) ? $settings['icon']['popupAnchor']['x'] : '',
-      '#element_validate' => array('element_validate_number'),
+    $element['marker_icon'] = array(
+      '#title' => t('Leaflet Marker Icon'),
+      '#type' => 'select',
+      '#options' => $pin_options,
+      '#default_value' => $settings['marker_icon'],
+      '#required' => FALSE,
     );
-    $element['icon']['popupAnchor']['y'] = array(
-      '#title' => t('Y'),
-      '#type' => 'textfield',
-      '#maxlength' => 3,
-      '#size' => 3,
-      '#default_value' => isset($settings['icon']['popupAnchor']['y'])  ?$settings['icon']['popupAnchor']['y'] : '',
-      '#element_validate' => array('element_validate_number'),
+
+    $element['merge_multiple'] = array(
+      '#title' => t('Merge geofield maps'),
+      '#description' => t('If there are multiple geofields with the same map, show all markers on one instance.'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['merge_multiple'],
+      '#return_value' => 1,
+      '#required' => FALSE,
     );
+
   }
 
   return $element;
@@ -171,25 +117,47 @@ function leaflet_field_formatter_settings_summary($field, $instance, $view_mode)
 function leaflet_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
   $element = array();
   $settings = $display['settings'];
+  $geofields = &drupal_static(__FUNCTION__);
 
   switch ($display['type']) {
     case 'geofield_leaflet':
-      $map = leaflet_map_get_info($settings['leaflet_map']);
+      $render = TRUE;
+
+      // check for already rendered maps
+      if (isset($geofields[$settings['leaflet_map']])) {
+        $geofields[$settings['leaflet_map']] += 1;
+      }
+      else {
+        $geofields[$settings['leaflet_map']] = 1;
+      }
+
+      if ($settings['merge_multiple']) {
+        $render = ($geofields[$settings['leaflet_map']] == 1); // only render first map
+        $map_key = md5($settings['leaflet_map']); // same key for all instances
+      }
+      else {
+        $map_key = md5($settings['leaflet_map']) . '_' . $geofields[$settings['leaflet_map']]; // unique key per instance
+      }
 
+      $map = leaflet_map_get_info($settings['leaflet_map']);
       $features = leaflet_process_geofield($items);
 
-      // if only a single feature, set the popup content to the entity title
-      if (count($items) == 1) {
-        $features[0]['popup'] = entity_label($entity_type, $entity);
+      if (!empty($settings['marker_icon'])) {
+        foreach ($features as &$feature) {
+          if ($feature['type'] == 'point') {
+            $feature['icon'] = leaflet_build_jsicon($settings['marker_icon']);
+          }
+        }
       }
 
-      if (!empty($settings['icon']) && isset($settings['icon']['iconUrl'])) {
-        foreach($features as $key => $feature) {
-          $features[$key]['icon'] = $settings['icon'];
+      if (!empty($settings['popup_text'])) {
+        $popup_field = field_get_items('node', $entity, $settings['popup_text'], $langcode);
+        for ($i=0; $i<min(count($features), count($popup_field)); $i++) {
+          $features[$i]['popup'] = $popup_field[$i]['value'];
         }
       }
 
-      $element[0] = array('#markup' => leaflet_render_map($map, $features));
+      $element[0] = array('#markup' => leaflet_render_map($render, $map_key, $map, $features));
 
       break;
   }
@@ -282,3 +250,11 @@ function leaflet_process_geofield($items = array()) {
 
   return $data;
 }
+
+function leaflet_build_jsicon($name) {
+  $markers = leaflet_icon_get_info();
+  if (isset($markers[$name])) {
+    return $markers[$name];
+  }
+  return NULL;
+}
diff --git a/leaflet.info b/leaflet.info
index 908a280..94333c4 100644
--- a/leaflet.info
+++ b/leaflet.info
@@ -2,6 +2,8 @@ name = Leaflet
 description = Integration with the Leaflet map scripting library.
 core = 7.x
 
+configure = admin/config/leaflet
+
 dependencies[] = libraries
 
 files[] = leaflet.formatters.inc
diff --git a/leaflet.module b/leaflet.module
index 34106d9..cc9e24a 100644
--- a/leaflet.module
+++ b/leaflet.module
@@ -1,5 +1,6 @@
 <?php
 require_once ('leaflet.formatters.inc');
+require_once ('leaflet.settings.inc');
 
 /**
  * Implements hook_requirements().
@@ -72,24 +73,26 @@ function leaflet_library() {
 /**
  * Load all Leaflet required client files and return markup for a map.
  *
+ * @param bool $render render map or just add points to existing
  * @param array $map
  * @param array $features
  * @param string $height
  *
  * @return string map markup
  */
-function leaflet_render_map($map, $features = array(), $height = '400px') {
-  $map_id = 'leaflet_map_' . md5(serialize($features) . serialize($features));
+function leaflet_render_map($render, $instance, $map, $features = array(), $height = '400px') {
+  $map_id = 'leaflet_map_' . $instance;
   drupal_add_library('leaflet', 'leaflet');
   drupal_add_js(drupal_get_path('module', 'leaflet') . '/leaflet.drupal.js');
   $settings = array(
     'mapId' => $map_id,
     'map' => $map,
     'features' => $features,
+    'render' => $render
   );
   drupal_add_js(array('leaflet' => array($settings)), 'setting');
 
-  return theme('leaflet_map', array('map_id' => $map_id, 'height' => $height));
+  return ($render ? theme('leaflet_map', array('map_id' => $map_id, 'height' => $height)) : NULL);
 }
 
 /**
@@ -98,69 +101,125 @@ function leaflet_render_map($map, $features = array(), $height = '400px') {
  * @param string $map
  */
 function leaflet_map_get_info($map = NULL) {
+  return leaflet_data_get_info('leaflet_map_info', $map);
+}
+
+/**
+ * Set Leaflet map definitions.
+ *
+ * @param string $info
+ */
+function leaflet_map_set_info($info) {
+  leaflet_data_set_info('leaflet_map_info', $info);
+}
+
+/**
+ * Get Leaflet icon definitions.
+ *
+ * @param string $icon
+ */
+function leaflet_icon_get_info($icon = NULL) {
+  return leaflet_data_get_info('leaflet_icon_info', $icon);
+}
+
+/**
+ * Set Leaflet icon definitions.
+ *
+ * @param string $info
+ */
+function leaflet_icon_set_info($info) {
+  leaflet_data_set_info('leaflet_icon_info', $info);
+}
+
+/**
+ * Get stored settings (map and icons).
+ *
+ * @param string $data setting type
+ */
+function leaflet_data_get_info($data, $param = NULL) {
   static $drupal_static_fast;
   if (!isset($drupal_static_fast)) {
-    $drupal_static_fast['leaflet_map_info'] = &drupal_static(__FUNCTION__);
+    $drupal_static_fast[$data] = &drupal_static($data);
   }
-  $map_info = &$drupal_static_fast['leaflet_map_info'];
+  $info = &$drupal_static_fast[$data];
 
-  if (empty($map_info)) {
-    if ($cache = cache_get("leaflet_map_info")) {
-      $map_info = $cache->data;
+  if (empty($info)) {
+    if ($cache = cache_get($data)) {
+      $info = $cache->data;
     }
     else {
-      $map_info = module_invoke_all('leaflet_map_info');
+      $info = variable_get($data, array()); //module_invoke_all($data);
 
       // Let other modules alter the map info.
-      drupal_alter('leaflet_map_info', $map_info);
+      drupal_alter($data, $info);
 
-      cache_set("leaflet_map_info", $map_info);
+      cache_set($data, $info);
     }
+    $drupal_static_fast[$data] = $info;
   }
 
-  if (empty($map)) {
-    return $map_info;
+  if (empty($param)) {
+    return $info;
   }
-  elseif (isset($map_info[$map])) {
-    return $map_info[$map];
+  elseif (isset($info[$param])) {
+    return $info[$param];
   }
 }
 
 /**
- * Implements hook_leaflet_map_info() to return a default map.
+ * Set stored data.
+ *
+ * @param string $data setting type
+ * @param array $info setting data
+ */
+function leaflet_data_set_info($data, $info) {
+  variable_set($data, $info);
+
+  // replace static & cache leaflet_data_get_info
+  $drupal_static = &drupal_static($data);
+  if (isset($drupal_static[$data])) {
+  $drupal_static[$data] = $info;
+  }
+  cache_set($data, $info);
+}
+
+/**
+ * Implements hook_leaflet_map_info_alter() to return a default map
+ * if there are no stored settings.
  *
  * @return array
  */
-function leaflet_leaflet_map_info() {
-  return array(
-    'OSM Mapnik' =>
-    array(
-      'label' => 'OSM Mapnik',
-      'description' => t('Leaflet default map.'),
-      'settings' => array(
-        'zoom' => 18,
-        'minZoom' => 0,
-        'maxZoom' => 18,
-        'dragging' => TRUE,
-        'touchZoom' => TRUE,
-        'scrollWheelZoom' => TRUE,
-        'doubleClickZoom' => TRUE,
-        'zoomControl' => TRUE,
-        'attributionControl' => TRUE,
-        'trackResize' => TRUE,
-        'fadeAnimation' => TRUE,
-        'zoomAnimation' => TRUE,
-        'closePopupOnClick' => TRUE,
-      ),
-      'layers' => array(
-        'earth' => array(
-          'urlTemplate' => 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
-          'options' => array(
-            'attribution' => 'OSM Mapnik'
-          )
+function leaflet_leaflet_map_info_alter(&$info) {
+  if (!(is_array($info) && count($info) > 0)) {
+    $info = array(
+      'OSM Mapnik' => array(
+        'label' => 'OSM Mapnik',
+        'description' => t('Leaflet default map.'),
+        'settings' => array(
+          'zoom' => 18,
+          'minZoom' => 0,
+          'maxZoom' => 18,
+          'dragging' => TRUE,
+          'touchZoom' => TRUE,
+          'scrollWheelZoom' => TRUE,
+          'doubleClickZoom' => TRUE,
+          'zoomControl' => TRUE,
+          'attributionControl' => TRUE,
+          'trackResize' => TRUE,
+          'fadeAnimation' => TRUE,
+          'zoomAnimation' => TRUE,
+          'closePopupOnClick' => TRUE,
+        ),
+        'layers' => array(
+          'earth' => array(
+            'urlTemplate' => 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
+            'options' => array(
+              'attribution' => 'OSM Mapnik'
+            )
+          ),
         ),
       ),
-    ),
-  );
+    );
+  }
 }
 
diff --git a/leaflet.settings.inc b/leaflet.settings.inc
new file mode 100644
index 0000000..d2810fb
--- /dev/null
+++ b/leaflet.settings.inc
@@ -0,0 +1,525 @@
+<?php
+/**
+ * @file
+ * Adds Leaflet configuration settings to the Configuration section
+ */
+
+/**
+ * Add admin menu
+ *
+ *
+ */
+function leaflet_menu() {
+
+  $items = array();
+
+  $items['admin/config/leaflet'] = array(
+    'title' => 'Leaflet settings',
+    'description' => 'Settings for Leaflet Maps',
+    'weight' => -5,
+    'page callback' => 'system_admin_menu_block_page',
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+    'file path' => drupal_get_path('module', 'system'),
+  );
+
+  $items['admin/config/leaflet/maps'] = array(
+    'title' => 'Leaflet Maps',
+    'description' => 'List of available Leaflet maps',
+    'page callback' => 'leaflet_map_list',
+    'access arguments' => array('administer site configuration'),
+  );
+
+  $items['admin/config/leaflet/maps/add'] = array(
+    'title' => 'Add Leaflet Map',
+    'description' => 'Add maps',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('leaflet_map_add'),
+    'access arguments' => array('administer site configuration'),
+    'weight' => -2,
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'leaflet.settings.inc'
+  );
+
+  $items['admin/config/leaflet/maps/edit'] = array(
+    'title' => 'Edit Leaflet Map',
+    'description' => 'Edit Leaflet map',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('leaflet_map_edit', 5),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'leaflet.settings.inc'
+  );
+
+  $items['admin/config/leaflet/maps/delete'] = array(
+    'title' => 'Delete Leaflet Map',
+    'description' => 'Delete map',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('leaflet_map_delete', 5),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'leaflet.settings.inc'
+  );
+
+  $items['admin/config/leaflet/icons'] = array(
+    'title' => 'Leaflet Icons',
+    'description' => 'List of available Leaflet marker icons',
+    'page callback' => 'leaflet_icon_list',
+    'access arguments' => array('administer site configuration'),
+  );
+
+  $items['admin/config/leaflet/icons/add'] = array(
+    'title' => 'Add Leaflet Icon',
+    'description' => 'Add icons',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('leaflet_icon_add'),
+    'access arguments' => array('administer site configuration'),
+    'weight' => -2,
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'leaflet.settings.inc'
+  );
+
+  $items['admin/config/leaflet/icons/edit'] = array(
+    'title' => 'Marker Icons',
+    'description' => 'Define custom icons',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('leaflet_icon_edit', 5),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'leaflet.settings.inc'
+  );
+
+  $items['admin/config/leaflet/icons/delete'] = array(
+    'title' => 'Delete Leaflet Icon',
+    'description' => 'Delete icon',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('leaflet_icon_delete', 5),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'leaflet.settings.inc'
+  );
+
+  return $items;
+}
+
+function leaflet_map_name_validate($element, $form_state) {
+  // Check for duplicates.
+  $maps = leaflet_map_get_info();
+
+  if (isset($maps[$element['#value']])) {
+    form_set_error($element['#name'], t('The map name %name is already in use.', array('%name' => $element['#value'])));
+  }
+
+  if (preg_match('/[^0-9a-z_\-]/', $element['#value'])) {
+    form_set_error($element['#name'], t('Please only use lowercase alphanumeric characters, underscores (_), and hyphens (-) for map names.'));
+  }
+}
+
+function leaflet_map_list() {
+  $maps = leaflet_map_get_info();
+
+  $header = array(t('Map name'), t('Label'), t('Description'), array('data' => t('Operations'), 'colspan' => 3));
+  $rows = array();
+  foreach ($maps as $name => $opts) {
+    $row = array();
+    $row[] = l($name, 'admin/config/leaflet/maps/edit/' . $name);
+    $row[] = $opts['label'];
+
+    $link_attributes = array(
+      'attributes' => array(
+        'class' => array('image-style-link'),
+      ),
+    );
+
+    $row[] = $opts['description'];
+    $row[] = l(t('edit'), 'admin/config/leaflet/maps/edit/' . $name, $link_attributes);
+    $row[] = l(t('delete'), 'admin/config/leaflet/maps/delete/' . $name, $link_attributes);
+
+    $rows[] = $row;
+  }
+
+  if (empty($rows)) {
+    $rows[] = array(array(
+      'colspan' => 4,
+      'data' => t('There are currently no maps. <a href="!url">Add a new one</a>.', array('!url' => url('admin/config/leaflet/maps/add'))),
+    ));
+  }
+
+  $markup = theme('table', array('header' => $header, 'rows' => $rows));
+
+  $page = array();
+  $page['leaflet_map_list'] = array(
+    '#markup' => $markup
+  );
+
+  return $page;
+}
+
+function leaflet_layer_settings() {
+  return array(
+    'zoom' => array( 'type' => 'textfield', 'default' => 2 ),
+    'minZoom' => array( 'type' =>  'textfield', 'default' => '0'),
+    'maxZoom' => array( 'type' =>  'textfield', 'default' => 8),
+    'dragging' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'touchZoom' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'scrollWheelZoom' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'doubleClickZoom' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'zoomControl' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'attributionControl' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'trackResize' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'fadeAnimation' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'zoomAnimation' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+    'closePopupOnClick' => array( 'type' =>  'checkbox', 'default' => TRUE  ),
+  );
+}
+
+function leaflet_icon_settings() {
+  return array(
+    'iconUrl' => array( 'type' => 'textfield' ),
+    'shadowUrl' => array( 'type' => 'textfield' ),
+    'iconSize' => array( 'type' => 'point' ),
+    'iconAnchor' => array( 'type' => 'point' ),
+    'popupAnchor' => array( 'type' => 'point' ),
+  );
+}
+
+function leaflet_map_add() {
+  $form = array();
+
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#size' => '64',
+    '#title' => t('Map name'),
+    '#default_value' => '',
+    '#description' => t('The name is used in URLs, use only lowercase alphanumeric characters, underscores (_), and hyphens (-).'),
+    '#element_validate' => array('leaflet_map_name_validate'),
+    '#required' => TRUE,
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Create new map'),
+  );
+
+  return $form;
+}
+
+function leaflet_map_add_submit($form, &$form_state) {
+  $map = array('name' => $form_state['values']['name']);
+  drupal_set_message(t('Map %name was created.', array('%name' => $map['name'])));
+  $form_state['redirect'] = 'admin/config/leaflet/maps/edit/' . $map['name'];
+}
+
+function leaflet_map_delete($map, &$form_state, $map_name) {
+  $form = array();
+  $form['map_name'] = array('#type' => 'hidden', '#value' => $map_name);
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete the map %map?', array('%map' => $map_name)),
+    'admin/config/leaflet/maps',
+    t('Any node/view still using it will broken.'),
+    t('Delete'), t('Cancel')
+  );
+}
+
+function leaflet_map_delete_submit($form, &$form_state) {
+  $values = $form_state['values'];
+  if (!empty($values['map_name']) && !empty($values['confirm']) && $values['confirm'] == 1) {
+    $maps = leaflet_map_get_info();
+    $mapkey = $values['map_name'];
+    if (isset($maps[$mapkey])) {
+      unset($maps[$mapkey]);
+      leaflet_map_set_info($maps);
+      drupal_set_message(t('Map %name was deleted.', array('%name' => $map['name'])));
+    }
+  }
+  $form_state['redirect'] = 'admin/config/leaflet/maps';
+}
+
+function leaflet_map_edit($map, &$form_state, $map_name) {
+  $map = leaflet_map_get_info($map_name);
+
+  $form = array();
+  $form['access'] = array(
+   '#tree' => TRUE
+  );
+
+  $form['label'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Label'),
+    '#default_value' => $map['label'],
+    '#maxlength' => 127,
+    '#required' => TRUE,
+  );
+
+  $form['description'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Description'),
+    '#default_value' => $map['description'],
+    '#maxlength' => 127,
+    '#required' => FALSE,
+  );
+
+  $form['settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#tree' => TRUE
+  );
+
+  $settings = leaflet_layer_settings();
+  foreach ($settings as $sn => $set) {
+    $form['settings'][$sn] = array(
+      '#type' => $set['type'],
+      '#title' => $sn,
+    );
+
+    if (!isset($map['settings'][$sn])) {
+      $form['settings'][$sn]['#default_value'] = (isset($set['default']) ? $set['default'] : NULL);
+    }
+    else {
+      $form['settings'][$sn]['#default_value'] = $map['settings'][$sn];
+    }
+
+    if ($set['type'] == 'textfield') {
+      $form['settings'][$sn]['#size'] = 3;
+    }
+
+    if ($set['type'] == 'checkbox') {
+      $form['settings'][$sn]['#return_value'] = TRUE;
+    }
+  }
+
+  // get first layer, doesn't handle multiple (yet)
+  $layer = reset($map['layers']);
+
+  $form['layers'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Layer'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#tree' => TRUE
+  );
+
+  $form['layers']['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Name'),
+    '#size' => 16,
+    '#default_value' => key($map['layers'])
+  );
+
+  $form['layers']['attribution'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Attribution'),
+    '#default_value' => $layer['options']['attribution']
+  );
+  $form['layers']['url'] = array(
+    '#type' => 'textfield',
+    '#title' => t('URL pattern'),
+    '#default_value' => $layer['urlTemplate']
+  );
+
+  $scheme = drupal_map_assoc(array('tms', 'xyz'));
+  $form['layers']['scheme'] = array(
+    '#type' => 'select',
+    '#title' => t('Scheme'),
+    '#options' => $scheme,
+    '#default_value' => (empty($layer['options']['scheme']) ? '' : $layer['options']['scheme'])
+  );
+
+  $form['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+
+  return $form;
+}
+
+function leaflet_map_edit_submit($form, &$form_state) {
+  $mapkey = current($form_state['build_info']['args']);
+  $map = $form_state['values'];
+  drupal_set_message(t('Map %name was saved.', array('%name' => $map['label'])));
+
+  $layername = $map['layers']['name'];
+  $layerset = array();
+  $layerset[$layername] = array(
+    'urlTemplate' => $map['layers']['url'],
+    'options' => array(
+      'attribution' => $map['layers']['attribution'],
+      'scheme' => $map['layers']['scheme']
+    )
+  );
+
+  $settings = leaflet_layer_settings();
+  foreach ($settings as $key => $set) {
+    if (
+      isset($map['settings'][$key]) &&
+      $set['type'] == 'checkbox' &&
+      $map['settings'][$key] == 0
+    ) {
+      $map['settings'][$key] = FALSE;
+    }
+  }
+
+  $mapset = array(
+    'label' => $map['label'],
+    'description' => $map['description'],
+    'settings' => $map['settings'],
+    'layers' => $layerset
+  );
+
+  $maps = leaflet_map_get_info();
+  $maps[$mapkey] = $mapset;
+  leaflet_map_set_info($maps);
+}
+
+function leaflet_icon_list() {
+  $maps = leaflet_icon_get_info();
+
+  $header = array(t('Icon name'), t('Path'), array('data' => t('Operations'), 'colspan' => 2));
+  $rows = array();
+  foreach ($maps as $name => $opts) {
+    $row = array();
+    $row[] = l($name, 'admin/config/leaflet/icons/edit/' . $name);
+    $row[] = $opts['iconUrl'];
+
+    $link_attributes = array(
+      'attributes' => array(
+        'class' => array('image-style-link'),
+      ),
+    );
+
+    $row[] = l(t('edit'), 'admin/config/leaflet/icons/edit/' . $name, $link_attributes);
+    $row[] = l(t('delete'), 'admin/config/leaflet/icons/delete/' . $name, $link_attributes);
+
+    $rows[] = $row;
+  }
+
+  if (empty($rows)) {
+    $rows[] = array(array(
+      'colspan' => 4,
+      'data' => t('There are currently no icons. <a href="!url">Add a new one</a>.', array('!url' => url('admin/config/leaflet/icons/add'))),
+    ));
+  }
+
+  $markup = theme('table', array('header' => $header, 'rows' => $rows));
+
+  $page = array();
+  $page['leaflet_icon_list'] = array(
+    '#markup' => $markup
+  );
+
+  return $page;
+}
+
+
+function leaflet_icon_add() {
+  $form = array();
+
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#size' => '64',
+    '#title' => t('Icon name'),
+    '#default_value' => '',
+    '#description' => t('The name is used in URLs, use only lowercase alphanumeric characters, underscores (_), and hyphens (-).'),
+    '#element_validate' => array('leaflet_map_name_validate'),
+    '#required' => TRUE,
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Create new icon'),
+  );
+
+  return $form;
+}
+
+function leaflet_icon_add_submit($form, &$form_state) {
+  $map = array('name' => $form_state['values']['name']);
+  drupal_set_message(t('Map %name was created.', array('%name' => $map['name'])));
+  $form_state['redirect'] = 'admin/config/leaflet/icons/edit/' . $map['name'];
+}
+
+function leaflet_icon_edit($map, &$form_state, $icon_name) {
+
+  $icon = leaflet_icon_get_info($icon_name);
+
+  $form = array();
+  $form['access'] = array(
+    '#tree' => TRUE
+  );
+
+  $settings = leaflet_icon_settings();
+  foreach ($settings as $setting => $preset) {
+    $form[$setting]['#title'] = $setting;
+    $form[$setting]['#tree'] = TRUE;
+    switch ($preset['type']) {
+      case 'textfield':
+        $form[$setting]['#type'] = 'textfield';
+        $form[$setting]['#default_value'] = (isset($icon[$setting]) ? $icon[$setting] : '');
+        break;
+      case 'point':
+        $form[$setting]['#type'] = 'fieldset';
+        $form[$setting]['#theme'] = 'leaflet_point_form';
+        $points = array('x', 'y');
+        foreach ($points as $p) {
+          $form[$setting][$p] = array(
+            '#type' => 'textfield',
+            '#title' => t($p),
+            '#size' => 3,
+            '#maxlength' => 3,
+            '#required' => FALSE,
+            '#default_value' => (isset($icon[$setting]) ? (isset($icon[$setting][$p]) ? $icon[$setting][$p] : '') : '')
+          );
+        }
+        break;
+    }
+  }
+
+  $form['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+
+  return $form;
+}
+
+function leaflet_icon_edit_submit($form, &$form_state) {
+
+  $iconkey = current($form_state['build_info']['args']);
+  $settings = leaflet_icon_settings();
+  $icon = array();
+  foreach ($settings as $sn => $set) {
+    if (isset($form_state['values'][$sn])) {
+      $icon[$sn] = $form_state['values'][$sn];
+    }
+  }
+  drupal_set_message(t('Icon %name was saved.', array('%name' => $iconkey)));
+
+  $icons = leaflet_icon_get_info();
+  $icons[$iconkey] = $icon;
+  leaflet_icon_set_info($icons);
+}
+
+function leaflet_icon_delete($icon, &$form_state, $icon_name) {
+  $form = array();
+  $form['icon_name'] = array('#type' => 'hidden', '#value' => $icon_name);
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete the icon %icon?', array('%icon' => $icon_name)),
+    'admin/config/leaflet/icons',
+    t('Any node/view still using it will broken.'),
+    t('Delete'), t('Cancel')
+  );
+}
+
+function leaflet_icon_delete_submit($form, &$form_state) {
+  $values = $form_state['values'];
+  if (!empty($values['icon_name']) && !empty($values['confirm']) && $values['confirm'] == 1) {
+    $icons = leaflet_icon_get_info();
+    $iconkey = $values['icon_name'];
+    if (isset($icons[$iconkey])) {
+      unset($icons[$iconkey]);
+      leaflet_icon_set_info($icons);
+      drupal_set_message(t('Icon %name was deleted.', array('%name' => $icon['name'])));
+    }
+  }
+  $form_state['redirect'] = 'admin/config/leaflet/icons';
+}
