location_cck.module in Location 6.3
Same filename and directory in other branches
Defines location field type.
File
contrib/location_cck/location_cck.moduleView source
<?php
/**
* @file
* Defines location field type.
*/
/**
* Implementation of hook_theme().
*/
function location_cck_theme() {
return array(
'location_cck_formatter_default' => array(
'arguments' => array(
'element' => NULL,
),
),
'location_cck_formatter_all' => array(
'arguments' => array(
'element' => NULL,
),
),
'location_cck_formatter_map' => array(
'arguments' => array(
'element' => NULL,
),
),
'location_cck_formatter_multiple' => array(
'arguments' => array(
'element' => NULL,
),
),
'location_cck_formatter_multiple_all' => array(
'arguments' => array(
'element' => NULL,
),
),
'location_cck_field_map' => array(
'arguments' => array(
'locations' => NULL,
'field' => NULL,
),
),
'location_cck_field_popup' => array(
'arguments' => array(
'location' => NULL,
'field' => NULL,
),
),
);
}
/**
* Implementation of hook_field_info().
*/
function location_cck_field_info() {
return array(
'location' => array(
'label' => t('Location'),
'description' => t('Store a location.module location.'),
),
);
}
/**
* Implementation of hook_field_settings().
*/
function location_cck_field_settings($op, $field) {
switch ($op) {
case 'form':
$form = array();
$settings = isset($field['location_settings']) ? $field['location_settings'] : FALSE;
$form['location_settings'] = location_settings($settings);
// Multiple is handled by CCK.
unset($form['location_settings']['multiple']);
// CCK handles weight, and collapsibility is not changeable.
unset($form['location_settings']['form']['weight']);
unset($form['location_settings']['form']['collapsible']);
unset($form['location_settings']['form']['collapsed']);
unset($form['location_settings']['display']['weight']);
// We want to see the settings, so uncollapse them.
$form['location_settings']['#collapsible'] = FALSE;
$form['location_settings']['form']['#collapsed'] = FALSE;
$form['location_settings']['display']['#collapsed'] = FALSE;
// Add some GMap settings, if GMap is enabled.
if (module_exists('gmap')) {
$form['gmap_macro'] = array(
'#type' => 'textarea',
'#title' => t('GMap Macro'),
'#rows' => 2,
'#maxlength' => 500,
'#description' => t('A macro to be used as a base map for this field. This map will be recentered on the location, so the center is not that important.'),
'#default_value' => !empty($field['gmap_macro']) ? $field['gmap_macro'] : '[gmap ]',
);
$options = gmap_get_marker_titles();
$form['gmap_marker'] = array(
'#type' => 'select',
'#title' => t('GMap marker'),
'#options' => $options,
'#default_value' => !empty($field['gmap_marker']) ? $field['gmap_marker'] : 'drupal',
);
}
else {
// Preserve existing data, apply defaults even if gmap is disabled.
$form['gmap_macro'] = array(
'#type' => 'value',
'#value' => !empty($field['gmap_macro']) ? $field['gmap_macro'] : '[gmap ]',
);
$form['gmap_marker'] = array(
'#type' => 'value',
'#value' => !empty($field['gmap_marker']) ? $field['gmap_marker'] : 'drupal',
);
}
return $form;
case 'save':
return array(
'location_settings',
'gmap_macro',
'gmap_marker',
);
case 'database columns':
return array(
'lid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
),
);
case 'views data':
// We want to for the most part use the CCK stuff, but we also want to
// patch in a relationship so location's views support can target
// cck fields directly.
$table = content_views_tablename($field);
$db_info = content_database_info($field);
$field_alias = $db_info['columns']['lid']['column'];
$data = content_views_field_views_data($field);
$data[$table][$field_alias]['relationship'] = array(
'base' => 'location',
'field' => $field_alias,
'handler' => 'views_handler_relationship',
'label' => t('Location'),
);
return $data;
}
}
/**
* Implementation of hook_field().
*/
function location_cck_field($op, &$node, $field, &$items, $teaser, $page) {
switch ($op) {
case 'insert':
case 'update':
// Store instances of locations by field name and vid.
$criteria = array(
'genid' => 'cck:' . $field['field_name'] . ':' . $node->vid,
'vid' => $node->vid,
'nid' => $node->nid,
);
location_save_locations($items, $criteria);
// CCK automatically picks up the new lids and stores them in its own tables.
break;
case 'load':
$locations = array();
// Locations are being cached by CCK now. Load the full location.
foreach ($items as $item) {
$locations[] = location_load_location($item['lid']);
}
return array(
$field['field_name'] => $locations,
);
case 'sanitize':
// Get the location information for the lid if it hasn't already been
// loaded (in the hook_field() load $op using location_load_location()).
// This is necessary for Views and any other modules that use the
// content_format() function to render CCK fields because content_format()
// doesn't call the "load" $op.
foreach ($items as $delta => $item) {
if (!isset($item['latitude'])) {
$items[$delta] = array_merge(location_load_location($item['lid']), $items[$delta]);
}
}
break;
case 'delete':
// Use the CCK storage to figure out the vids that need to be deleted,
// and clean up all the applicable references.
$db_info = content_database_info($field);
$result = db_query('SELECT vid FROM {' . $db_info['table'] . '} WHERE nid = %d', $node->nid);
while ($row = db_fetch_object($result)) {
$genid = 'cck:' . $field['field_name'] . ':' . $row->vid;
$locs = array();
location_save_locations($locs, array(
'genid' => $genid,
));
}
break;
case 'delete revision':
$genid = 'cck:' . $field['field_name'] . ':' . $node->vid;
$locs = array();
location_save_locations($locs, array(
'genid' => $genid,
));
break;
}
}
/**
* Implementation of hook_field_formatter_info().
*/
function location_cck_field_formatter_info() {
$info = array(
'default' => array(
'label' => t('Default (address)'),
'field types' => array(
'location',
),
),
);
if (module_exists('gmap')) {
$info['all'] = array(
'label' => t('Address with map'),
'field types' => array(
'location',
),
);
$info['map'] = array(
'label' => t('Map only'),
'field types' => array(
'location',
),
);
$info['multiple'] = array(
'label' => t('Multiple field values on a single map'),
'field types' => array(
'location',
),
'multiple values' => CONTENT_HANDLE_MODULE,
);
$info['multiple_all'] = array(
'label' => t('Addresses with multiple field values on a single map'),
'field types' => array(
'location',
),
'multiple values' => CONTENT_HANDLE_MODULE,
);
}
return $info;
}
/**
* Implementation of hook_widget_info().
*/
function location_cck_widget_info() {
return array(
'location' => array(
'label' => t('Location Field'),
'field types' => array(
'location',
),
// Location will set its own custom values.
'callbacks' => array(),
),
);
}
/**
* Implementation of hook_widget().
*/
function location_cck_widget(&$form, &$form_state, $field, $items, $delta = 0) {
if ($field['widget']['type'] == 'location') {
$settings = $field['location_settings'];
// Load location data for existing locations.
if (isset($items[$delta]['lid']) && $items[$delta]['lid']) {
// Are we in a node preview?
// If we aren't, then we only have the lid, because that's all cck
// actually knows about internally. So, we have to pull in the location
// at this point.
if (empty($items[$delta]['cck_preview_in_progress'])) {
$location = location_load_location($items[$delta]['lid']);
}
else {
// Otherwise, the data was already populated and we're running
// off the form state.
$location = $items[$delta];
}
}
else {
if (isset($items[$delta]) && is_array($items[$delta]) && !empty($items[$delta])) {
// Initialize empty location.
$location = location_empty_location($settings);
foreach ($items[$delta] as $k => $v) {
$location[$k] = $v;
}
// We can't trust that CCK is giving us the right information.
// It can't tell us whether $items is defaults or multistep values.
// Location *needs* the defaults to match the initial field values,
// so we re-calculate the defaults here and stash them into the settings.
// @@@ There is still a bug here!
// If you go back and edit something, and you hadn't set a location the
// first time, CCK fails to set up the defaults properly!
// I'm just going to leave it like that for now, because I don't know how
// to work around it.
$temp = content_default_value($form, $form_state, $field, 0);
if (is_array($temp) && isset($temp[$delta]) && is_array($temp[$delta])) {
foreach ($temp[$delta] as $k => $v) {
$settings['form']['fields'][$k]['default'] = $v;
}
}
// unset($location['location_settings']);
// unset($location['locpick']);
}
}
$element = array(
'#type' => 'location_element',
'#title' => t($field['widget']['label']),
'#description' => t($field['widget']['description']),
'#required' => $field['required'],
'#location_settings' => $settings,
'#default_value' => $location,
);
// This is used to determine whether we are in a preview or not, because
// several pieces of code work differently when previewing.
$element['cck_preview_in_progress'] = array(
'#type' => 'value',
'#value' => TRUE,
);
return $element;
}
}
/**
* CCK Emptiness check.
*/
function location_cck_content_is_empty($item, $field) {
$fields = array();
if (location_is_empty($item, $fields)) {
return TRUE;
}
return FALSE;
}
/**
* Return an address for an individual item.
*/
function theme_location_cck_formatter_default($element) {
$field = content_fields($element['#field_name'], $element['#type_name']);
$hide = isset($field['location_settings']['display']['hide']) ? array_keys(array_filter($field['location_settings']['display']['hide'])) : array();
$location = $element['#item'];
if (!empty($location['cck_preview_in_progress'])) {
// Our canary field is in place, we are in a node preview.
$fields = array();
// If the location isn't "empty", then theme it based on the current state
// of the item.
if (!location_is_empty($location, $fields)) {
return theme('location', $location, $hide);
}
}
else {
if (isset($location['lid']) && $location['lid']) {
// "normal" viewing.
// Location is already cached by CCK, so no need to load it.
return theme('location', $location, $hide);
}
}
}
/**
* Return both an address and a map for an individual item.
*/
function theme_location_cck_formatter_all($element) {
$content = '';
$field = content_fields($element['#field_name'], $element['#type_name']);
$hide = isset($field['location_settings']['display']['hide']) ? array_keys(array_filter($field['location_settings']['display']['hide'])) : array();
$location = $element['#item'];
if (!empty($location['cck_preview_in_progress'])) {
// Our canary field is in place, we are in a node preview.
$fields = array();
// If the location isn't "empty", then theme it based on the current state
// of the item.
if (!location_is_empty($location, $fields)) {
$content = theme('location', $location, $hide);
}
}
else {
if (isset($location['lid']) && $location['lid']) {
// "normal" viewing.
// Location is already cached by CCK, so no need to load it.
$content = theme('location', $location, $hide);
}
}
$content .= theme_location_cck_field_map(array(
$location,
), $field);
return $content;
}
/**
* Returns a map for an individual field value.
*/
function theme_location_cck_formatter_map($element) {
$field = content_fields($element['#field_name'], $element['#type_name']);
$location = $element['#item'];
return theme_location_cck_field_map(array(
$location,
), $field);
}
/**
* Alternate function to return a map with all
* multiple values in the same map.
*/
function theme_location_cck_formatter_multiple($element) {
$field = content_fields($element['#field_name'], $element['#type_name']);
$locations = array();
foreach (element_children($element) as $key) {
$locations[$key] = $element[$key]['#item'];
}
return theme_location_cck_field_map($locations, $field);
}
/**
* Return both a addresses and a single map with all location items.
*/
function theme_location_cck_formatter_multiple_all($element) {
$content = '';
$field = content_fields($element['#field_name'], $element['#type_name']);
$hide = isset($field['location_settings']['display']['hide']) ? array_keys(array_filter($field['location_settings']['display']['hide'])) : array();
$locations = array();
foreach (element_children($element) as $key) {
$location = $element[$key]['#item'];
$locations[$key] = $location;
if (!empty($location['cck_preview_in_progress'])) {
// Our canary field is in place, we are in a node preview.
$fields = array();
// If the location isn't "empty", then theme it based on the current state
// of the item.
if (!location_is_empty($location, $fields)) {
$content .= theme('location', $location, $hide);
}
}
else {
if (isset($location['lid']) && $location['lid']) {
// "normal" viewing.
// Location is already cached by CCK, so no need to load it.
$content .= theme('location', $location, $hide);
}
}
}
$content .= theme_location_cck_field_map($locations, $field);
return $content;
}
/**
* Generate a GMap map for one or more location field values.
*
* Mostly just cut and paste from gmap_location
* block view.
*/
function theme_location_cck_field_map($locations, $field) {
$count = 0;
$content = '';
foreach ($locations as $location) {
if (location_has_coordinates($location)) {
$count++;
$markername = isset($field['gmap_marker']) ? $field['gmap_marker'] : 'drupal';
$markers[] = array(
'latitude' => $location['latitude'],
'longitude' => $location['longitude'],
'markername' => $markername,
'offset' => $count - 1,
'text' => theme('location_cck_field_popup', $location, $field),
);
}
}
if (!empty($markers)) {
$macro = !empty($field['gmap_macro']) ? $field['gmap_macro'] : '[gmap ]';
$map = gmap_parse_macro($macro);
$map['latitude'] = $markers[0]['latitude'];
$map['longitude'] = $markers[0]['longitude'];
$map['markers'] = $markers;
$map['id'] = gmap_get_auto_mapid();
$content = theme('gmap', array(
'#settings' => $map,
));
}
return $content;
}
/**
* Theme the GMap popup text for the field.
*/
function theme_location_cck_field_popup($location, $field) {
$hide = isset($field['location_settings']['display']['hide']) ? array_keys(array_filter($field['location_settings']['display']['hide'])) : array();
// Don't use a map link in a popup!
// We're making the name into a title.
$hide[] = 'map_link';
$hide[] = 'name';
$markertitle = $field['widget']['label'];
if (!empty($location['name'])) {
$markertitle = $location['name'];
}
return '<h4>' . $markertitle . '</h4>' . theme('location', $location, $hide);
}
/**
* Implementation of hook_token_list().
*/
function location_cck_token_list($type = 'all') {
if ($type == 'field') {
$tokens = array();
$fields = location_field_names(TRUE);
// @@@ We really need to rethink fields in location..
unset($fields['locpick']);
foreach ($fields as $k => $v) {
$tokens['location'][$k] = $v;
}
return $tokens;
}
}
/**
* Implementation of hook_token_values().
*/
function location_cck_token_values($type, $object = NULL) {
if ($type == 'field') {
$tokens = array();
$item = $object[0];
if ($item['lid']) {
// If the location exists, we need to set up the tokens.
$location = array(
// There is no way to find out which elements to hide because $item does not contain
// the 'location_settings' element, so for now, just set it to be an empty array.
// See http://drupal.org/node/463618 for more infomation.
'hide' => array(),
'location' => location_load_location($item['lid']),
);
// @@@ This is rather silly, but I can't think of anything better at the moment.
template_preprocess_location($location);
$fields = location_field_names(TRUE);
// @@@ We really need to rethink fields in location..
unset($fields['locpick']);
foreach ($fields as $k => $v) {
if (isset($location[$k])) {
$tokens[$k] = $location[$k];
}
else {
$tokens[$k] = '';
}
}
}
return $tokens;
}
}
/**
* Implementation of hook_locationapi().
*/
function location_cck_locationapi(&$obj, $op, $a3 = NULL, $a4 = NULL, $a5 = NULL) {
switch ($op) {
case 'instance_links':
foreach ($obj as $k => $v) {
if (substr($v['genid'], 0, 4) == 'cck:') {
$data = explode(':', $v['genid']);
$obj[$k]['href'] = 'node/' . $data[2];
$obj[$k]['title'] = t('CCK location');
$obj[$k]['type'] = t('CCK location');
}
}
}
}
Functions
Name | Description |
---|---|
location_cck_content_is_empty | CCK Emptiness check. |
location_cck_field | Implementation of hook_field(). |
location_cck_field_formatter_info | Implementation of hook_field_formatter_info(). |
location_cck_field_info | Implementation of hook_field_info(). |
location_cck_field_settings | Implementation of hook_field_settings(). |
location_cck_locationapi | Implementation of hook_locationapi(). |
location_cck_theme | Implementation of hook_theme(). |
location_cck_token_list | Implementation of hook_token_list(). |
location_cck_token_values | Implementation of hook_token_values(). |
location_cck_widget | Implementation of hook_widget(). |
location_cck_widget_info | Implementation of hook_widget_info(). |
theme_location_cck_field_map | Generate a GMap map for one or more location field values. |
theme_location_cck_field_popup | Theme the GMap popup text for the field. |
theme_location_cck_formatter_all | Return both an address and a map for an individual item. |
theme_location_cck_formatter_default | Return an address for an individual item. |
theme_location_cck_formatter_map | Returns a map for an individual field value. |
theme_location_cck_formatter_multiple | Alternate function to return a map with all multiple values in the same map. |
theme_location_cck_formatter_multiple_all | Return both a addresses and a single map with all location items. |