'. t('The OpenLayers module is the base module for the OpenLayers suite of modules, and provides the main API.') .'

'; } return ''; } /** * Implementation of hook_theme(). */ function openlayers_theme($existing, $type, $theme, $path) { return array( 'openlayers_map' => array( 'arguments' => array( 'map' => array(), 'preset_name' => '', ), 'file' => 'includes/openlayers.theme.inc', ), 'openlayers_styles' => array( 'arguments' => array( 'styles' => array(), 'map' => array(), ), 'file' => 'includes/openlayers.theme.inc', ), ); } /** * Include necessary CSS and JS for rendering maps * * @ingroup openlayers_api */ function openlayers_include() { // Use a static variable to prevent running URL check code repeatedly. static $once; if (!isset($once)) { $once = TRUE; $path = check_plain(variable_get('openlayers_source', 'http://openlayers.org/api/2.9/OpenLayers.js')); // Correctly handle URLs beginning with a double backslash, see RFC 1808 Section 4 if (substr($path, 0, 2) == '//') { $http_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; $path = $http_protocol .':'. $path; } // Check for full URL and include it manually if external. if (valid_url($path, TRUE)) { drupal_set_html_head(''); } else { drupal_add_js($path); } drupal_add_css(drupal_get_path('module', 'openlayers') . '/openlayers.css', 'module'); drupal_add_js(drupal_get_path('module', 'openlayers') . '/js/openlayers.js', 'module'); } } /** * Prepare a map for rendering. * * Takes a map array and builds up the data given the * reference to objects like styles, layers, and behaviors. * * @ingroup openlayers_api * * @param $map * Array of map settings * @return * Filled in map array. */ function openlayers_build_map($map = array()) { // Get the necessary parts openlayers_include(); module_load_include('inc', 'openlayers', 'includes/openlayers.render'); // If no map is specified, use the default preset. if (empty($map)) { if ($preset = openlayers_preset_load(variable_get('openlayers_default_preset', 'default'))) { $map = $preset->data; } } // Create ID for map as this will help with alters. $map['id'] = !isset($map['id']) ? _openlayers_create_map_id() : $map['id']; // Hook to alter map before main processing. Styles, behaviors, // layers may all be added here. // hook_openlayers_map_preprocess_alter($map) drupal_alter('openlayers_map_preprocess', $map); // styles and layer styles are not required parameters $map['styles'] = isset($map['styles']) ? $map['styles'] : array(); $layer_styles = array(); if ( isset($map['layer_styles']) ) { foreach ($map['layer_styles'] as $layer => $style) { // UPGRADE NOTE: // Presets up to 6.x-2.x-alpha10 always had a single style // per layer specified. Newer ones have them splitted by role if ( is_array($style) ) { $layer_styles[$layer] = $style; } else { $layer_styles[$layer] = array( 'default' => $style, 'select' => $style, 'temporary' => $style ); } } } $map['layer_styles'] = $layer_styles; $map['layers'] = _openlayers_layers_process($map['layers'], $map); $map['behaviors'] = _openlayers_behaviors_render($map['behaviors'], $map); $map['styles'] = _openlayers_styles_process( $map['styles'], $map['layer_styles'], $map); // Hook to alter map one last time. Final modification to existing // styles, behaviors, layers can happen here, but adding new styles, // behaviors will not get rendered. // hook_openlayers_map_alter($map) drupal_alter('openlayers_map', $map); // Check map for errors $map['errors'] = openlayers_error_check_map($map); return $map; } /** * Render map array * * Given a map array, render into HTML to display * a map. * * @ingroup openlayers_api * * @param $map * Associative array of map paramters. * @param $preset_name * Name of the preset used for use in the theme function. * @return * Map HTML. */ function openlayers_render_map($map = array(), $preset_name = '') { // Run map through build process $map = openlayers_build_map($map); // Given hide_empty_map flag, check if the map has any features // defined. If not, assume it is an empty map and shouldn't be displayed. if (isset($map['hide_empty_map']) && $map['hide_empty_map'] == TRUE) { $empty = TRUE; $layers = $map['layers']; foreach ($layers as $layer) { if (isset($layer['features']) && count($layer['features'])) { $empty = FALSE; } } if ($empty) { return ''; } } // Return themed map if no errors found if (empty($map['errors'])) { $js = array('openlayers' => array('maps' => array($map['id'] => $map))); // Try to use more efficient json_encode function, if available if (function_exists('json_encode')) { drupal_add_js('Drupal.settings.openlayers.maps["' . $map['id'] . '"] = ' . json_encode($map) . ';', 'inline', 'header', TRUE); } else { drupal_add_js($js, 'setting'); } // Push map through theme function and return $output = theme('openlayers_map', $map, $preset_name); } return $output; } /** * Get layer object * * @ingroup openlayers_api * @param $reset * Boolean whether to reset cache or not * @return array * array of layer info */ function openlayers_get_layer_object($layer, $map = array()) { // Static cache because this function will possibly be called in big loops static $layer_types; if (!isset($layer_types)) { $layer_types = openlayers_layer_types(); } $layer->title = t($layer->title); $layer->description = t($layer->description); // Attempt to get ctool class // class is renamed klass because of PHP keywords if (isset($layer_types[$layer->data['layer_type']]) && $klass = ctools_plugin_get_class( $layer_types[$layer->data['layer_type']], 'layer_type') ) { $layer_object = new $klass($layer, $map); return $layer_object; } else { watchdog('openlayers', 'Layer !layer_name is unavailable because its layer type or the module that provides its layer type is missing', array('!layer_name' => $layer->title), WATCHDOG_ERROR); return FALSE; } } /** * Menu loader for layers. %openlayers_layer_export * @ingroup openlayers_api * * @param $name * Layer name * @return object * Layer export */ function openlayers_layer_export_load($name, $reset = TRUE) { ctools_include('export'); if ($reset) ctools_export_load_object_reset('openlayers_layers'); $layers = ctools_export_load_object('openlayers_layers', 'all', array($name)); return !empty($layers[$name]) ? $layers[$name] : FALSE; } /** * Get all openlayers layers. * @ingroup openlayers_api * * @param $reset * Boolean whether to reset cache or not * @return array * layer exports */ function openlayers_layers_export_load($reset = TRUE) { ctools_include('export'); if ($reset) ctools_export_load_object_reset('openlayers_layers'); $layers = ctools_export_load_object('openlayers_layers', 'all', array()); return $layers; } /** * Menu loader for layers. (%openlayers_layer) * @ingroup openlayers_api * * @param $name * Layer name * @return array * Layer export */ function openlayers_layer_load($name, $reset = FALSE) { ctools_include('export'); if ($reset) ctools_export_load_object_reset('openlayers_layers'); $layer = ctools_export_load_object('openlayers_layers', 'names', array($name)); if ($layer) { $layer_object = openlayers_get_layer_object($layer[$name]); if (openlayers_layer_sanity_check($layer_object)) { return $layer_object; } } else { watchdog('openlayers', 'Layer %layer not found.', array('%layer' => $name), WATCHDOG_ERROR); return FALSE; } } /** * Get all openlayers layers as objects. * @ingroup openlayers_api * * @param $reset * Boolean whether to reset cache or not * @return array * array of layer info */ function openlayers_layers_load($reset = FALSE) { ctools_include('export'); $layer_objects = array(); if ($reset) ctools_export_load_object_reset('openlayers_layers'); $layers = ctools_export_load_object('openlayers_layers', 'all', array()); foreach ($layers as $layer) { $layer_objects[$layer->name] = openlayers_get_layer_object($layer); } $layer_objects = array_filter($layer_objects, 'openlayers_layer_sanity_check'); return $layer_objects; } /** * Check layer to determine whether it has all the * necessary attributes to be rendered. This is necessary * because of API changes, and is a consolidation from other * layer-error-checking in this module * * @param $layer * Layer object * @param $projection * Projection number (EPSG) to check compatibility with * @param $strict * reject invalid layers * @return boolean * layer validity if strict is set, otherwise always true */ function openlayers_layer_sanity_check($layer, $projection = FALSE, $strict = FALSE) { // Handle layers after they've been rendered for a map $layer = (is_array($layer)) ? (object) $layer : $layer; if (!isset($layer->data['projection']) || !is_array($layer->data['projection'])) { watchdog('openlayers', 'Layer %name does not have a projection set.', array('%name' => $layer->name)); drupal_set_message( t('OpenLayers layers failed the sanity check. See the Drupal log for details', array('@drupallog' => url('admin/reports/dblog'))) ); return !$strict; } if (!isset($layer->data['layer_type'])) { watchdog('openlayers', 'Layer %name does not have its layer_type set.', array('%name' => $layer->name)); drupal_set_message( t('OpenLayers layers failed the sanity check. See the Drupal log for details', array('@drupallog' => url('admin/reports/dblog'))) ); return !$strict; } if ($projection && empty($layer->data['vector']) && (!in_array($projection, $layer->data['projection']))) { watchdog('openlayers', 'The layer %layer_name cannot be reprojected to the map projection: EPSG: %map_proj', array( '%layer_name' => $layer->name, '%map_proj' => $map['projection'], ) ); return !$strict; } return TRUE; } /** * Save layer. * @ingroup openlayers_api * * @param $layer * Layer object * @return * bool for success in saving */ function openlayers_layer_save($layer) { if (!empty($layer->name)) { $exists = db_result(db_query("SELECT name FROM {openlayers_layers} WHERE name = '%s'", $layer->name)); return $exists ? drupal_write_record('openlayers_layers', $layer, 'name') : drupal_write_record('openlayers_layers', $layer); } return FALSE; } /** * Delete a layer object from the database. * * @ingroup openlayers_api * * @param $preset * String identifier of a layer or layer object with name. * @return * The results of DB delete. */ function openlayers_layer_delete($layer) { return openlayers_object_delete($layer, 'layer'); } /** * Get all layer types. * * @ingroup openlayers_api * * @param $reset * Boolean whether to reset cache or not. * @return * Array of layer type info. */ function openlayers_layer_types($reset = FALSE) { ctools_include('plugins'); return ctools_get_plugins('openlayers', 'layer_types'); } /** * Menu loader for layer types. * * @ingroup openlayers_api * * @param $name * String identifier of layer type. * @param $reset * Boolean whether to reset cache or not. * @return * An instantiated layer type object or FALSE if not found. */ function openlayers_layer_type_load($name, $reset = FALSE) { ctools_include('plugins'); if ($layer_type_class = ctools_plugin_load_class( 'openlayers', 'layer_types', $name, 'layer_type')) { $layer_type = new $layer_type_class(); return $layer_type; } return FALSE; } /** * Get all behaviors. * * @ingroup openlayers_api * * @param $reset * Boolean whether to reset cache or not. * @return * Array of behavior info. */ function openlayers_behaviors($reset = FALSE) { ctools_include('plugins'); return ctools_get_plugins('openlayers', 'behaviors'); } /** * Get all style plugins. * * @ingroup openlayers_api * * @param $reset * Boolean whether to reset cache or not. * @return * Array of style handler info. */ function openlayers_style_plugins($reset = FALSE) { ctools_include('plugins'); return ctools_get_plugins('openlayers', 'style_plugin'); } /** * Get all openlayers styles. * * @ingroup openlayers_api * * @param $reset * Boolean whether to reset cache or not. * @return * Array of all available styles. */ function openlayers_styles($reset = FALSE) { ctools_include('export'); if ($reset) { ctools_export_load_object_reset('openlayers_styles'); } $styles = ctools_export_load_object('openlayers_styles', 'all', array()); return $styles; } /** * Load a style object by name. * * This function can also be used as a * menu loader for a style. * * @ingroup openlayers_api * * @param $name * The string identifier of the style. * @param $reset * Boolean whether to reset the cache or not. * @return * A style object or FALSE if not found. */ function openlayers_style_load($name, $reset = FALSE) { $styles = openlayers_styles($reset); return !empty($styles[$name]) ? $styles[$name] : FALSE; } /** * Save style. * * @ingroup openlayers_api * * @param $style * The style object to save. * @return * The results of DB write or FALSE if no name. */ function openlayers_style_save($style) { if (!empty($style->name)) { $exists = db_result(db_query("SELECT name FROM {openlayers_styles} WHERE name = '%s'", $style->name)); return $exists ? drupal_write_record('openlayers_styles', $style, 'name') : drupal_write_record('openlayers_styles', $style); } return FALSE; } /** * Delete a style object from the database. * * @ingroup openlayers_api * * @param $preset * String identifier of a style or style object with name. * @return * The results of DB delete. */ function openlayers_style_delete($style) { return openlayers_object_delete($style, 'style'); } /** * Get Presets from DB or code, via cache. * * @ingroup openlayers_api * * @param $reset * Boolean whether to reset or not. * @return * Return array of presets. */ function openlayers_presets($reset = FALSE) { ctools_include('export'); if ($reset) { ctools_export_load_object_reset('openlayers_map_presets'); } $presets = ctools_export_load_object( 'openlayers_map_presets', 'all', array()); return $presets; } /** * Given a preset name, get full preset object. * * This function can also be used as a * menu loader for a style. * * @ingroup openlayers_api * * @param $name * String identifier of the preset. * @param $reset * Boolean whether to reset cache. * @return * Preset object or FALSE if not found. */ function openlayers_preset_load($name = '', $reset = FALSE) { ctools_include('export'); if ($reset) { ctools_export_load_object_reset('openlayers_map_presets'); } $presets = ctools_export_load_object( 'openlayers_map_presets', 'names', array($name)); if (empty($presets[$name])) { return FALSE; } else { $preset = $presets[$name]; $preset->data['preset_name'] = $name; return $preset; } } /** * Save a preset object to the database. * * @ingroup openlayers_api * * @param $preset * Preset object. * @return * The results of DB write or FALSE if no name. */ function openlayers_preset_save($preset) { if (!empty($preset->name)) { $exists = db_result(db_query("SELECT name FROM {openlayers_map_presets} WHERE name = '%s'", $preset->name)); return $exists ? drupal_write_record('openlayers_map_presets', $preset, 'name') : drupal_write_record('openlayers_map_presets', $preset); } return FALSE; } /** * Delete a preset object from the database. * * @ingroup openlayers_api * * @param $preset * String identifier of a preset or preset object with name. * @return * The results of DB delete. */ function openlayers_preset_delete($preset) { return openlayers_object_delete($preset, 'preset'); } /** * Get preset options in an array suitable for a FormAPI element. * * @ingroup openlayers_api * * @param $reset * Boolean whether to reset or not. * @return * Return array of formatted data. */ function openlayers_preset_options($reset = FALSE) { $presets = openlayers_presets($reset); $options = array(); foreach ($presets as $preset) { $options[$preset->name] = $preset->title; } return $options; } /** * Delete an object from the database. * * @ingroup openlayers_api * * @param $ol_object * String identifier of an object or the object with name. * @param $type * Type of object to delete. The options are the following: * - 'layer' * - 'style' * = 'preset' * @return * The results of the DB delete. */ function openlayers_object_delete($ol_object, $type) { // Check for object or name if (is_object($ol_object) && isset($ol_object->name)) { $ol_object = $ol_object->name; } // Determine query to use switch ($type) { case 'style': $query = "DELETE FROM {openlayers_styles} WHERE name = '%s'"; break; case 'layer': $query = "DELETE FROM {openlayers_layers} WHERE name = '%s'"; break; case 'preset': $query = "DELETE FROM {openlayers_map_presets} WHERE name = '%s'"; break; default: return FALSE; } return db_query($query, $ol_object); } /** * Checks map array for incompatibilities or errors. * * @ingroup openlayers_api * * @param $map * Map array * @param $log_errors * Boolean whether to log errors. * @return * FALSE if passed. Array of descriptive errors if fail. */ function openlayers_error_check_map($map, $log_errors = TRUE) { $errors = array(); // Check for layers if (!is_array($map['layers'])) { $errors[] = t('Map contains no renderable layers.'); } else { // Check layer projections foreach ($map['layers'] as $layer) { openlayers_layer_sanity_check( array('data' => $layer), $map['projection'], TRUE); } } // Check if any errors found to log if (count($errors) > 0 && $log_errors) { // Log the Error(s) watchdog('openlayers', implode(', ', $errors), array(), WATCHDOG_ERROR); } // Check if errors and return return (count($errors) > 0) ? $errors : FALSE; } /** * Get extent given projection * * Returns standard world-max-extents for common projections. * Layers implementing other projections and subsets of the * world should define their maxExtent in the layer array. * * @ingroup openlayers_api * * @param $projection * String of the projection value. Currently * supports 900913, 4326. * @return * Array of maxExtent in OpenLayers toArray() format. */ function openlayers_get_extent($projection) { switch ($projection) { case '900913': return array(-20037508, -20037508, 20037508, 20037508); case '4326': return array(-180, -90, 180, 90); } } /** * Get resolution given projection * * Returns a default set of resolutions for standard * TMS, WMS, etc servers serving up common projections. * Layers supporting less common projections and resolutions * can easily define custom resolutions arrays. * * @ingroup openlayers_api * * @param $projection * String specifying which projection this should take, like 900913. * @param $zoom_start * Integer of first zoom level, default 0. * @param $zoom_end * Integer of last zoom level, default FALSE. * @return * Array of resolutions. */ function openlayers_get_resolutions($projection, $zoom_start = 0, $zoom_end = FALSE) { switch ($projection) { case '900913': // 16 zoom levels, taken from // openlayers.org TMS map $res = array( 156543.0339, 78271.51695, 39135.758475, 19567.8792375, 9783.93961875, 4891.969809375, 2445.9849046875, 1222.99245234375, 611.496226171875, 305.7481130859375, 152.87405654296876, 76.43702827148438, 38.21851413574219, 19.109257067871095, 9.554628533935547, 4.777314266967774, 2.388657133483887, 1.1943285667419434, 0.5971642833709717); break; case '4326': // 16 zoom levels, taken from // openlayers.org default WMS map $res = array( 0.703125, 0.3515625, 0.17578125, 0.087890625, 0.0439453125, 0.02197265625, 0.010986328125, 0.0054931640625, 0.00274658203125, 0.001373291015625, 0.0006866455078125, 0.00034332275390625, 0.000171661376953125, 0.0000858306884765625, 0.00004291534423828125, 0.000021457672119140625); break; default: $res = array(); break; } $length = ($zoom_end == FALSE) ? NULL : $zoom_end - $zoom_start; // By default this will not actually clip the array $resolutions = array_slice($res, $zoom_start, $length); return $resolutions; } /** * We define base classes in the core module. * All other parent classes can be autoloaded through ctools. */ class openlayers_behavior { var $options, $map; function __construct($options = array(), $map = array()) { $this->options = $options + $this->options_init(); $this->map = $map; } /* * @return array of JavaScript functions required to be defined * in order for this function to work */ function js_dependency() { return array(); } function options_init() { return array(); } /* * @param $defaults default values for the form * @return a FormAPI form */ function options_form($defaults = array()) { return array(); } function render(&$map) {} } /** * We define base classes in the core module. * All other parent classes can be autoloaded through ctools. */ class openlayers_layer_type { var $options, $map; function __construct($layer = array(), $map = array()) { foreach (array('name', 'title', 'description', 'data', 'export_type') as $k) { if (isset($layer->{$k})) { $this->{$k} = $layer->{$k}; } } if (isset($this->data) && is_array($this->data)) { $this->data += $this->options_init(); } $this->map = $map; } function options_init() { return array(); } function options_form() { return array(); } /** * @return * A version of this layer_type which can be saved, * when attempting to save a modified layer */ function to_record() { return array( 'name' => $this->name, 'description' => $this->description, 'title' => $this->title, 'data' => $this->data ); } /** * @return * Success value on saving this layer */ function save() { if (!empty($this->name)) { $exists = db_result(db_query("SELECT name FROM {openlayers_layers} WHERE name = '%s'", $this->name)); // If this layer exists, specify that 'name' is // the primary key for the layer which will be updated return $exists ? drupal_write_record('openlayers_layers', $this->to_record(), 'name') : drupal_write_record('openlayers_layers', $this->to_record()); } } function render(&$map) {} } /** * Base class for style plugins * * We define base classes in the core module. * All other parent classes can be autoloaded through ctools. */ class openlayers_style_plugin { /** * Return true if this plugin can handle * the given property */ function can_handle_property($propname) { return array_key_exists($propname, $this->get_context_properties()); } /** * Get an array of style property callbacks * * @return * Array of => */ function get_context_properties() { return array(); } /** * Initial default options. * * @return * Array of default options. */ function options_init() { return array(); } /** * Options form. * * @param $defaults * Array of default values for the form. * @return * Array of Drupal form elements. */ function options_form($defaults = array()) { return array(); } /** * Render the style. */ function render() { // Render style. } } /** * Implementation of hook_ctools_plugin_directory */ function openlayers_ctools_plugin_directory($module, $plugin) { // The format of plugin includes should be the // following: // modulename_plugin_name.inc // // For example: // openlayers_style_plugin_name.inc // If this module needed to supply style plugins. /* if ($module == 'openlayers' && $plugin == 'style_plugin') { return 'plugins/style_plugin'; } */ // This should change to the following when converted: /* if ($module == 'openlayers') { return 'plugins/' . $plugin; } */ } /** * Implementation of hook_ctools_plugin */ function openlayers_ctools_plugin_behaviors() { return array( 'use hooks' => TRUE, ); } /** * Implementation of hook_ctools_plugin */ function openlayers_ctools_plugin_layer_types() { return array( 'use hooks' => TRUE, ); } /** * Implementation of hook_ctools_plugin_api(). */ function openlayers_ctools_plugin_api($module, $api) { if ($module == "openlayers") { switch ($api) { case 'openlayers_presets': return array('version' => 1); case 'openlayers_layers': return array('version' => 1); case 'openlayers_styles': return array('version' => 1); } } } /** * Implementation of hook_openlayers_layers(). */ function openlayers_openlayers_layers() { module_load_include('inc', 'openlayers', 'includes/openlayers.layers'); return _openlayers_openlayers_layers(); } /** * Implementation of hook_openlayers_behaviors(). */ function openlayers_openlayers_behaviors() { module_load_include('inc', 'openlayers', 'includes/openlayers.behaviors'); return _openlayers_openlayers_behaviors(); } /** * Implementation of hook_openlayers_styles(). */ function openlayers_openlayers_styles() { module_load_include('inc', 'openlayers', 'includes/openlayers.styles'); return _openlayers_openlayers_styles(); } /** * Implementation of hook_openlayers_presets(). */ function openlayers_openlayers_presets() { module_load_include('inc', 'openlayers', 'includes/openlayers.presets'); return _openlayers_openlayers_presets(); } /** * Implementation of hook_openlayers_layer_types(). */ function openlayers_openlayers_layer_types() { module_load_include('inc', 'openlayers', 'includes/openlayers.layer_types'); return _openlayers_openlayers_layer_types(); }