View source
<?php
define('LOCATION_PATH', drupal_get_path('module', 'location'));
define('LOCATION_LATLON_UNDEFINED', 0);
define('LOCATION_LATLON_USER_SUBMITTED', 1);
define('LOCATION_LATLON_GEOCODED_APPROX', 2);
define('LOCATION_LATLON_GEOCODED_EXACT', 3);
define('LOCATION_LATLON_JIT_GEOCODING', 4);
define('LOCATION_USER_DONT_COLLECT', 0);
define('LOCATION_USER_COLLECT', 1);
include_once LOCATION_PATH . '/location.inc';
require_once LOCATION_PATH . '/location.d5.inc';
function location_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'location/autocomplete',
'access' => user_access('access content'),
'callback' => '_location_autocomplete',
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'admin/settings/location',
'title' => t('Location'),
'description' => t('Settings for Location module'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'location_admin_settings',
),
'access' => user_access('administer site configuration'),
);
$items[] = array(
'path' => 'admin/settings/location/main',
'title' => t('Main settings'),
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items[] = array(
'path' => 'admin/settings/location/maplinking',
'title' => t('Map links'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'location_map_link_options_form',
),
'access' => user_access('administer site configuration'),
'type' => MENU_LOCAL_TASK,
'weight' => 1,
);
$items[] = array(
'path' => 'admin/settings/location/geocoding',
'title' => t('Geocoding options'),
'callback' => 'location_geocoding_options_page',
'access' => user_access('administer site configuration'),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);
$items[] = array(
'path' => 'admin/settings/location/util',
'title' => t('Location utilities'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'location_util_form',
),
'access' => user_access('administer site configuration'),
'type' => MENU_LOCAL_TASK,
'weight' => 3,
);
}
return $items;
}
function location_api_variant() {
return 2;
}
function location_perm() {
return array(
'submit latitude/longitude',
);
}
function location_help($section) {
switch ($section) {
case 'admin/help#location':
$output = '<p>' . t('The location module allows you to associate a geographic location with content and users. Users can do proximity searches by postal code. This is useful for organizing communities that have a geographic presence.') . '</p>';
$output .= '<p>' . t('To administer locative information for content, use the content type administration page. To support most location enabled features, you will need to install the country specific include file. To support postal code proximity searches for a particular country, you will need a database dump of postal code data for that country. As of June 2007 only U.S. and German postal codes are supported.') . '</p>';
$output .= t('<p>You can</p>
<ul>
<li>administer locative information at <a href="@admin-node-configure-types">Administer >> Content management >> Content types</a> to configure a type and see the locative information.</li>
<li>administer location at <a href="@admin-settings-location">Administer >> Site configuration >> Location</a>.</li>
<li>use a database dump for a U.S. and/or German postal codes table that can be found at <a href="@external-http-cvs-drupal-org">zipcode database</a>.</li>
', array(
'@admin-node-configure-types' => url('admin/content/types'),
'@admin-settings-location' => url('admin/settings/location'),
'@external-http-cvs-drupal-org' => 'http://cvs.drupal.org/viewcvs/drupal/contributions/modules/location/database/',
)) . '</ul>';
$output .= '<p>' . t('For more information please read the configuration and customization handbook <a href="@location">Location page</a>.', array(
'@location' => 'http://www.drupal.org/handbook/modules/location/',
)) . '</p>';
return $output;
}
}
function location_elements() {
return array(
'location_element' => array(
'#input' => TRUE,
'#process' => array(
'_location_expand_location' => array(),
),
'#tree' => TRUE,
'#location_settings' => array(),
'#required' => FALSE,
'#attributes' => array(
'class' => 'location',
),
'#validate' => array(
'location_element_validate' => array(),
),
),
'location_settings' => array(
'#input' => FALSE,
'#process' => array(
'_location_expand_location_settings' => array(),
),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
),
);
}
function theme_location_element($element) {
unset($element['#value']);
return theme('fieldset', $element);
}
function location_simpletest() {
$dir = drupal_get_path('module', 'location') . '/tests';
$tests = file_scan_directory($dir, '\\.test$');
return array_keys($tests);
}
function _location_expand_location($element) {
drupal_add_css(drupal_get_path('module', 'location') . '/location.css');
$element['#tree'] = TRUE;
if (!isset($element['#title'])) {
$element['#title'] = t('Location');
}
if (empty($element['#location_settings'])) {
$element['#location_settings'] = array();
}
if (!isset($element['#default_value']) || $element['#default_value'] == 0) {
$element['#default_value'] = array();
}
$element['location_settings'] = array(
'#type' => 'value',
'#value' => $element['#location_settings'],
);
unset($element['#location_settings']);
$settings =& $element['location_settings']['#value'];
if (isset($element['#default_value']['lid']) && $element['#default_value']['lid']) {
$element['lid'] = array(
'#type' => 'value',
'#value' => $element['#default_value']['lid'],
);
}
location_normalize_settings($settings, $element['#required']);
$defaults = location_empty_location($settings);
if (isset($element['lid']['#value']) && $element['lid']['#value']) {
$defaults = location_load_location($element['lid']['#value']);
}
$fsettings =& $settings['form']['fields'];
$fields = location_field_names();
foreach ($fields as $field => $title) {
if (!isset($element[$field])) {
if ($fsettings[$field]['collect'] != 0) {
$element[$field] = location_invoke_locationapi($defaults[$field], 'field_expand', $field, $fsettings[$field]['collect'], $defaults);
$element[$field]['#weight'] = (int) $fsettings[$field]['weight'];
}
}
}
if (!isset($element['street'])) {
unset($element['additional']);
}
if (user_access('submit latitude/longitude') && $fsettings['locpick']['collect']) {
$element['locpick'] = array(
'#weight' => $fsettings['locpick']['weight'],
);
if (location_has_coordinates($defaults, FALSE)) {
$element['locpick']['current'] = array(
'#type' => 'fieldset',
'#title' => t('Current coordinates'),
'#attributes' => array(
'class' => 'location-current-coordinates-fieldset',
),
);
$element['locpick']['current']['current_latitude'] = array(
'#type' => 'item',
'#title' => t('Latitude'),
'#value' => $defaults['latitude'],
);
$element['locpick']['current']['current_longitude'] = array(
'#type' => 'item',
'#title' => t('Longitude'),
'#value' => $defaults['longitude'],
);
$source = t('Unknown');
switch ($defaults['source']) {
case LOCATION_LATLON_USER_SUBMITTED:
$source = t('User-submitted');
break;
case LOCATION_LATLON_GEOCODED_APPROX:
$source = t('Geocoded (Postal code level)');
break;
case LOCATION_LATLON_GEOCODED_EXACT:
$source = t('Geocoded (Exact)');
}
$element['locpick']['current']['current_source'] = array(
'#type' => 'item',
'#title' => t('Source'),
'#value' => $source,
);
}
$element['locpick']['user_latitude'] = array(
'#type' => 'textfield',
'#title' => t('Latitude'),
'#default_value' => isset($element['#default_value']['locpick']['user_latitude']) ? $element['#default_value']['locpick']['user_latitude'] : '',
'#size' => 16,
'#attributes' => array(
'class' => 'container-inline',
),
'#maxlength' => 20,
'#required' => $fsettings['locpick']['collect'] == 2,
);
$element['locpick']['user_longitude'] = array(
'#type' => 'textfield',
'#title' => t('Longitude'),
'#default_value' => isset($element['#default_value']['locpick']['user_longitude']) ? $element['#default_value']['locpick']['user_longitude'] : '',
'#size' => 16,
'#maxlength' => 20,
'#required' => $fsettings['locpick']['collect'] == 2,
);
$element['locpick']['instructions'] = array(
'#type' => 'markup',
'#weight' => 1,
'#prefix' => '<div class=\'description\'>',
'#value' => '<br /><br />' . t('If you wish to supply your own latitude and longitude, you may enter them above. If you leave these fields blank, the system will attempt to determine a latitude and longitude for you from the entered address. To have the system recalculate your location from the address, for example if you change the address, delete the values for these fields.'),
'#suffix' => '</div>',
);
if (function_exists('gmap_get_auto_mapid') && variable_get('location_usegmap', FALSE)) {
$mapid = gmap_get_auto_mapid();
$map = gmap_parse_macro(variable_get('location_locpick_macro', '[gmap]'));
$map['id'] = $mapid;
$map['points'] = array();
$map['pointsOverlays'] = array();
$map['lines'] = array();
$map['behavior']['locpick'] = TRUE;
$map['behavior']['collapsehack'] = TRUE;
if (location_has_coordinates($defaults, FALSE)) {
$map['latitude'] = (double) $defaults['latitude'];
$map['longitude'] = (double) $defaults['longitude'];
$map['markers'][] = array(
'latitude' => $defaults['latitude'],
'longitude' => $defaults['longitude'],
'markername' => 'small gray',
'offset' => 0,
'opts' => array(
'clickable' => FALSE,
),
);
}
$element['locpick']['user_latitude']['#map'] = $mapid;
gmap_widget_setup($element['locpick']['user_latitude'], 'locpick_latitude');
$element['locpick']['user_longitude']['#map'] = $mapid;
gmap_widget_setup($element['locpick']['user_longitude'], 'locpick_longitude');
$element['locpick']['map'] = array(
'#type' => 'gmap',
'#weight' => -1,
'#map' => $mapid,
'#settings' => $map,
);
$element['locpick']['map_instructions'] = array(
'#type' => 'markup',
'#weight' => 2,
'#prefix' => '<div class=\'description\'>',
'#value' => t('You may set the location by clicking on the map, or dragging the location marker. To clear the location and cause it to be recalculated, click on the marker.'),
'#suffix' => '</div>',
);
}
}
if (isset($defaults['lid']) && !empty($defaults['lid'])) {
$element['delete_location'] = array(
'#type' => 'checkbox',
'#title' => t('Delete'),
'#default_value' => FALSE,
'#description' => t('Check this box to delete this location.'),
);
}
$element += _element_info('fieldset');
return $element;
}
function _location_expand_location_settings($element) {
$value = is_array($element['#value']) ? $element['#value'] : array();
$element['#tree'] = TRUE;
$element['#theme'] = 'location_settings';
if (!isset($element['#title'])) {
$element['#title'] = t('Location Fields');
}
if (!isset($element['#default_value']) || $element['#default_value'] == 0) {
$element['#default_value'] = array();
}
$element['#tree'] = TRUE;
$defaults = $element['#default_value'];
if (!isset($defaults) || !is_array($defaults)) {
$defaults = array();
}
$temp = location_invoke_locationapi($element, 'defaults');
foreach ($temp as $k => $v) {
if (!isset($defaults[$k])) {
$defaults[$k] = array();
}
$defaults[$k] = array_merge($v, $defaults[$k]);
}
$fields = location_field_names();
$options = array(
0 => t('Do not collect'),
1 => t('Allow'),
2 => t('Require'),
4 => t('Force Default'),
);
foreach ($fields as $field => $title) {
$element[$field] = array(
'#type' => 'fieldset',
'#tree' => TRUE,
);
$element[$field]['name'] = array(
'#type' => 'item',
'#value' => $title,
);
$element[$field]['collect'] = array(
'#type' => 'select',
'#default_value' => $defaults[$field]['collect'],
'#options' => $options,
);
$temp = $defaults[$field]['default'];
$element[$field]['default'] = location_invoke_locationapi($temp, 'field_expand', $field, 1, $defaults);
$defaults[$field]['default'] = $temp;
$element[$field]['weight'] = array(
'#type' => 'weight',
'#delta' => 100,
'#default_value' => $defaults[$field]['weight'],
);
}
return $element;
}
function theme_location_settings($element) {
$rows = array();
$header = array(
array(
'data' => t('Name'),
'colspan' => 2,
),
t('Collect'),
t('Default'),
t('Weight'),
);
$element['country']['default']['#required'] = TRUE;
unset($element['country']['collect']['#options'][0]);
foreach (element_children($element) as $key) {
$element[$key]['weight']['#attributes']['class'] = 'location-settings-weight';
unset($element[$key]['default']['#title']);
$row = array();
$row[] = array(
'data' => '',
'class' => 'location-settings-drag',
);
$row[] = drupal_render($element[$key]['name']);
$row[] = drupal_render($element[$key]['collect']);
$row[] = drupal_render($element[$key]['default']);
$row[] = array(
'data' => drupal_render($element[$key]['weight']),
'class' => 'delta-order',
);
$rows[] = array(
'data' => $row,
'class' => 'draggable',
);
}
$output = theme('table', $header, $rows, array(
'id' => 'location-settings-table',
));
return $output;
}
function location_field_names($all = FALSE) {
static $fields;
static $allfields;
if ($all) {
if (empty($allfields)) {
$dummy = array();
$allfields = location_invoke_locationapi($dummy, 'fields');
$virtual = location_invoke_locationapi($dummy, 'virtual fields');
$allfields += $virtual;
}
return $allfields;
}
else {
if (empty($fields)) {
$dummy = array();
$fields = location_invoke_locationapi($dummy, 'fields');
}
return $fields;
}
}
function location_locationapi(&$obj, $op, $a3 = NULL, $a4 = NULL, $a5 = NULL) {
switch ($op) {
case 'fields':
return array(
'name' => t('Location name'),
'street' => t('Street location'),
'additional' => t('Additional'),
'city' => t('City'),
'province' => t('State/Province'),
'postal_code' => t('Postal code'),
'country' => t('Country'),
'locpick' => t('Coordinate Chooser'),
);
case 'virtual fields':
return array(
'province_name' => t('Province name'),
'country_name' => t('Country name'),
'map_link' => t('Map link'),
'coords' => t('Coordinates'),
);
case 'defaults':
return array(
'lid' => array(
'default' => FALSE,
),
'name' => array(
'default' => '',
'collect' => 1,
'weight' => 2,
),
'street' => array(
'default' => '',
'collect' => 1,
'weight' => 4,
),
'additional' => array(
'default' => '',
'collect' => 1,
'weight' => 6,
),
'city' => array(
'default' => '',
'collect' => 0,
'weight' => 8,
),
'province' => array(
'default' => '',
'collect' => 0,
'weight' => 10,
),
'postal_code' => array(
'default' => '',
'collect' => 0,
'weight' => 12,
),
'country' => array(
'default' => variable_get('location_default_country', 'us'),
'collect' => 1,
'weight' => 14,
),
'locpick' => array(
'default' => FALSE,
'collect' => 1,
'weight' => 20,
'nodiff' => TRUE,
),
'latitude' => array(
'default' => 0,
),
'longitude' => array(
'default' => 0,
),
'source' => array(
'default' => LOCATION_LATLON_UNDEFINED,
),
'is_primary' => array(
'default' => 0,
),
);
case 'validate':
if (!empty($obj['country'])) {
if (!empty($obj['province'])) {
$provinces = location_get_provinces($obj['country']);
$found = FALSE;
$p = strtoupper($obj['province']);
foreach ($provinces as $k => $v) {
if ($p == strtoupper($k) || $p == strtoupper($v)) {
$found = TRUE;
break;
}
}
if (!$found) {
form_error($a3['province'], t('The specified province was not found in the specified country.'));
}
}
}
if (!empty($obj['locpick']) && is_array($obj['locpick'])) {
if (_location_floats_are_equal($obj['locpick']['user_latitude'], 0) xor _location_floats_are_equal($obj['locpick']['user_longitude'], 0)) {
$ref =& $a3['locpick']['user_latitude'];
if (_location_floats_are_equal($obj['locpick']['user_longitude'], 0)) {
$ref =& $a3['locpick']['user_longitude'];
}
form_error($ref, t('You must fill out both latitude and longitude or you must leave them both blank.'));
}
}
break;
case 'field_expand':
switch ($a3) {
case 'name':
return array(
'#type' => 'textfield',
'#title' => t('Location name'),
'#default_value' => $obj,
'#size' => 64,
'#maxlength' => 255,
'#description' => t('e.g. a place of business, venue, meeting point'),
'#attributes' => NULL,
'#required' => $a4 == 2,
);
case 'street':
return array(
'#type' => 'textfield',
'#title' => t('Street'),
'#default_value' => $obj,
'#size' => 64,
'#maxlength' => 255,
'#required' => $a4 == 2,
);
case 'additional':
return array(
'#type' => 'textfield',
'#title' => t('Additional'),
'#default_value' => $obj,
'#size' => 64,
'#maxlength' => 255,
);
case 'city':
return array(
'#type' => 'textfield',
'#title' => t('City'),
'#default_value' => $obj,
'#size' => 64,
'#maxlength' => 255,
'#description' => NULL,
'#attributes' => NULL,
'#required' => $a4 == 2,
);
case 'province':
drupal_add_js(drupal_get_path('module', 'location') . '/location_autocomplete.js');
if (isset($a5['country']) && is_string($a5['country'])) {
$country = $a5['country'];
}
elseif (isset($a5['country']['default']) && is_string($a5['country']['default'])) {
$country = $a5['country']['default'];
}
else {
$country = variable_get('site_default_country', 'us');
}
return array(
'#type' => 'textfield',
'#title' => t('State/Province'),
'#autocomplete_path' => 'location/autocomplete/' . $country,
'#default_value' => variable_get('location_use_province_abbreviation', 1) ? $obj : location_province_name($country, $obj),
'#size' => 64,
'#maxlength' => 64,
'#description' => NULL,
'#attributes' => array(
'class' => 'location_auto_province',
),
'#required' => $a4 == 2,
);
case 'country':
if ($a4 == 4) {
return array(
'#type' => 'value',
'#value' => $obj,
);
}
else {
$options = array_merge(array(
'' => t('Please select'),
'xx' => t('NOT LISTED'),
), location_get_iso3166_list());
return array(
'#type' => 'select',
'#title' => t('Country'),
'#default_value' => $obj,
'#options' => $options,
'#description' => NULL,
'#required' => $a4 == 2,
'#attributes' => array(
'class' => 'location_auto_country',
),
);
}
break;
case 'postal_code':
return array(
'#type' => 'textfield',
'#title' => t('Postal code'),
'#default_value' => $obj,
'#size' => 16,
'#maxlength' => 16,
'#required' => $a4 == 2,
);
}
break;
case 'isunchanged':
switch ($a3) {
case 'lid':
if (empty($obj[$a3]) && empty($a4)) {
return TRUE;
}
break;
case 'latitude':
case 'longitude':
if (_location_floats_are_equal($obj[$a3], $a4)) {
return TRUE;
}
break;
case 'country':
if (trim($obj[$a3]) == trim($a4)) {
return TRUE;
}
break;
case 'province_name':
case 'country_name':
case 'map_link':
case 'coords':
case 'locpick':
return TRUE;
}
break;
}
}
function location_geocoding_parameters_page($country_iso, $service) {
drupal_set_title(t('Configure parameters for %service geocoding', array(
'%service' => $service,
)));
$breadcrumbs = drupal_get_breadcrumb();
$breadcrumbs[] = l('location', 'admin/settings/location');
$breadcrumbs[] = l('geocoding', 'admin/settings/location/geocoding');
$countries = location_get_iso3166_list();
$breadcrumbs[] = l($countries[$country_iso], 'admin/settings/location/geocoding', array(), NULL, $country_iso);
drupal_set_breadcrumb($breadcrumbs);
return drupal_get_form('location_geocoding_parameters_form', $country_iso, $service);
}
function location_geocoding_parameters_form($country_iso, $service) {
location_load_country($country_iso);
$geocode_settings_form_function_specific = 'location_geocode_' . $country_iso . '_' . $service . '_settings';
$geocode_settings_form_function_general = $service . '_geocode_settings';
if (function_exists($geocode_settings_form_function_specific)) {
return system_settings_form($geocode_settings_form_function_specific());
}
location_load_geocoder($service);
if (function_exists($geocode_settings_form_function_general)) {
return system_settings_form($geocode_settings_form_function_general());
}
else {
return system_settings_form(array(
'#type' => 'markup',
'#value' => t('No configuration parameters are necessary, or a form to take such paramters has not been implemented.'),
));
}
}
function location_load_locations($id, $key = 'vid') {
if (empty($id)) {
return array();
}
if ($key == 'genid') {
$result = db_query('SELECT lid FROM {location_instance} WHERE ' . db_escape_table($key) . " = '%s'", $id);
}
else {
$result = db_query('SELECT lid FROM {location_instance} WHERE ' . db_escape_table($key) . ' = %d', $id);
}
$locations = array();
while ($lid = db_fetch_object($result)) {
$locations[] = location_load_location($lid->lid);
}
return $locations;
}
function location_save_locations(&$locations, $criteria) {
if (isset($locations) && is_array($locations) && !empty($criteria) && is_array($criteria)) {
foreach (array_keys($locations) as $key) {
location_save($locations[$key], TRUE, $criteria);
}
$columns = array();
$placeholders = array();
$qfrags = array();
$args = array();
foreach (array(
'nid' => '%d',
'vid' => '%d',
'uid' => '%d',
'genid' => "'%s'",
) as $key => $placeholder) {
if (isset($criteria[$key])) {
$columns[] = $key;
$placeholders[] = $placeholder;
$args[] = $criteria[$key];
$qfrags[] = "{$key} = {$placeholder}";
}
}
$querybase = 'FROM {location_instance} WHERE ' . implode(' AND ', $qfrags);
$oldlids = array();
$newlids = array();
$query = "SELECT lid {$querybase}";
$result = db_query($query, $args);
while ($t = db_fetch_object($result)) {
$oldlids[] = $t->lid;
}
$query = "DELETE {$querybase}";
db_query($query, $args);
$columns[] = 'lid';
$placeholders[] = '%d';
foreach ($locations as $location) {
if ($location['lid'] !== FALSE) {
$args[] = $location['lid'];
$newlids[] = $location['lid'];
db_query('INSERT INTO {location_instance} (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $placeholders) . ')', $args);
array_pop($args);
}
}
foreach (array_diff($oldlids, $newlids) as $check) {
$count = db_result(db_query('SELECT COUNT(*) FROM {location_instance} WHERE lid = %d', $check));
if ($count !== FALSE && $count == 0) {
watchdog('location', t('Deleting unreferenced location with LID %lid.', array(
'%lid' => $check,
)));
$location = array(
'lid' => $check,
);
location_invoke_locationapi($location, 'delete');
db_query('DELETE FROM {location} WHERE lid = %d', $location['lid']);
}
}
}
}
function location_load_location($lid) {
$location = db_fetch_array(db_query('SELECT * FROM {location} WHERE lid = %d', $lid));
if (empty($location)) {
$location = array(
'lid' => $lid,
);
}
if (isset($location['source']) && $location['source'] == LOCATION_LATLON_USER_SUBMITTED) {
$location['locpick'] = array(
'user_latitude' => $location['latitude'],
'user_longitude' => $location['longitude'],
);
}
if (isset($location['source']) && $location['source'] == LOCATION_LATLON_JIT_GEOCODING) {
if (variable_get('location_jit_geocoding', FALSE)) {
_location_geo_logic($location, array(
'street' => 1,
), array());
db_query("UPDATE {location} SET latitude = '%f', longitude = '%f', source = %d WHERE lid = %d", $location['latitude'], $location['longitude'], $location['source'], $location['lid']);
}
}
$location['province_name'] = '';
$location['country_name'] = '';
if (!empty($location['country'])) {
$location['country_name'] = location_country_name($location['country']);
if (!empty($location['province'])) {
$location['province_name'] = location_province_name($location['country'], $location['province']);
}
}
$location = array_merge($location, location_invoke_locationapi($location, 'load', $lid));
return $location;
}
function _location_autocomplete($country, $string = '') {
$counter = 0;
$string = strtolower($string);
$string = '/^' . preg_quote($string) . '/';
$matches = array();
if (strpos($country, ',') !== FALSE) {
$provinces = array();
$country = explode(',', $country);
foreach ($country as $c) {
$provinces = $provinces + location_get_provinces($c);
}
}
else {
$provinces = location_get_provinces($country);
}
if (!empty($provinces)) {
while (list($code, $name) = each($provinces)) {
if ($counter < 5) {
if (preg_match($string, strtolower($name))) {
$matches[$name] = $name;
++$counter;
}
}
}
}
drupal_set_header('Content-Type: text/javascript; charset=utf-8');
echo drupal_to_js($matches);
return;
}
function _location_floats_are_equal($x, $y) {
$x = floatval($x);
$y = floatval($y);
return abs(max($x, $y) - min($x, $y)) < pow(10, -6);
}
function location_has_coordinates($location, $canonical = FALSE) {
if ($canonical) {
return $location['source'] != LOCATION_LATLON_UNDEFINED;
}
if (empty($location['latitude']) || empty($location['longitude'])) {
return FALSE;
}
if (_location_floats_are_equal($location['latitude'], 0.0) || _location_floats_are_equal($location['longitude'], 0.0)) {
return FALSE;
}
return TRUE;
}
function location_invoke_locationapi(&$location, $op, $a3 = NULL, $a4 = NULL, $a5 = NULL) {
$return = array();
foreach (module_implements('locationapi') as $name) {
$function = $name . '_locationapi';
$result = $function($location, $op, $a3, $a4, $a5);
if (isset($result) && is_array($result)) {
$return = array_merge($return, $result);
}
else {
if (isset($result)) {
$return[] = $result;
}
}
}
return $return;
}
function _location_patch_locpick(&$location) {
$inhibit_geocode = FALSE;
if (!empty($location['locpick'])) {
$location['locpick']['user_latitude'] = trim($location['locpick']['user_latitude']);
$location['locpick']['user_longitude'] = trim($location['locpick']['user_longitude']);
}
if (!empty($location['locpick']['user_latitude']) && !empty($location['locpick']['user_longitude'])) {
$location['source'] = LOCATION_LATLON_USER_SUBMITTED;
$location['latitude'] = $location['locpick']['user_latitude'];
$location['longitude'] = $location['locpick']['user_longitude'];
$inhibit_geocode = TRUE;
}
return $inhibit_geocode;
}
function location_save(&$location, $cow = TRUE, $criteria = array()) {
if (!isset($location['location_settings'])) {
$location['location_settings'] = array();
}
location_normalize_settings($location['location_settings']);
$inhibit_geocode = FALSE;
if (isset($location['inhibit_geocode']) && $location['inhibit_geocode']) {
$inhibit_geocode = TRUE;
unset($location['inhibit_geocode']);
}
if (isset($location['delete_location']) && $location['delete_location']) {
$location['lid'] = FALSE;
return FALSE;
}
$oldloc = location_empty_location($location['location_settings']);
if (isset($location['lid']) && !empty($location['lid'])) {
$oldloc = (array) location_load_location($location['lid']);
}
if (_location_patch_locpick($location)) {
$inhibit_geocode = TRUE;
}
$location = array_merge($oldloc, $location);
$filled = array();
if (location_is_empty($location, $filled)) {
$location['lid'] = FALSE;
return FALSE;
}
$changed = array();
if (!location_calc_difference($oldloc, $location, $changed)) {
if (!empty($location['lid'])) {
return $location['lid'];
}
else {
$location['lid'] = FALSE;
return FALSE;
}
}
_location_geo_logic($location, $changed, $filled, $inhibit_geocode);
if ($cow) {
if (isset($location['lid']) && $location['lid']) {
if (!empty($criteria)) {
$columns = array();
$placeholders = array();
$qfrags = array();
$args = array();
foreach (array(
'nid' => '%d',
'vid' => '%d',
'uid' => '%d',
'genid' => "'%s'",
) as $key => $placeholder) {
if (isset($criteria[$key])) {
$columns[] = $key;
$placeholders[] = $placeholder;
$args[] = $criteria[$key];
$qfrags[] = "{$key} = {$placeholder}";
}
}
$querybase = 'FROM {location_instance} WHERE ' . implode(' AND ', $qfrags);
$associated = db_result(db_query("SELECT COUNT(*) {$querybase}"));
$all = db_result(db_query("SELECT COUNT(*) FROM {location_instance} WHERE lid = %d", $location['lid']));
if ($associated != $all) {
unset($location['lid']);
}
}
else {
unset($location['lid']);
}
}
}
if (empty($location['lid'])) {
$location['lid'] = db_next_id('{location}_lid');
}
db_query('DELETE FROM {location} WHERE lid = %d', $location['lid']);
db_query("INSERT INTO {location}\n (lid, name, street, additional, city, province, postal_code, country, latitude, longitude, source)\n VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%f', '%f', %d)", $location['lid'], $location['name'], $location['street'], $location['additional'], $location['city'], $location['province'], $location['postal_code'], $location['country'], $location['latitude'], $location['longitude'], $location['source']);
location_invoke_locationapi($location, 'save');
return $location['lid'];
}
function location_calc_difference($oldloc, $newloc, &$changes) {
location_strip($oldloc);
location_strip($newloc);
$location_changed = FALSE;
foreach ($newloc as $k => $v) {
if (!isset($oldloc[$k])) {
$changes[$k] = TRUE;
$location_changed = TRUE;
continue;
}
else {
if ($oldloc[$k] == $v) {
$changes[$k] = FALSE;
continue;
}
}
$results = location_invoke_locationapi($newloc, 'isunchanged', $k, $oldloc[$k]);
$waschanged = TRUE;
foreach ($results as $r) {
if ($r) {
$waschanged = FALSE;
$changes[$k] = FALSE;
}
}
if ($waschanged) {
$changes[$k] = TRUE;
$location_changed = TRUE;
}
}
if (!$location_changed) {
return FALSE;
}
return TRUE;
}
function location_is_empty($location, &$filled) {
if (empty($location)) {
return TRUE;
}
_location_patch_locpick($location);
$settings = isset($location['location_settings']) ? $location['location_settings'] : array();
$emptyloc = location_empty_location($settings);
return !location_calc_difference($emptyloc, $location, $filled);
}
function location_empty_location($settings) {
$location = array();
$defaults = location_invoke_locationapi($location, 'defaults');
if (isset($settings['form']['fields'])) {
foreach ($settings['form']['fields'] as $k => $v) {
if (isset($defaults[$k])) {
$defaults[$k] = array_merge($defaults[$k], $v);
}
}
}
foreach ($defaults as $k => $v) {
if (isset($v['default'])) {
$location[$k] = $v['default'];
}
}
return $location;
}
function location_strip(&$location) {
static $tmp;
if (!isset($tmp)) {
$tmp = array();
$defaults = location_invoke_locationapi($location, 'defaults');
foreach ($defaults as $k => $v) {
if (!isset($v['nodiff'])) {
$tmp[$k] = TRUE;
}
}
}
foreach ($location as $k => $v) {
if (!isset($tmp[$k])) {
unset($location[$k]);
}
}
}
function location_normalize_settings(&$settings, $required = TRUE) {
if (!isset($settings['form'])) {
$settings['form'] = array();
}
if (!isset($settings['form']['fields'])) {
$settings['form']['fields'] = array();
}
$dummy = array();
$ds = location_invoke_locationapi($dummy, 'defaults');
foreach ($ds as $k => $v) {
if (!isset($settings['form']['fields'][$k])) {
$settings['form']['fields'][$k] = array();
}
$settings['form']['fields'][$k] = array_merge($v, $settings['form']['fields'][$k]);
}
if (!$required) {
foreach ($settings['form']['fields'] as $k => $v) {
if (isset($v['collect'])) {
if ($v['collect'] == 2) {
$settings['form']['fields'][$k]['collect'] = 1;
}
}
}
}
}
function _location_geo_logic(&$location, $changed, $filled, $inhibit_geocode = FALSE) {
if (!$inhibit_geocode) {
if ($changed['street'] || $changed['additional'] || $changed['city'] || $changed['province'] || $changed['country'] || $changed['postal_code'] || $location['source'] == LOCATION_LATLON_USER_SUBMITTED) {
if ($data = location_latlon_exact($location)) {
$location['source'] = LOCATION_LATLON_GEOCODED_EXACT;
$location['latitude'] = $data['lat'];
$location['longitude'] = $data['lon'];
}
elseif ($data = location_get_postalcode_data($location)) {
$location['source'] = LOCATION_LATLON_GEOCODED_APPROX;
$location['latitude'] = $data['lat'];
$location['longitude'] = $data['lon'];
}
else {
$location['source'] = LOCATION_LATLON_UNDEFINED;
$location['latitude'] = 0;
$location['longitude'] = 0;
}
}
}
while ($location['latitude'] > 90) {
$location['latitude'] -= 180;
}
while ($location['latitude'] < -90) {
$location['latitude'] += 180;
}
while ($location['longitude'] > 180) {
$location['longitude'] -= 360;
}
while ($location['longitude'] < -180) {
$location['longitude'] += 360;
}
if (!empty($location['postal_code'])) {
if (empty($location['city']) || empty($location['province'])) {
if ($data = location_get_postalcode_data($location)) {
$location['city'] = $data['city'];
$location['province'] = $data['province'];
}
}
}
if (!empty($location['province']) && !empty($location['country'])) {
$location['province'] = location_province_code($location['country'], $location['province']);
}
}
function location_element_validate($form) {
location_invoke_locationapi($form['#value'], 'validate', $form);
}
function location_dd_to_dms($coord) {
$negative = $coord < 0 ? TRUE : FALSE;
$coord = abs($coord);
$degrees = floor($coord);
$coord -= $degrees;
$coord *= 60;
$minutes = floor($coord);
$coord -= $minutes;
$coord *= 60;
$seconds = round($coord, 6);
return array(
$degrees,
$minutes,
$seconds,
$negative,
);
}
function theme_location_latitude_dms($latitude) {
$output = '';
list($degrees, $minutes, $seconds, $negative) = location_dd_to_dms($latitude);
$output .= "{$degrees}° {$minutes}' {$seconds}\" ";
if (!$negative) {
$output .= 'N';
}
else {
$output .= 'S';
}
return $output;
}
function theme_location_longitude_dms($longitude) {
$output = '';
list($degrees, $minutes, $seconds, $negative) = location_dd_to_dms($longitude);
$output .= "{$degrees}° {$minutes}' {$seconds}\" ";
if (!$negative) {
$output .= 'E';
}
else {
$output .= 'W';
}
return $output;
}
function location_token_values($type, $object = NULL) {
require_once drupal_get_path('module', 'location') . '/location.token.inc';
return _location_token_values($type, $object);
}
function location_token_list($type = 'all') {
require_once drupal_get_path('module', 'location') . '/location.token.inc';
return _location_token_list($type);
}
if (module_exists('location_search')) {
function location_search($op = 'search', $keys = NULL) {
return _location_search($op, $keys);
}
}
function template_preprocess_location(&$variables) {
$location = $variables['location'];
$location['map_link'] = TRUE;
if (is_array($variables['hide'])) {
foreach ($variables['hide'] as $key) {
unset($location[$key]);
if ($key == 'coords') {
unset($location['latitude']);
unset($location['longitude']);
}
}
}
$fields = location_field_names(TRUE);
if (is_array($fields)) {
foreach ($fields as $key => $value) {
$variables[$key] = '';
if (!empty($location[$key]) && !is_array($location[$key])) {
$variables[$key] = check_plain($location[$key]);
}
}
}
$variables['map_link'] = '';
if (!empty($location['map_link'])) {
$variables['map_link'] = location_map_link($variables['location']);
}
$variables['latitude'] = '';
$variables['latitude_dms'] = '';
if (!empty($location['latitude'])) {
$variables['latitude'] = check_plain($location['latitude']);
$variables['latitude_dms'] = theme('location_latitude_dms', $location['latitude']);
}
$variables['longitude'] = '';
$variables['longitude_dms'] = '';
if (!empty($location['longitude'])) {
$variables['longitude'] = check_plain($location['longitude']);
$variables['longitude_dms'] = theme('location_longitude_dms', $location['longitude']);
}
if (!empty($location['country']) && location_standardize_country_code($location['country'])) {
$variables['template_files'][] = 'location-' . $location['country'];
}
if (!isset($location['province'])) {
$location['province'] = '';
}
if (!isset($location['province_name'])) {
$location['province_name'] = '';
}
$variables['province_print'] = variable_get('location_use_province_abbreviation', 1) ? $location['province'] : $location['province_name'];
}
function template_preprocess_location_distance(&$variables) {
$units = $variables['units'];
unset($variables['units']);
if ($units == 'km') {
$variables['shortunit'] = 'km';
$variables['longunit'] = 'kilometer(s)';
}
if ($units == 'mi') {
$variables['shortunit'] = 'mi';
$variables['longunit'] = 'mile(s)';
}
$variables['distance'] = (double) $variables['distance'];
}
function template_preprocess_locations(&$variables) {
if (isset($variables['locations']) && is_array($variables['locations'])) {
$locs = $variables['locations'];
}
else {
$locs = array();
}
$variables['locations'] = array();
$variables['rawlocs'] = $locs;
foreach ($locs as $location) {
$variables['locations'][] = theme('location', $location, $variables['hide']);
}
}
function location_settings($old = FALSE) {
if (empty($old)) {
$old = array();
}
$form = array(
'#type' => 'fieldset',
'#title' => t('Locative information'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#tree' => TRUE,
);
$form['multiple'] = array(
'#type' => 'fieldset',
'#title' => t('Number of locations'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
'#weight' => 2,
);
$form['multiple']['min'] = array(
'#type' => 'select',
'#title' => t('Minimum number of locations'),
'#options' => drupal_map_assoc(range(0, 100)),
'#default_value' => isset($old['multiple']['min']) ? $old['multiple']['min'] : 0,
'#description' => t('The number of locations that are required to be filled in.'),
);
$form['multiple']['max'] = array(
'#type' => 'select',
'#title' => t('Maximum number of locations'),
'#options' => drupal_map_assoc(range(0, 100)),
'#default_value' => isset($old['multiple']['max']) ? $old['multiple']['max'] : 1,
'#description' => t('The maximum number of locations that can be associated.'),
);
$form['multiple']['add'] = array(
'#type' => 'select',
'#title' => t('Number of locations that can be added at once'),
'#options' => drupal_map_assoc(range(0, 100)),
'#default_value' => isset($old['multiple']['add']) ? $old['multiple']['add'] : 1,
'#description' => t('The number of empty location forms to show when editing.'),
);
$form['form'] = array(
'#type' => 'fieldset',
'#title' => t('Collection settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
'#weight' => 4,
);
$form['form']['weight'] = array(
'#type' => 'weight',
'#title' => t('Location form weight'),
'#default_value' => isset($old['form']['weight']) ? $old['form']['weight'] : 0,
'#description' => t('Weight of the location box in the add / edit form. Lower values will be displayed higher in the form.'),
);
$form['form']['collapsible'] = array(
'#type' => 'checkbox',
'#title' => t('Collapsible'),
'#default_value' => isset($old['form']['collapsible']) ? $old['form']['collapsible'] : TRUE,
'#description' => t('Make the location box collapsible.'),
);
$form['form']['collapsed'] = array(
'#type' => 'checkbox',
'#title' => t('Collapsed'),
'#default_value' => isset($old['form']['collapsed']) ? $old['form']['collapsed'] : TRUE,
'#description' => t('Display the location box collapsed.'),
);
$form['form']['fields'] = array(
'#type' => 'location_settings',
'#default_value' => isset($old['form']['fields']) ? $old['form']['fields'] : array(),
);
$form['display'] = array(
'#type' => 'fieldset',
'#title' => t('Display Settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
'#weight' => 6,
);
$form['display']['weight'] = array(
'#type' => 'weight',
'#title' => t('Display Weight'),
'#default_value' => isset($old['display']['weight']) ? $old['display']['weight'] : 0,
);
$fields = location_field_names(TRUE);
$form['display']['hide'] = array(
'#type' => 'checkboxes',
'#title' => t('Hide fields from display'),
'#collapsed' => TRUE,
'#default_value' => isset($old['display']['hide']) ? $old['display']['hide'] : array(),
'#options' => $fields,
);
return $form;
}
function location_form($settings, $locations) {
if (!isset($settings['multiple']['max']) || $settings['multiple']['max'] == 0) {
return array();
}
$numloc = count($locations);
$numforms = min($numloc + $settings['multiple']['add'], $settings['multiple']['max']);
$form = array(
'#type' => 'fieldset',
'#title' => format_plural($numforms, 'Location', 'Locations'),
'#tree' => TRUE,
'#attributes' => array(
'class' => 'locations',
),
'#weight' => $settings['form']['weight'],
'#collapsible' => $settings['form']['collapsible'],
'#collapsed' => $settings['form']['collapsed'],
);
if ($settings['multiple']['max'] == 1) {
$form['#type'] = 'markup';
}
for ($i = 0; $i < $numforms; $i++) {
$required = FALSE;
if ($i < $settings['multiple']['min']) {
$required = TRUE;
}
$form[$i] = array(
'#type' => 'location_element',
'#title' => t('Location #%number', array(
'%number' => $i + 1,
)),
'#default_value' => isset($locations[$i]) ? $locations[$i] : NULL,
'#location_settings' => $settings,
'#required' => $required,
);
}
if ($numforms == 1) {
$form[0]['#title'] = t('Location');
$form[0]['#collapsible'] = $form['#collapsible'];
$form[0]['#collapsed'] = $form['#collapsed'];
}
return $form;
}
function location_display($settings, $locations) {
if (!isset($settings['display']['hide'])) {
return array();
}
$hide = array_keys(array_filter($settings['display']['hide']));
return array(
'#type' => 'markup',
'#value' => theme('locations', $locations, $hide),
'#weight' => $settings['display']['weight'],
);
}
function location_rss_item($location, $mode = 'simple') {
require_once drupal_get_path('module', 'location') . '/location.georss.inc';
return _location_rss_item($location, $mode);
}
function location_google_geocode_accuracy_codes() {
return array(
0 => t('Unknown location'),
1 => t('Country level accuracy'),
2 => t('Region (state, province, prefecture, etc.) level accuracy'),
3 => t('Sub-region (county, municipality, etc.) level accuracy'),
4 => t('Town (city, village) level accuracy'),
5 => t('Post code (zip code) level accuracy'),
6 => t('Street level accuracy'),
7 => t('Intersection level accuracy'),
8 => t('Address level accuracy'),
9 => t('Premise (building name, property name, shopping center, etc.) level accuracy'),
);
}