leaflet.formatters.inc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  1. <?php
  2. /**
  3. * @file
  4. * Leaflet field formatter functions.
  5. */
  6. /**
  7. * Implements hook_field_formatter_info().
  8. */
  9. function leaflet_field_formatter_info() {
  10. $formatters = array();
  11. if (module_exists('geofield')) {
  12. $formatters['geofield_leaflet'] = array(
  13. 'label' => t('Leaflet'),
  14. 'field types' => array('geofield'),
  15. 'settings' => array(
  16. 'leaflet_map' => '',
  17. 'height' => 400,
  18. 'popup' => array(
  19. 'show' => '',
  20. 'text' => '',
  21. ),
  22. 'zoom' => array(
  23. 'initialZoom' => '',
  24. 'minZoom' => 1,
  25. 'maxZoom' => 19
  26. ),
  27. 'icon' => array(
  28. 'iconUrl' => '',
  29. 'shadowUrl' => '',
  30. 'iconSize' => array(
  31. 'x' => '',
  32. 'y' => '',
  33. ),
  34. 'iconAnchor' => array(
  35. 'x' => '',
  36. 'y' => '',
  37. ),
  38. 'shadowAnchor' => array(
  39. 'x' => '',
  40. 'y' => '',
  41. ),
  42. 'popupAnchor' => array(
  43. 'x' => '',
  44. 'y' => '',
  45. ),
  46. 'html' => '',
  47. 'htmlClass' => '',
  48. ),
  49. 'vector_display' => array(
  50. 'stroke_override' => 0,
  51. 'stroke' => 1,
  52. 'color' => '',
  53. 'weight' => '',
  54. 'opacity' => '',
  55. 'dashArray' => '',
  56. 'fill' => 1,
  57. 'fillColor' => '',
  58. 'fillOpacity' => '',
  59. 'clickable' => 1,
  60. ),
  61. ),
  62. );
  63. }
  64. return $formatters;
  65. }
  66. /**
  67. * Implements hook_field_formatter_settings_form().
  68. */
  69. function leaflet_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
  70. $display = $instance['display'][$view_mode];
  71. $settings = $display['settings'];
  72. $entity_type = $instance['entity_type'];
  73. $element = array();
  74. if ($display['type'] == 'geofield_leaflet') {
  75. $options = array('' => t('-- Select --'));
  76. foreach (leaflet_map_get_info() as $key => $map) {
  77. $options[$key] = $map['label'];
  78. }
  79. $element['leaflet_map'] = array(
  80. '#title' => t('Leaflet Map'),
  81. '#type' => 'select',
  82. '#options' => $options,
  83. '#default_value' => $settings['leaflet_map'],
  84. '#required' => TRUE,
  85. );
  86. $element['height'] = array(
  87. '#title' => t('Map Height'),
  88. '#type' => 'textfield',
  89. '#default_value' => $settings['height'],
  90. '#field_suffix' => t('px'),
  91. '#element_validate' => array('element_validate_integer_positive'),
  92. );
  93. foreach ($form['#fields'] as $fieldname) {
  94. $field_options[$fieldname] = $fieldname;
  95. }
  96. $fieldpath = 'fields[' . $field['field_name'] . '][settings_edit_form][settings]';
  97. $element['popup'] = leaflet_form_elements('popup', $settings, array('path' => $fieldpath));
  98. $element['zoom'] = leaflet_form_elements('zoom', $settings);
  99. $element['icon'] = leaflet_form_elements('icon', $settings, array('path' => $fieldpath, 'fields' => $field_options));
  100. $element['vector_display'] = leaflet_form_elements('vector_display', $settings, array('path' => $fieldpath));
  101. // Show the list of available tokens.
  102. $element['tokens'] = leaflet_form_elements('tokens', $settings, array('weight' => 999, 'entity_type' => $entity_type));
  103. }
  104. return $element;
  105. }
  106. /**
  107. * Validation callback for icon urls.
  108. */
  109. function leaflet_icon_validate($element, &$form_state, $form) {
  110. if (!empty($element['#value']) && !valid_url($element['#value'])) {
  111. form_error($element, t('Icon URL is invalid'));
  112. }
  113. }
  114. /**
  115. * Implements hook_field_formatter_settings_summary().
  116. */
  117. function leaflet_field_formatter_settings_summary($field, $instance, $view_mode) {
  118. $display = $instance['display'][$view_mode];
  119. $settings = $display['settings'];
  120. $summary = '';
  121. if ($display['type'] == 'geofield_leaflet') {
  122. $summary = t('Leaflet map: @map', array('@map' => $settings['leaflet_map']));
  123. }
  124. return $summary;
  125. }
  126. /**
  127. * Implements hook_field_formatter_view().
  128. */
  129. function leaflet_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  130. $element = array();
  131. $settings = $display['settings'];
  132. if (count($items) == 0) {
  133. return '';
  134. }
  135. else {
  136. switch ($display['type']) {
  137. case 'geofield_leaflet':
  138. $map = leaflet_map_get_info($settings['leaflet_map']);
  139. $features = leaflet_process_geofield($items);
  140. foreach ($features as &$feat) {
  141. $feat['entity'] = $entity;
  142. }
  143. leaflet_apply_map_settings($map, $features, $settings, $entity_type);
  144. $element[0] = leaflet_build_map($map, $features, $settings['height'] . 'px');
  145. break;
  146. }
  147. return $element;
  148. }
  149. }
  150. /**
  151. * Convert a geofield into an array of map points.
  152. *
  153. * @param array $items
  154. * A collection of geofield values.
  155. *
  156. * @return array
  157. * Points built for consumption by the leaflet module as expected by
  158. * leaflet_render_map().
  159. */
  160. function leaflet_process_geofield($items = array()) {
  161. $data = array();
  162. geophp_load();
  163. foreach ($items as $delta => $item) {
  164. // Translate linestring to polyline:
  165. if ($item['geo_type'] == 'multilinestring') {
  166. $item['geo_type'] = 'multipolyline';
  167. }
  168. // Geofield 7.x-2.x compatibility.
  169. if (!isset($item['wkt']) && isset($item['geom'])) {
  170. $item['wkt'] = $item['geom'];
  171. }
  172. $datum = array('type' => $item['geo_type']);
  173. switch ($item['geo_type']) {
  174. case 'point':
  175. $datum += array(
  176. 'lat' => (float) $item['lat'],
  177. 'lon' => (float) $item['lon'],
  178. );
  179. $data[] = $datum;
  180. break;
  181. case 'linestring':
  182. $geom = geoPHP::load($item['wkt'], 'wkt');
  183. $components = $geom->getComponents();
  184. foreach ($components as $component) {
  185. $datum['points'][] = array(
  186. 'lat' => $component->getY(),
  187. 'lon' => $component->getX(),
  188. );
  189. }
  190. $data[] = $datum;
  191. break;
  192. case 'polygon':
  193. $geom = geoPHP::load($item['wkt'], 'wkt');
  194. $tmp = $geom->getComponents();
  195. $components = $tmp[0]->getComponents();
  196. foreach ($components as $component) {
  197. $datum['points'][] = array(
  198. 'lat' => $component->getY(),
  199. 'lon' => $component->getX(),
  200. );
  201. }
  202. $data[] = $datum;
  203. break;
  204. case 'multipoint':
  205. $geom = geoPHP::load($item['wkt'], 'wkt');
  206. $points = $geom->getComponents();
  207. foreach ($points as $point) {
  208. $data[] = array(
  209. 'type' => 'point',
  210. 'lat' => $point->getY(),
  211. 'lon' => $point->getX(),
  212. );
  213. }
  214. break;
  215. case 'multipolygon':
  216. $geom = geoPHP::load($item['wkt'], 'wkt');
  217. $tmp = $geom->getComponents();
  218. $components = array();
  219. foreach ($tmp as $polygon) {
  220. $polygon_component = $polygon->getComponents();
  221. foreach ($polygon_component as $linestring) {
  222. $components[] = $linestring;
  223. }
  224. }
  225. foreach ($components as $key => $component) {
  226. $subcomponents = $component->getComponents();
  227. foreach ($subcomponents as $subcomponent) {
  228. $datum['component'][$key]['points'][] = array(
  229. 'lat' => $subcomponent->getY(),
  230. 'lon' => $subcomponent->getX(),
  231. );
  232. }
  233. unset($subcomponent);
  234. }
  235. $data[] = $datum;
  236. break;
  237. case 'multipolyline':
  238. $geom = geoPHP::load($item['wkt'], 'wkt');
  239. $components = $geom->getComponents();
  240. foreach ($components as $key => $component) {
  241. $subcomponents = $component->getComponents();
  242. foreach ($subcomponents as $subcomponent) {
  243. $datum['component'][$key]['points'][] = array(
  244. 'lat' => $subcomponent->getY(),
  245. 'lon' => $subcomponent->getX(),
  246. );
  247. }
  248. unset($subcomponent);
  249. }
  250. $data[] = $datum;
  251. break;
  252. case 'geometrycollection':
  253. $geom = geoPHP::load($item['wkt'], 'wkt');
  254. foreach ($geom as $geom_items) {
  255. foreach ($geom_items as $geom_item) {
  256. $class = get_class($geom_item);
  257. switch ($class) {
  258. case 'Point':
  259. $datum = array();
  260. $datum['type'] = 'point';
  261. $datum += array(
  262. 'lat' => (float) $geom_item->coords[1],
  263. 'lon' => (float) $geom_item->coords[0],
  264. );
  265. $data[] = $datum;
  266. break;
  267. case 'LineString':
  268. $points = $geom_item->getComponents();
  269. $datum = array();
  270. $datum['type'] = 'linestring';
  271. foreach ($points as $component) {
  272. $datum['points'][] = array(
  273. 'lat' => $component->getY(),
  274. 'lon' => $component->getX(),
  275. );
  276. }
  277. $data[] = $datum;
  278. break;
  279. case 'Polygon':
  280. $points = $geom_item->getComponents();
  281. $components = $points[0]->getComponents();
  282. $datum = array();
  283. $datum['type'] = 'polygon';
  284. foreach ($components as $component) {
  285. $datum['points'][] = array(
  286. 'lat' => $component->getY(),
  287. 'lon' => $component->getX(),
  288. );
  289. }
  290. $data[] = $datum;
  291. break;
  292. }
  293. }
  294. }
  295. break;
  296. }
  297. }
  298. return $data;
  299. }
  300. /**
  301. * Universal method for applying map settings from leaflet_form_elements items.
  302. *
  303. * @array $map
  304. * Leaflet map definition.
  305. * @array $features
  306. * Associative array of map features.
  307. * @array $map_settings
  308. * Map settings returned by a settings form.
  309. * @string $entity_type
  310. * Entity type this map is being displayed for.
  311. *
  312. */
  313. function leaflet_apply_map_settings(&$map, &$features, $map_settings, $entity_type) {
  314. // These are the settings key that will be tokenized by entity:
  315. $token_by_entity = array(
  316. 'popup',
  317. 'icon',
  318. 'vector_display',
  319. );
  320. // Apply zoom settings (will override hook_leaflet_map_info() values):
  321. if (isset($map_settings['zoom']['initialZoom']) && $map_settings['zoom']['initialZoom'] >= 0) {
  322. $map['settings']['zoom'] = intval($map_settings['zoom']['initialZoom']);
  323. }
  324. if (isset($map_settings['zoom']['minZoom']) && $map_settings['zoom']['minZoom'] >= 0) {
  325. $map['settings']['minZoom'] = intval($map_settings['zoom']['minZoom']);
  326. }
  327. if (isset($map_settings['zoom']['maxZoom']) && $map_settings['zoom']['maxZoom'] >= 0) {
  328. $map['settings']['maxZoom'] = intval($map_settings['zoom']['maxZoom']);
  329. }
  330. if (isset($map_settings['zoom']['scrollWheelZoom'])) {
  331. $map['settings']['scrollWheelZoom'] = $map_settings['zoom']['scrollWheelZoom'];
  332. }
  333. $icon = 'none';
  334. if (isset($map_settings['icon']['iconType'])) {
  335. $icon = $map_settings['icon']['iconType'];
  336. $classes = NULL;
  337. if ($icon == 'html' && isset($map_settings['icon']['htmlClass'])) {
  338. // Clean the user-entered classes.
  339. $classes = explode(' ', $map_settings['icon']['htmlClass']);
  340. array_walk($classes, 'drupal_html_class');
  341. $map_settings['icon']['htmlClass'] = implode(' ', $classes);
  342. }
  343. elseif (!$map_settings['icon']['iconUrl']) {
  344. $icon = 'none';
  345. }
  346. }
  347. $vector_settings = FALSE;
  348. if (!empty($map_settings['vector_display']) && $map_settings['vector_display']['stroke_override']) {
  349. $vector_settings = TRUE;
  350. }
  351. foreach ($features as &$feat) {
  352. // Apply tokens where relevant:
  353. $settings = $map_settings;
  354. $entity = !empty($feat['entity']) ? $feat['entity'] : NULL;
  355. $token_args = array('data' => array($entity_type => $entity), 'options' => array('clear' => TRUE));
  356. foreach ($token_by_entity as $key) {
  357. if (isset($settings[$key]) && is_array($settings[$key])) {
  358. array_walk_recursive($settings[$key], 'leaflet_token_replace', $token_args);
  359. }
  360. }
  361. if (isset($settings['popup']['show']) && $settings['popup']['show']) {
  362. $feat['popup'] = trim($settings['popup']['text']);
  363. }
  364. // Apply Icon settings:
  365. if ($icon == 'html') {
  366. // Maps handled by Views will have rendered HTML already.
  367. if (isset($feat['rendered_html'])) {
  368. $feat['html'] = $feat['rendered_html'];
  369. }
  370. else {
  371. $icon_config = array(
  372. 'label' => 'hidden',
  373. 'settings' => array(
  374. 'image_style' => isset($settings['icon']['iconImageStyle']) ? $settings['icon']['iconImageStyle'] : '',
  375. ),
  376. );
  377. $icon_field = field_view_field($entity_type, $feat['entity'], $settings['icon']['html'], $icon_config);
  378. $feat['html'] = render($icon_field);
  379. }
  380. if (!empty($settings['icon']['iconSize']['x']) || !empty($settings['icon']['iconSize']['y'])) {
  381. // We hand the size off to the API, but the rendered HTML will dictate
  382. // its own size, so we override that as well.
  383. // @todo: actually allow the API settings to control this.
  384. $feat['icon']['iconSize'] = $settings['icon']['iconSize'];
  385. if (!empty($icon_field)) {
  386. foreach (element_children($icon_field) as $i) {
  387. if (!empty($settings['icon']['iconSize']['x'])) {
  388. $icon_field[$i]['#item']['width'] = $settings['icon']['iconSize']['x'];
  389. unset($icon_field[$i]['#item']['width']);
  390. }
  391. if (!empty($settings['icon']['iconSize']['y'])) {
  392. $icon_field[$i]['#item']['height'] = $settings['icon']['iconSize']['y'];
  393. unset($icon_field[$i]['#item']['width']);
  394. }
  395. }
  396. }
  397. }
  398. $feat['html_class'] = $settings['icon']['htmlClass'];
  399. $feat['icon']['iconAnchor'] = $settings['icon']['iconAnchor'];
  400. }
  401. if ($icon == 'marker') {
  402. $feat['icon'] = $settings['icon'];
  403. unset($feat['icon']['html']);
  404. unset($feat['icon']['html_class']);
  405. }
  406. // Apply vector display settings:
  407. if ($vector_settings) {
  408. if ($feat['type'] != 'point') {
  409. // To avoid overwrite the options with empty values removes all
  410. // NULL, FALSE and empty Strings and leaves zero values.
  411. $options = array_filter($settings['vector_display'], 'strlen');
  412. unset($options['stroke_override']);
  413. $feat['options'] = $options;
  414. }
  415. }
  416. // Unset the entity here so it does not get returned to the client in JS.
  417. unset($feat['entity']);
  418. }
  419. }
  420. /**
  421. * Replaces all tokens in a given string with appropriate values.
  422. *
  423. * This is a wrapper arround token_replace, to apply token_replace only
  424. * to strings.
  425. */
  426. function leaflet_token_replace(&$subject, $key, $data = array()) {
  427. if (is_string($subject) && $subject) {
  428. $subject = token_replace($subject, $data['data'], $data['options']);
  429. }
  430. }
  431. /**
  432. * Helper function to standardize forms between views and field formatters.
  433. *
  434. * $group - String
  435. * The name of the group element to generate.
  436. *
  437. * $settings - Array
  438. * Current form settings (for defaults, etc)
  439. *
  440. * $options - Array
  441. * Special options needed for this form element, if necessary.
  442. *
  443. * Return - A fully loaded form element.
  444. */
  445. function leaflet_form_elements($group, $settings, $options = NULL) {
  446. $form_element = NULL;
  447. switch ($group) {
  448. case 'popup':
  449. $form_element = array(
  450. '#title' => t('Popup Settings'),
  451. '#type' => 'fieldset',
  452. '#tree' => TRUE,
  453. '#collapsible' => TRUE,
  454. '#collapsed' => TRUE,
  455. );
  456. $form_element['show'] = array(
  457. '#title' => t('Popup'),
  458. '#description' => t('Show a popup when locations are clicked.'),
  459. '#type' => 'checkbox',
  460. '#default_value' => $settings[$group]['show'],
  461. );
  462. $form_element['text'] = array(
  463. '#title' => t('Popup text'),
  464. '#description' => t('Enter the text for the popup. Tokens are supported.'),
  465. '#type' => 'textfield',
  466. '#default_value' => $settings[$group]['text'],
  467. '#states' => array(
  468. 'visible' => array(
  469. ':input[name="' . $options['path'] . '[popup][show]"]' => array('checked' => TRUE),
  470. ),
  471. ),
  472. );
  473. break;
  474. case 'zoom':
  475. // Define zoom options.
  476. $zoom_options = array(
  477. -1 => t('Use map defined setting'),
  478. 0 => t('0 - Low/Far'),
  479. 18 => t('18 - High/Close'),
  480. );
  481. for ($i = 1; $i < 18; $i++) {
  482. $zoom_options[$i] = $i;
  483. }
  484. ksort($zoom_options);
  485. $form_element = array(
  486. '#title' => t('Zoom Settings'),
  487. '#description' => t("These settings will override the zoom settings defined in the map definition. Low values are 'zoomed out', high values are 'zoomed in'."),
  488. '#type' => 'fieldset',
  489. '#tree' => TRUE,
  490. '#collapsible' => TRUE,
  491. '#collapsed' => TRUE,
  492. );
  493. $form_element['initialZoom'] = array(
  494. '#title' => t('Initial zoom level'),
  495. '#description' => t('The starting zoom level when this map is rendered. Restricted by min and max zoom settings.'),
  496. '#type' => 'select',
  497. '#options' => $zoom_options,
  498. '#default_value' => isset($settings[$group]['initialZoom']) ? $settings[$group]['initialZoom'] : -1,
  499. '#element_validate' => array('leaflet_initial_zoom_validate'),
  500. );
  501. $form_element['minZoom'] = array(
  502. '#title' => t('Minimum zoom level'),
  503. '#description' => t('The minimum zoom level allowed. (How far away can you view from?)'),
  504. '#type' => 'select',
  505. '#options' => $zoom_options,
  506. '#default_value' => isset($settings[$group]['minZoom']) ? $settings[$group]['minZoom'] : -1,
  507. '#element_validate' => array('leaflet_min_zoom_validate'),
  508. );
  509. $form_element['maxZoom'] = array(
  510. '#title' => t('Maximum zoom level'),
  511. '#description' => t('The maximum zoom level allowed. (How close in can you get?).'),
  512. '#type' => 'select',
  513. '#options' => $zoom_options,
  514. '#default_value' => isset($settings[$group]['maxZoom']) ? $settings[$group]['maxZoom'] : -1,
  515. '#element_validate' => array('leaflet_max_zoom_validate'),
  516. );
  517. $form_element['scrollWheelZoom'] = array(
  518. '#title' => t('Scroll wheel zoom'),
  519. '#description' => t('Allow map to be zoomed with the mouse wheel.'),
  520. '#type' => 'checkbox',
  521. '#default_value' => isset($settings[$group]['scrollWheelZoom']) ? $settings[$group]['scrollWheelZoom'] : 1,
  522. );
  523. break;
  524. case 'icon':
  525. $form_element = array(
  526. '#title' => t('Point Icon'),
  527. '#description' => t('These settings will overwrite the icon settings defined in the map definition.'),
  528. '#type' => 'fieldset',
  529. '#collapsible' => TRUE,
  530. '#collapsed' => TRUE,
  531. );
  532. $form_element['iconType'] = array(
  533. '#type' => 'radios',
  534. '#title' => t('Icon Source'),
  535. '#default_value' => isset($settings[$group]['iconType']) ? $settings[$group]['iconType'] : 'marker',
  536. '#options' => array(
  537. 'marker' => "Icon File",
  538. 'html' => "Field (html DivIcon)",
  539. ),
  540. );
  541. $form_element['iconUrl'] = array(
  542. '#title' => t('Icon URL'),
  543. '#description' => t('Can be an absolute or relative URL.'),
  544. '#type' => 'textfield',
  545. '#maxlength' => 999,
  546. '#default_value' => isset($settings[$group]['iconUrl']) ? $settings[$group]['iconUrl'] : '',
  547. '#element_validate' => array('leaflet_icon_validate'),
  548. '#states' => array(
  549. 'visible' => array(
  550. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'marker'),
  551. ),
  552. ),
  553. );
  554. $form_element['shadowUrl'] = array(
  555. '#title' => t('Icon Shadow URL'),
  556. '#description' => t('Can be an absolute or relative URL.'),
  557. '#type' => 'textfield',
  558. '#maxlength' => 999,
  559. '#default_value' => isset($settings[$group]['shadowUrl']) ? $settings[$group]['shadowUrl'] : '',
  560. '#element_validate' => array('leaflet_icon_validate'),
  561. '#states' => array(
  562. 'visible' => array(
  563. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'marker'),
  564. ),
  565. ),
  566. );
  567. $form_element['html'] = array(
  568. '#type' => 'select',
  569. '#title' => t('Marker field'),
  570. '#description' => t('Field to use as output for a map marker.'),
  571. // See [#1796656]
  572. '#options' => (array)array_merge(array('' => ''), $options['fields']),
  573. '#default_value' => isset($settings[$group]['html']) ? $settings[$group]['html'] : '',
  574. '#empty_option' => t('-- Select --'),
  575. '#states' => array(
  576. 'visible' => array(
  577. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'html'),
  578. ),
  579. 'required' => array(
  580. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'html'),
  581. ),
  582. ),
  583. );
  584. $form_element['iconImageStyle'] = array(
  585. '#title' => t('Icon image style'),
  586. '#type' => 'select',
  587. '#default_value' => isset($settings[$group]['iconImageStyle']) ? $settings[$group]['iconImageStyle'] : '',
  588. '#empty_option' => t('None (original image)'),
  589. '#options' => image_style_options(FALSE, PASS_THROUGH),
  590. '#states' => array(
  591. 'visible' => array(
  592. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'html'),
  593. ),
  594. ),
  595. );
  596. $form_element['htmlClass'] = array(
  597. '#type' => 'textfield',
  598. '#title' => t('Marker HTML class'),
  599. '#description' => t('Required class name for the div used to wrap field output. For multiple classes, separate with a space.'),
  600. '#default_value' => isset($settings[$group]['htmlClass']) ? $settings[$group]['htmlClass'] : 'leaflet_map_icon',
  601. '#states' => array(
  602. 'visible' => array(
  603. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'html'),
  604. ),
  605. 'required' => array(
  606. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'html'),
  607. ),
  608. ),
  609. );
  610. $form_element['iconSize'] = array(
  611. '#title' => t('Icon Size'),
  612. '#description' => "It is usually preferable to leave this blank and use the image style system to size the icons. Sizes are in pixels.",
  613. '#type' => 'fieldset',
  614. '#collapsible' => TRUE,
  615. );
  616. $form_element['iconSize']['x'] = array(
  617. '#title' => t('Width'),
  618. '#type' => 'textfield',
  619. '#maxlength' => 3,
  620. '#size' => 3,
  621. '#default_value' => isset($settings[$group]['iconSize']['x']) ? $settings[$group]['iconSize']['x'] : '',
  622. '#element_validate' => array('element_validate_integer_positive'),
  623. );
  624. $form_element['iconSize']['y'] = array(
  625. '#title' => t('Height'),
  626. '#type' => 'textfield',
  627. '#maxlength' => 3,
  628. '#size' => 3,
  629. '#default_value' => isset($settings[$group]['iconSize']['y']) ? $settings[$group]['iconSize']['y'] : '',
  630. '#element_validate' => array('element_validate_integer_positive'),
  631. );
  632. $form_element['iconAnchor'] = array(
  633. '#title' => t('Icon Anchor'),
  634. '#type' => 'fieldset',
  635. '#collapsible' => TRUE,
  636. '#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."),
  637. );
  638. $form_element['iconAnchor']['x'] = array(
  639. '#title' => t('X'),
  640. '#type' => 'textfield',
  641. '#maxlength' => 3,
  642. '#size' => 3,
  643. '#default_value' => isset($settings[$group]['iconAnchor']['x']) ? $settings[$group]['iconAnchor']['x'] : '',
  644. '#element_validate' => array('element_validate_number'),
  645. );
  646. $form_element['iconAnchor']['y'] = array(
  647. '#title' => t('Y'),
  648. '#type' => 'textfield',
  649. '#maxlength' => 3,
  650. '#size' => 3,
  651. '#default_value' => isset($settings[$group]['iconAnchor']['y']) ? $settings[$group]['iconAnchor']['y'] : '',
  652. '#element_validate' => array('element_validate_number'),
  653. );
  654. $form_element['shadowAnchor'] = array(
  655. '#title' => t('Shadow Anchor'),
  656. '#type' => 'fieldset',
  657. '#collapsible' => TRUE,
  658. '#description' => t('The point from which the shadow is shown.'),
  659. '#states' => array(
  660. 'visible' => array(
  661. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'marker'),
  662. ),
  663. ),
  664. );
  665. $form_element['shadowAnchor']['x'] = array(
  666. '#title' => t('X'),
  667. '#type' => 'textfield',
  668. '#maxlength' => 3,
  669. '#size' => 3,
  670. '#default_value' => isset($settings[$group]['shadowAnchor']['x']) ? $settings[$group]['shadowAnchor']['x'] : '',
  671. '#element_validate' => array('element_validate_number'),
  672. );
  673. $form_element['shadowAnchor']['y'] = array(
  674. '#title' => t('Y'),
  675. '#type' => 'textfield',
  676. '#maxlength' => 3,
  677. '#size' => 3,
  678. '#default_value' => isset($settings[$group]['shadowAnchor']['y']) ? $settings[$group]['shadowAnchor']['y'] : '',
  679. '#element_validate' => array('element_validate_number'),
  680. );
  681. $form_element['popupAnchor'] = array(
  682. '#title' => t('Popup Anchor'),
  683. '#type' => 'fieldset',
  684. '#collapsible' => TRUE,
  685. '#description' => t('The point from which the marker popup opens, relative to the anchor point.'),
  686. '#states' => array(
  687. 'visible' => array(
  688. ':input[name="' . $options['path'] . '[icon][iconType]"]' => array('value' => 'marker'),
  689. ),
  690. ),
  691. );
  692. $form_element['popupAnchor']['x'] = array(
  693. '#title' => t('X'),
  694. '#type' => 'textfield',
  695. '#maxlength' => 3,
  696. '#size' => 3,
  697. '#default_value' => isset($settings[$group]['popupAnchor']['x']) ? $settings[$group]['popupAnchor']['x'] : '',
  698. '#element_validate' => array('element_validate_number'),
  699. );
  700. $form_element['popupAnchor']['y'] = array(
  701. '#title' => t('Y'),
  702. '#type' => 'textfield',
  703. '#maxlength' => 3,
  704. '#size' => 3,
  705. '#default_value' => isset($settings[$group]['popupAnchor']['y']) ? $settings[$group]['popupAnchor']['y'] : '',
  706. '#element_validate' => array('element_validate_number'),
  707. );
  708. break;
  709. case "vector_display":
  710. $form_element = array(
  711. '#title' => t('Vector Display Options'),
  712. '#description' => t('These settings will overwrite the !options and constants shared between vector overlays (Polygon, Polyline, Circle).', array('!options' => l(t("default options"), 'http://leafletjs.com/reference.html#path'))),
  713. '#type' => 'fieldset',
  714. '#collapsible' => TRUE,
  715. '#collapsed' => TRUE,
  716. );
  717. $form_element['stroke_override'] = array(
  718. '#title' => t('Override Defaults'),
  719. '#description' => t('If checked, the default values will be overridden by these settings.'),
  720. '#type' => 'checkbox',
  721. '#default_value' => isset($settings[$group]['stroke_override']) ? $settings[$group]['stroke_override'] : 1,
  722. );
  723. $form_element['stroke'] = array(
  724. '#title' => t('Stroke'),
  725. '#description' => t('Draw an outline around the shape. Uncheck to disable borders on polygons and circles. (Default: True)'),
  726. '#type' => 'checkbox',
  727. '#default_value' => isset($settings[$group]['stroke']) ? $settings[$group]['stroke'] : 1,
  728. '#states' => array(
  729. 'enabled' => array(
  730. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  731. ),
  732. ),
  733. );
  734. $form_element['color'] = array(
  735. '#title' => t('Line Color'),
  736. '#description' => t('Line color. (Default: #00030f)'),
  737. '#type' => 'textfield',
  738. '#default_value' => isset($settings[$group]['color']) ? $settings[$group]['color'] : '',
  739. '#states' => array(
  740. 'visible' => array(
  741. ':input[name="' . $options['path'] . '[' . $group . '][stroke]"]' => array('checked' => TRUE),
  742. ),
  743. 'enabled' => array(
  744. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  745. ),
  746. ),
  747. );
  748. $form_element['weight'] = array(
  749. '#title' => t('Line Weight'),
  750. '#description' => t('Line width in pixels. (Default: 5)'),
  751. '#type' => 'textfield',
  752. '#default_value' => isset($settings[$group]['weight']) ? $settings[$group]['weight'] : '',
  753. '#states' => array(
  754. 'visible' => array(
  755. ':input[name="' . $options['path'] . '[' . $group . '][stroke]"]' => array('checked' => TRUE),
  756. ),
  757. 'enabled' => array(
  758. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  759. ),
  760. ),
  761. );
  762. $form_element['opacity'] = array(
  763. '#title' => t('Line Opacity'),
  764. '#description' => t('Line opacity. A number between 0 (would make the line invisible) to 1 (no transparency at all). (Default: 0.5)'),
  765. '#type' => 'textfield',
  766. '#default_value' => isset($settings[$group]['opacity']) ? $settings[$group]['opacity'] : '',
  767. '#states' => array(
  768. 'visible' => array(
  769. ':input[name="' . $options['path'] . '[' . $group . '][stroke]"]' => array('checked' => TRUE),
  770. ),
  771. 'enabled' => array(
  772. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  773. ),
  774. ),
  775. );
  776. $form_element['dashArray'] = array(
  777. '#title' => t('Line Dash Pattern'),
  778. '#description' => t("A string that defines the line's !url. Depending on your line weight, this can be hard to see. Note that this is ignored by canvas-powered layers (e.g. Android 2). Sample: 5, 5", array('!url' => l(t('dash pattern'), 'https://developer.mozilla.org/en/SVG/Attribute/stroke-dasharray'))),
  779. '#type' => 'textfield',
  780. '#default_value' => isset($settings[$group]['dashArray']) ? $settings[$group]['dashArray'] : '',
  781. '#states' => array(
  782. 'visible' => array(
  783. ':input[name="' . $options['path'] . '[' . $group . '][stroke]"]' => array('checked' => TRUE),
  784. ),
  785. 'enabled' => array(
  786. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  787. ),
  788. ),
  789. );
  790. $form_element['fill'] = array(
  791. '#title' => t('Fill'),
  792. '#description' => t('Fill the shape with color. Default: "!depends"', array('!depends' => l(t("depends"), 'http://leafletjs.com/reference.html#path-fill'))),
  793. '#type' => 'checkbox',
  794. '#default_value' => isset($settings[$group]['fill']) ? $settings[$group]['fill'] : 1,
  795. '#states' => array(
  796. 'enabled' => array(
  797. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  798. ),
  799. ),
  800. );
  801. $form_element['fillColor'] = array(
  802. '#title' => t('Fill Color'),
  803. '#description' => t('Fill color. Default: #00030f'),
  804. '#type' => 'textfield',
  805. '#default_value' => isset($settings[$group]['fillColor']) ? $settings[$group]['fillColor'] : '',
  806. '#states' => array(
  807. 'visible' => array(
  808. ':input[name="' . $options['path'] . '[' . $group . '][fill]"]' => array('checked' => TRUE),
  809. ),
  810. 'enabled' => array(
  811. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  812. ),
  813. ),
  814. );
  815. $form_element['fillOpacity'] = array(
  816. '#title' => t('Fill Opacity'),
  817. '#description' => t('Fill opacity. A number between 0 (would make the fill invisible) to 1 (no transparency at all). Default: 0.2'),
  818. '#type' => 'textfield',
  819. '#default_value' => isset($settings[$group]['fillOpacity']) ? $settings[$group]['fillOpacity'] : '',
  820. '#states' => array(
  821. 'visible' => array(
  822. ':input[name="' . $options['path'] . '[' . $group . '][fill]"]' => array('checked' => TRUE),
  823. ),
  824. 'enabled' => array(
  825. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  826. ),
  827. ),
  828. );
  829. $form_element['clickable'] = array(
  830. '#title' => t('Clickable'),
  831. '#description' => t('If disabled, the vector will not emit mouse events, essentially acting as a part of the underlying map. Default: True'),
  832. '#type' => 'checkbox',
  833. '#default_value' => isset($settings[$group]['clickable']) ? $settings[$group]['clickable'] : 1,
  834. '#states' => array(
  835. 'enabled' => array(
  836. ':input[name="' . $options['path'] . '[' . $group . '][stroke_override]"]' => array('checked' => TRUE),
  837. ),
  838. ),
  839. );
  840. break;
  841. case "tokens":
  842. // See [#2176681]
  843. $form_element = array(
  844. '#type' => 'container',
  845. '#theme' => 'token_tree_link',
  846. '#token_types' => array($options['entity_type']),
  847. );
  848. break;
  849. }
  850. return $form_element;
  851. }
  852. /**
  853. * Validation callback for the initial zoom level.
  854. */
  855. function leaflet_initial_zoom_validate($element, &$form_state, $form) {
  856. $input_root = _leaflet_get_form_input_path($form_state['input'], $element['#parents']);
  857. $min_zoom = (int) $input_root['minZoom'];
  858. $max_zoom = (int) $input_root['maxZoom'];
  859. $initial_zoom = (int) $input_root['initialZoom'];
  860. if (isset($initial_zoom) && $initial_zoom != -1) {
  861. if (isset($min_zoom)) {
  862. if ($min_zoom > $initial_zoom) {
  863. form_error($element, t('The initial zoom level should be greater than the minimum zoom settings'));
  864. }
  865. }
  866. if (isset($max_zoom) && $max_zoom != -1) {
  867. if ($max_zoom < $initial_zoom) {
  868. form_error($element, t('The initial zoom level should be less than the maximum zoom settings'));
  869. }
  870. }
  871. }
  872. }
  873. /**
  874. * Validation callback for min zoom level.
  875. */
  876. function leaflet_min_zoom_validate($element, &$form_state, $form) {
  877. $input_root = _leaflet_get_form_input_path($form_state['input'], $element['#parents']);
  878. $min_zoom = (int) $input_root['minZoom'];
  879. $max_zoom = (int) $input_root['maxZoom'];
  880. if (isset($max_zoom) && $max_zoom != "-1" && isset($min_zoom)) {
  881. if ($min_zoom > $max_zoom) {
  882. form_error($element, t('The minimum zoom setting must be less than or equal to the maximum zoom setting'));
  883. }
  884. }
  885. }
  886. /**
  887. * Validation callback for max zoom level.
  888. */
  889. function leaflet_max_zoom_validate($element, &$form_state, $form) {
  890. $input_root = _leaflet_get_form_input_path($form_state['input'], $element['#parents']);
  891. $min_zoom = (int) $input_root['minZoom'];
  892. $max_zoom = (int) $input_root['maxZoom'];
  893. if (isset($max_zoom) && $max_zoom != "-1" && isset($min_zoom)) {
  894. if ($min_zoom > $max_zoom) {
  895. form_error($element, t('The maximum zoom setting must be greater than or equal to the minimum zoom setting'));
  896. }
  897. }
  898. }
  899. /**
  900. * Helper function to find the correct values for input validation.
  901. */
  902. function _leaflet_get_form_input_path($path, $path_items) {
  903. array_pop($path_items);
  904. while ($item = array_shift($path_items)) {
  905. $path = $path[$item];
  906. }
  907. return $path;
  908. }