geofield.widgets.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <?php
  2. /**
  3. * @file
  4. * Provides field widget hooks for geofield module.
  5. */
  6. /**
  7. * Implements hook_field_widget_info().
  8. */
  9. function geofield_field_widget_info() {
  10. $widgets = array();
  11. // OpenLayers dependant widget
  12. if (module_exists('openlayers')) {
  13. $widgets['geofield_openlayers'] = array(
  14. 'label' => t('Openlayers Map'),
  15. 'field types' => array('geofield'),
  16. );
  17. }
  18. $widgets['geofield_wkt'] = array(
  19. 'label' => t('Well Known Text (WKT)'),
  20. 'field types' => array('geofield'),
  21. );
  22. $widgets['geofield_geojson'] = array(
  23. 'label' => t('GeoJSON'),
  24. 'field types' => array('geofield'),
  25. );
  26. $widgets['geofield_latlon'] = array(
  27. 'label' => t('Latitude / Longitude'),
  28. 'field types' => array('geofield'),
  29. );
  30. $widgets['geofield_bounds'] = array(
  31. 'label' => t('Bounds'),
  32. 'field types' => array('geofield'),
  33. );
  34. $widgets['geofield_textfields'] = array(
  35. 'label' => t('All Textfields'),
  36. 'field types' => array('geofield'),
  37. );
  38. $widgets['geofield_geolocation'] = array(
  39. 'label' => 'HTML5 Geolocation',
  40. 'field types' => array('geofield'),
  41. );
  42. return $widgets;
  43. }
  44. /**
  45. * Implements hook_field_widget_settings_form().
  46. */
  47. function geofield_field_widget_settings_form($field, $instance) {
  48. $widget = $instance['widget'];
  49. $settings = $widget['settings'];
  50. $form = array();
  51. //TODO: Allow more fine-grained control
  52. if ($widget['type'] == 'geofield_openlayers') {
  53. // Get preset options, filtered to those which have the GeoField behavior and *don't* have the draw features behavior, which is incompatible
  54. $maps = openlayers_maps();
  55. $map_options = array();
  56. foreach ($maps as $map) {
  57. if (array_key_exists('openlayers_behavior_geofield', $map->data['behaviors']) && !array_key_exists('openlayers_behavior_drawfeatures', $map->data['behaviors'])) {
  58. $map_options[$map->name] = $map->title;
  59. }
  60. }
  61. if (empty($map_options)) {
  62. form_set_error('openlayers_map', "Error: You have no compatible openlayers maps. Make sure that at least one preset has the 'GeoField' behavior enabled and that it does not have the 'Draw Features' behavior enabled (which is incompatible).");
  63. }
  64. $form['openlayers_map'] = array(
  65. '#type' => 'select',
  66. '#title' => t('OpenLayers Map'),
  67. '#default_value' => isset($settings['openlayers_map']) ? $settings['openlayers_map'] : 'geofield_widget_map',
  68. '#options' => $map_options,
  69. '#description' => t('Select which OpenLayers map you would like to use. Only maps which have the GeoField behavior may be selected. If your preferred map is not here, add the GeoField behavior to it first. The "Draw Features" bahavior is incompatible - presets with this behavior are not shown.'),
  70. );
  71. $form['data_storage'] = array(
  72. '#type' => 'radios',
  73. '#title' => t('Storage Options'),
  74. '#description' => t('Should the widget only allow simple features (points, lines, or polygons), or should the widget allow for complex features? Note that changing this setting from complex to simple after data has been entered can lead to data loss.'),
  75. '#options' => array(
  76. 'collection' => 'Store as a single collection.',
  77. 'single' => 'Store each simple feature as a separate field.',
  78. ),
  79. '#default_value' => (isset($settings['data_storage'])) ? $settings['data_storage'] : 'collection',
  80. );
  81. }
  82. return $form;
  83. }
  84. /**
  85. * Implements hook_field_widget_form().
  86. */
  87. function geofield_field_widget_form(&$form, &$form_state, $field, $instance,
  88. $langcode, $items, $delta, $base) {
  89. $widget = $instance['widget'];
  90. $settings = $widget['settings'];
  91. $element = geofield_get_base_element($base, $items, $delta);
  92. if ($widget['type'] == 'geofield_wkt') {
  93. $element['wkt']['#title'] = 'Well Known Text';
  94. $element['wkt']['#type'] = 'textarea';
  95. $element['master_column']['#value'] = 'wkt';
  96. }
  97. if ($widget['type'] == 'geofield_geojson') {
  98. $element['wkt']['#title'] = 'GeoJSON';
  99. $element['wkt']['#type'] = 'textarea';
  100. // We're actually displaying as GeoJSON, not wkt. This is confusing.
  101. geophp_load();
  102. $default_value = '';
  103. try {
  104. $wkt = isset($items[$delta]['wkt']) ? $items[$delta]['wkt'] : NULL;
  105. $geometry = geoPHP::load($wkt, 'wkt');
  106. if ($geometry) {
  107. $default_value = $geometry->out('json');
  108. }
  109. } catch (Exception $e) {
  110. // @TODO: Not sure if we should do validation here or not...
  111. }
  112. $element['wkt']['#default_value'] = $default_value;
  113. $element['master_column']['#value'] = 'wkt';
  114. $element['input_format']['#value'] = 'geojson';
  115. }
  116. if ($widget['type'] == 'geofield_latlon') {
  117. $element['lat']['#title'] = 'Latitude';
  118. $element['lat']['#type'] = 'textfield';
  119. $element['lon']['#title'] = 'Longitude';
  120. $element['lon']['#type'] = 'textfield';
  121. $element['master_column']['#value'] = 'latlon';
  122. }
  123. if ($widget['type'] == 'geofield_bounds') {
  124. $element['left']['#title'] = 'Left Longitude';
  125. $element['left']['#type'] = 'textfield';
  126. $element['top']['#title'] = 'Top Latitude';
  127. $element['top']['#type'] = 'textfield';
  128. $element['right']['#title'] = 'Right Longitude';
  129. $element['right']['#type'] = 'textfield';
  130. $element['bottom']['#title'] = 'Bottom Latitude';
  131. $element['bottom']['#type'] = 'textfield';
  132. $element['master_column']['#value'] = 'bounds';
  133. }
  134. if ($widget['type'] == 'geofield_textfields') {
  135. $element['wkt']['#title'] = 'Well Known Text';
  136. $element['wkt']['#type'] = 'textarea';
  137. $element['geo_type']['#title'] = 'Geometry Type';
  138. $element['geo_type']['#type'] = 'textfield';
  139. $element['lat']['#title'] = 'Latitude';
  140. $element['lat']['#type'] = 'textfield';
  141. $element['lon']['#title'] = 'Longitude';
  142. $element['lon']['#type'] = 'textfield';
  143. $element['left']['#title'] = 'Left Longitude';
  144. $element['left']['#type'] = 'textfield';
  145. $element['top']['#title'] = 'Top Latitude';
  146. $element['top']['#type'] = 'textfield';
  147. $element['right']['#title'] = 'Right Longitude';
  148. $element['right']['#type'] = 'textfield';
  149. $element['bottom']['#title'] = 'Bottom Latitude';
  150. $element['bottom']['#type'] = 'textfield';
  151. }
  152. if ($widget['type'] == 'geofield_geolocation') {
  153. $element['#attached']['js'][] = drupal_get_path('module', 'geofield') . '/js/geolocation.js';
  154. $element['lat']['#title'] = 'Latitude';
  155. $element['lat']['#type'] = 'textfield';
  156. $element['lon']['#title'] = 'Longitude';
  157. $element['lon']['#type'] = 'textfield';
  158. $element['master_column']['#value'] = 'latlon';
  159. }
  160. if ($widget['type'] == 'geofield_openlayers') {
  161. $openlayers_map_id = !empty($instance['widget']['settings']['openlayers_map']) ? $instance['widget']['settings']['openlayers_map'] : 'geofield_widget_map';
  162. $element['#openlayers_mapname'] = $openlayers_map_id;
  163. $element['#after_build']= array('geofield_widget_openlayers_afterbuild');
  164. }
  165. return $element;
  166. }
  167. /**
  168. * Callback for afterbuild for widget for js addition to
  169. */
  170. function geofield_widget_openlayers_afterbuild($element, &$form_state) {
  171. drupal_add_js(
  172. array('geofield' => array(
  173. 'data_storage' => (!empty($settings['data_storage'])) ? $settings['data_storage'] : 'collection',
  174. ),
  175. ),
  176. 'setting');
  177. $defaults = array();
  178. $element['helpmap'] = array(
  179. '#markup' => '<div class="form-item geotaxonomy-latlon-helpmap" style="display:block">'
  180. . geofield_form_latlon_map(array(), $element['#openlayers_mapname'])
  181. . '</div>');
  182. $element['helpmap_desc'] = array(
  183. '#markup' => t('<div class="description geofield-help">Use the icons to select what type of feature to draw. Each map can contain one simple feature. Pan and zoom with arrows and the zoom bar.</div>')
  184. );
  185. return $element;
  186. }
  187. /**
  188. * Create LatLon Helper Map.
  189. */
  190. function geofield_form_latlon_map($defaults = array(), $map_name) {
  191. // Pass variables etc. to javascript
  192. // Set up our map to help set lat and lon
  193. // This map will always be projected as 4326 and use just the default map preset
  194. $map_data = openlayers_map_load($map_name);
  195. $map = $map_data->data;
  196. return openlayers_render_map($map);
  197. }
  198. function geofield_get_base_element($base, $items, $delta) {
  199. $element = $base;
  200. // @TODO: Change this to be generic, so that we don't have poor DX to input as WKT.
  201. $element['wkt'] = array(
  202. '#type' => 'hidden',
  203. '#attributes' => array('class' => array('geofield_wkt')),
  204. '#default_value' => isset($items[$delta]['wkt']) ? $items[$delta]['wkt'] : NULL,
  205. );
  206. $element['input_format'] = array(
  207. '#type' => 'value',
  208. '#attributes' => array('class' => array('geofield_input_format')),
  209. '#value' => 'wkt',
  210. );
  211. $element['geo_type'] = array(
  212. '#type' => 'hidden',
  213. '#attributes' => array('class' => array('geofield_geo_type')),
  214. '#default_value' => isset($items[$delta]['geo_type']) ? $items[$delta]['geo_type'] : NULL,
  215. );
  216. $element['lat'] = array(
  217. '#type' => 'hidden',
  218. '#attributes' => array('class' => array('geofield_lat')),
  219. '#default_value' => isset($items[$delta]['lat']) ? $items[$delta]['lat'] : NULL,
  220. );
  221. $element['lon'] = array(
  222. '#type' => 'hidden',
  223. '#attributes' => array('class' => array('geofield_lon')),
  224. '#default_value' => isset($items[$delta]['lon']) ? $items[$delta]['lon'] : NULL,
  225. );
  226. $element['left'] = array(
  227. '#type' => 'hidden',
  228. '#attributes' => array('class' => array('geofield_left')),
  229. '#default_value' => isset($items[$delta]['left']) ? $items[$delta]['left'] : NULL,
  230. );
  231. $element['right'] = array(
  232. '#type' => 'hidden',
  233. '#attributes' => array('class' => array('geofield_right')),
  234. '#default_value' => isset($items[$delta]['right']) ? $items[$delta]['right'] : NULL,
  235. );
  236. $element['bottom'] = array(
  237. '#type' => 'hidden',
  238. '#attributes' => array('class' => array('geofield_bottom')),
  239. '#default_value' => isset($items[$delta]['bottom']) ? $items[$delta]['bottom'] : NULL,
  240. );
  241. $element['top'] = array(
  242. '#type' => 'hidden',
  243. '#attributes' => array('class' => array('geofield_top')),
  244. '#default_value' => isset($items[$delta]['top']) ? $items[$delta]['top'] : NULL,
  245. );
  246. $element['description'] = array(
  247. '#markup' => (!empty($element['#description'])) ? '<div class="description">' . $element['#description'] . '</div>' : '',
  248. );
  249. // Master column is used by element-validate to decide which set of columns it should use to compute all other values.
  250. // By default, wkt is the master-column, all we compute all other values from it. For other widget (such as lat/lon) this will be different
  251. $element['master_column'] = array(
  252. '#type' => 'hidden',
  253. '#value' => 'wkt',
  254. );
  255. // This validate function computes all other columns from the master field
  256. $element['#element_validate'] = array('geofield_element_validate');
  257. return $element;
  258. }
  259. /**
  260. * Geofield Element Validate for GeoJSON widget
  261. */
  262. function geofield_element_geojson_validate($element, &$form_state) {
  263. }
  264. /**
  265. * Geofield Element Validate
  266. *
  267. */
  268. function geofield_element_validate($element, &$form_state) {
  269. $master_column = $element['master_column']['#value'];
  270. $values = array(
  271. 'wkt' => $element['wkt']['#value'],
  272. 'lat' => $element['lat']['#value'] ? geofield_latlon_DMStoDEC($element['lat']['#value']) : '',
  273. 'lon' => $element['lon']['#value'] ? geofield_latlon_DMStoDEC($element['lon']['#value']) : '',
  274. 'top' => $element['top']['#value'],
  275. 'bottom' => $element['bottom']['#value'],
  276. 'right' => $element['right']['#value'],
  277. 'left' => $element['left']['#value'],
  278. );
  279. // Because we have an odd flow to filter potential GeoJSON, we need a flag to determine whether or not to process.
  280. // @TODO: This could be expanded to cover WKT as well.
  281. $geo_process = "PROCESS";
  282. if ($element['input_format']['#value'] == 'geojson' && $values['wkt']) {
  283. // For geojson input, we've hijacked the wkt value.
  284. geophp_load();
  285. try {
  286. $geometry = geoPHP::load($values['wkt'], 'json');
  287. $values['wkt'] = $geometry->out('wkt');
  288. } catch (Exception $e) {
  289. form_set_error($element['wkt']['#name'], 'Please enter valid GeoJSON');
  290. $geo_process = '';
  291. }
  292. }
  293. if ($geo_process == "PROCESS") {
  294. geofield_compute_values($values, $master_column);
  295. // Set form values from the $values array
  296. if (isset($values['wkt'])) form_set_value($element['wkt'], $values['wkt'], $form_state);
  297. if (isset($values['geo_type'])) form_set_value($element['geo_type'], $values['geo_type'], $form_state);
  298. if (isset($values['lat'])) form_set_value($element['lat'], $values['lat'], $form_state);
  299. if (isset($values['lon'])) form_set_value($element['lon'], $values['lon'], $form_state);
  300. if (isset($values['top'])) form_set_value($element['top'], $values['top'], $form_state);
  301. if (isset($values['bottom'])) form_set_value($element['bottom'], $values['bottom'], $form_state);
  302. if (isset($values['right'])) form_set_value($element['right'], $values['right'], $form_state);
  303. if (isset($values['left'])) form_set_value($element['left'], $values['left'], $form_state);
  304. }
  305. }