/[drupal]/contributions/modules/gmap_addons/gmap_cck.module
ViewVC logotype

Contents of /contributions/modules/gmap_addons/gmap_cck.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations) (download) (as text)
Tue Oct 14 16:53:26 2008 UTC (13 months, 2 weeks ago) by bdragon
Branch: MAIN
CVS Tags: DRUPAL-6--1-0, HEAD
Changes since 1.2: +7 -8 lines
File MIME type: text/x-php
(sync gmap_cck with D5) Fix brokenness when creating a cck field.
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * display of a google map as cck field
7 */
8
9 /**
10 * @addtogroup hooks
11 * @{
12 */
13
14
15 /**
16 * Declare information about a field type.
17 *
18 * @return
19 * An array keyed by field type name. Each element of the array is an associative
20 * array with these keys and values:
21 * - "label": The human-readable label for the field type.
22 */
23 function gmap_cck_field_info() {
24 return array(
25 'gmap_cck' => array('label' => 'Google map view'),
26 );
27 }
28
29 /**
30 * Handle the parameters for a field.
31 *
32 * @param $op
33 * The operation to be performed. Possible values:
34 * - "form": Display the field settings form.
35 * - "validate": Check the field settings form for errors.
36 * - "save": Declare which fields to save back to the database.
37 * - "database columns": Declare the columns that content.module should create
38 * and manage on behalf of the field. If the field module wishes to handle
39 * its own database storage, this should be omitted.
40 * - "callbacks": Describe the field's behaviour regarding hook_field operations.
41 * - "tables" : Declare the Views tables informations for the field.
42 * Use this operator only if you need to override CCK's default general-purpose
43 * implementation.
44 * In this case, it is probably a good idea to use the default definitions
45 * returned by content_views_field_tables($field) as a start point for your own
46 * definitions.
47 * - "arguments" : Declare the Views arguments informations for the field.
48 * Use this operator only if you need to override CCK's default general-purpose
49 * implementation.
50 * In this case, it is probably a good idea to use the default definitions
51 * returned by content_views_field_arguments($field) as a start point for your own
52 * definitions.
53 * - "filters": Declare the Views filters available for the field.
54 * (this is used in CCK's default Views tables definition)
55 * They always apply to the first column listed in the "database columns"
56 * array.
57 * @param $field
58 * The field on which the operation is to be performed.
59 * @return
60 * This varies depending on the operation.
61 * - "form": an array of form elements to add to
62 * the settings page.
63 * - "validate": no return value. Use form_set_error().
64 * - "save": an array of names of form elements to
65 * be saved in the database.
66 * - "database columns": an array keyed by column name, with arrays of column
67 * information as values. This column information must include "type", the
68 * MySQL data type of the column, and may also include a "sortable" parameter
69 * to indicate to views.module that the column contains ordered information.
70 * Details of other information that can be passed to the database layer can
71 * be found at content_db_add_column().
72 * - "callbacks": an array describing the field's behaviour regarding hook_field
73 * operations. The array is keyed by hook_field operations ('view', 'validate'...)
74 * and has the following possible values :
75 * CONTENT_CALLBACK_NONE : do nothing for this operation
76 * CONTENT_CALLBACK_CUSTOM : use the behaviour in hook_field(operation)
77 * CONTENT_CALLBACK_DEFAULT : use content.module's default bahaviour
78 * Note : currently only the 'view' operation implements this feature.
79 * All other field operation implemented by the module _will_ be executed
80 * no matter what.
81 * - "tables": an array of 'tables' definitions as expected by views.module
82 * (see Views Documentation).
83 * - "arguments": an array of 'arguments' definitions as expected by views.module
84 * (see Views Documentation).
85 * - "filters": an array of 'filters' definitions as expected by views.module
86 * (see Views Documentation).
87 * When providing several filters, it is recommended to use the 'name'
88 * attribute in order to let the user distinguish between them. If no 'name'
89 * is specified for a filter, the key of the filter will be used instead.
90 */
91 function gmap_cck_field_settings($op, $field) {
92 switch ($op) {
93 case 'form':
94 $def = gmap_defaults();
95 foreach (array('maptype', 'controltype', 'width', 'height', 'latlong') as $key) {
96 if (isset($field[$key]) && !empty($field[$key])) {
97 $def[$key] = $field[$key];
98 }
99 }
100
101 $form = gmap_macro_builder_form($def);
102 $form['#title'] = t('Google Map settings');
103 // keep: mapdiv
104 unset($form['macroform']['overlayedit']);
105 unset($form['macroform']['mapid']);
106 // keep: maptype, controltype
107 unset($form['macroform']['address']);
108 //unset($form['macroform']['latlong']);
109 // keep: width, height, alignment, zoom
110 unset($form['macroform']['macro']);
111
112 // GPX file support
113 $gpx_opts = array(t('Disabled'));
114 if (module_exists('filefield')) $gpx_opts['filefield'] = t('CCK Filefield');
115 // TODO: attachment to node, uploaded file, url from user, ...
116
117 if (count($gpx_opts) > 1) {
118 $form['gpx'] = array(
119 '#type' => 'select',
120 '#title' => t("GPX File support"),
121 '#options' => array(
122 0 => t('Disabled'),
123 'filefield' => t('CCK Filefield'),
124 ),
125 '#default_value' => $field['gpx'],
126 );
127
128 // if gpx-support is enabled we need a source for the data
129 $form['gpx_src'] = array(
130 '#type' => 'textfield',
131 '#title' => t('GPX data source parameter'),
132 '#description' => t('Only used if gpx-support is enabled'),
133 '#default_value' => $field['gpx_src'],
134 );
135 }
136
137 // noderef field(s) to nodes with locations for markers
138 if (module_exists('nodereference')) {
139 $form['marker_noderef'] = array(
140 '#type' => 'textfield',
141 '#title' => t('Marker noderef'),
142 '#description' => t('Name of noderef field to nodes to show as markers'),
143 '#default_value' => $field['marker_noderef']
144 );
145 }
146
147 return $form;
148
149 case 'validate': // check stuff entered in form-fields
150 break;
151
152 case 'save':
153 return array('maptype', 'controltype', 'width', 'height', 'alignment',
154 'zoom', 'latlong', 'gpx', 'gpx_src', 'marker_noderef');
155
156 case 'database columns':
157 $columns = array( // TODO: ??? type -> longtext ???
158 'value' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'default' => "''", 'sortable' => false),
159 );
160 return $columns;
161
162 case 'callbacks': // CHECK: ??? any effect on calling ..._field() ???
163 return array(
164 'view' => CONTENT_CALLBACK_CUSTOM,
165 );
166 }
167 }
168
169 /**
170 * Define the behavior of a field type.
171 *
172 * @param $op
173 * What kind of action is being performed. Possible values:
174 * - "load": The node is about to be loaded from the database. This hook
175 * should be used to load the field.
176 * - "view": The node is about to be presented to the user. The module
177 * should prepare and return an HTML string containing a default
178 * representation of the field.
179 * It will be called only if 'view' was set to TRUE in hook_field_settings('callbacks')
180 * - "validate": The user has just finished editing the node and is
181 * trying to preview or submit it. This hook can be used to check or
182 * even modify the node. Errors should be set with form_set_error().
183 * - "submit": The user has just finished editing the node and the node has
184 * passed validation. This hook can be used to modify the node.
185 * - "insert": The node is being created (inserted in the database).
186 * - "update": The node is being updated.
187 * - "delete": The node is being deleted.
188 * @param &$node
189 * The node the action is being performed on. This argument is passed by
190 * reference for performance only; do not modify it.
191 * @param $field
192 * The field the action is being performed on.
193 * @param &$items
194 * The contents of the field in this node. Changes to this variable will
195 * be saved back to the node object.
196 * @return
197 * This varies depending on the operation.
198 * - The "load" operation should return an object containing extra values
199 * to be merged into the node object.
200 * - The "view" operation should return a string containing an HTML
201 * representation of the field data.
202 * - The "insert", "update", "delete", "validate", and "submit" operations
203 * have no return value.
204 *
205 * In most cases, only "validate" operations is relevant ; the rest
206 * have default implementations in content_field() that usually suffice.
207 */
208 function gmap_cck_field($op, &$node, $field, &$items, $teaser, $page) {
209 switch ($op) {
210 case 'view':
211 $context = $teaser ? 'teaser' : 'full';
212 $formatter = isset($field['display_settings'][$context]['format'])
213 ? $field['display_settings'][$context]['format'] : 'default';
214 foreach ($items as $delta => $item) {
215 $items[$delta]['view'] = content_format($field, $item, $formatter, $node);
216 }
217 return theme('field', $node, $field, $items, $teaser, $page);
218 }
219 }
220
221 /**
222 * Declare information about a formatter.
223 *
224 * @return
225 * An array keyed by formatter name. Each element of the array is an associative
226 * array with these keys and values:
227 * - "label": The human-readable label for the formatter.
228 * - "field types": An array of field type names that can be displayed using
229 * this formatter.
230 */
231 function gmap_cck_field_formatter_info() {
232 return array(
233 'default' => array(
234 'label' => t('Default map'),
235 'field types' => array('gmap_cck'),
236 ),
237 // TODO: add list of configurable small map-displays
238 );
239 }
240
241 /**
242 * Prepare an individual item for viewing in a browser.
243 *
244 * @param $field
245 * The field the action is being performed on.
246 * @param $item
247 * An array, keyed by column, of the data stored for this item in this field.
248 * @param $formatter
249 * The name of the formatter being used to display the field.
250 * @param $node
251 * The node object, for context. Will be NULL in some cases.
252 * Warning : when displaying field retrieved by Views, $node will not
253 * be a "full-fledged" node object, but an object containg the data returned
254 * by the Views query (at least nid, vid, changed)
255 * @return
256 * An HTML string containing the formatted item.
257 *
258 * In a multiple-value field scenario, this function will be called once per
259 * value currently stored in the field. This function is also used as the handler
260 * for viewing a field in a views.module tabular listing.
261 *
262 * It is important that this function at the minimum perform security
263 * transformations such as running check_plain() or check_markup().
264 */
265 function gmap_cck_field_formatter($field, $item, $formatter, $node) {
266 if (!isset($item['value'])) {
267 return '';
268 }
269
270 $m = unserialize($item['value']);
271 if (!is_array($m)) $m = array();
272 if (!empty($field['gpx']) && _gmap_cck_check_gpx_source($m, $field, $node)) {
273 _gmap_cck_get_gpx($m, $field, $node);
274 }
275 if (!empty($field['marker_noderef'])) {
276 _gmap_cck_noderef_markers($m, $field, $node);
277 }
278 $map = array_merge(gmap_defaults(), $field, $m);
279
280 $map['id'] = 'gmap';
281 if (isset($node) && isset($node->nid)) $map['id'] .= '_'. $node->nid;
282 $map['id'] .= '_'. $field['field_name'];
283
284 // TODO: correct width, height & zoom if ($formatter != 'default')
285
286 return theme('gmap', array('#settings' => $map));
287 }
288
289
290 /**
291 * Declare information about a widget.
292 *
293 * @return
294 * An array keyed by widget name. Each element of the array is an associative
295 * array with these keys and values:
296 * - "label": The human-readable label for the widget.
297 * - "field types": An array of field type names that can be edited using
298 * this widget.
299 */
300 function gmap_cck_widget_info() {
301 return array(
302 'gmap_cck' => array(
303 'label' => 'Google Map',
304 'field types' => array('gmap_cck'),
305 ),
306 );
307 }
308
309 /**
310 * Handle the parameters for a widget.
311 *
312 * @param $op
313 * The operation to be performed. Possible values:
314 * - "form": Display the widget settings form.
315 * - "validate": Check the widget settings form for errors.
316 * - "save": Declare which pieces of information to save back to the database.
317 * - "callbacks": Describe the widget's behaviour regarding hook_widget operations.
318 * @param $widget
319 * The widget on which the operation is to be performed.
320 * @return
321 * This varies depending on the operation.
322 * - "form": an array of form elements to add to the settings page.
323 * - "validate": no return value. Use form_set_error().
324 * - "save": an array of names of form elements to be saved in the database.
325 * - "callbacks": an array describing the widget's behaviour regarding hook_widget
326 * operations. The array is keyed by hook_widget operations ('form', 'validate'...)
327 * and has the following possible values :
328 * CONTENT_CALLBACK_NONE : do nothing for this operation
329 * CONTENT_CALLBACK_CUSTOM : use the behaviour in hook_widget(operation)
330 * CONTENT_CALLBACK_DEFAULT : use content.module's default bahaviour
331 * Note : currently only the 'default value' operation implements this feature.
332 * All other widget operation implemented by the module _will_ be executed
333 * no matter what.
334 */
335 function gmap_cck_widget_settings($op, $widget) {
336 switch ($op) {
337
338 case 'callbacks': // CHECK: do we need this ???
339 return array(
340 'default value' => CONTENT_CALLBACK_CUSTOM,
341 );
342 }
343 }
344
345 /**
346 * Define the behavior of a widget.
347 *
348 * @param $op
349 * What kind of action is being performed. Possible values:
350 * - "prepare form values": The editing form will be displayed. The widget
351 * should perform any conversion necessary from the field's native storage
352 * format into the storage used for the form. Convention dictates that the
353 * widget's version of the data should be stored beginning with "default".
354 * - "form": The node is being edited, and a form should be prepared for
355 * display to the user.
356 * - "validate": The user has just finished editing the node and is
357 * trying to preview or submit it. This hook can be used to check or
358 * even modify the node. Errors should be set with form_set_error().
359 * - "process form values": The inverse of the prepare operation. The widget
360 * should convert the data back to the field's native format.
361 * - "submit": The user has just finished editing the node and the node has
362 * passed validation. This hook can be used to modify the node.
363 * @param &$node
364 * The node the action is being performed on. This argument is passed by
365 * reference for performance only; do not modify it.
366 * @param $field
367 * The field the action is being performed on.
368 * @param &$items
369 * The contents of the field in this node. Changes to this variable will
370 * be saved back to the node object.
371 * @return
372 * This varies depending on the operation.
373 * - The "form" operation should return an array of form elements to display.
374 * - Other operations have no return value.
375 */
376 function gmap_cck_widget($op, &$node, $field, &$items) {
377
378 switch ($op) {
379
380 case 'prepare form values':
381 // db-value (serialized array) is in $items[0]['value'];
382 $items[0]['raw'] = unserialize($items[0]['value']);
383 // show some gpx-data?
384 if (!empty($field['gpx'])) {
385 _gmap_cck_check_gpx_source($items[0]['raw'], $field, $node);
386 }
387 // if ($field['multiple']) { ??? }
388 break;
389
390 case 'form':
391 $rd =& $items[0]['raw']; // raw data
392 if (empty($rd)) $rd = array();
393
394 $ndefs = array(
395 'maptype' => $field['maptype'],
396 'width' => $field['width'],
397 'height' => $field['height'],
398 'zoom' => $field['zoom'],
399 'latlong' => $field['latlong'],
400 );
401
402 if (isset($rd['gpx'])) {
403 $gpx_support = array('#value' => 'GPX support enabled');
404 _gmap_cck_get_gpx($rd, $field, $node);
405 }
406 $ndefs = array_merge(gmap_defaults(), $ndefs, $rd);
407 $hide = array('mapid' => 1, // type=hidden
408 'width' => 1, 'height' => 1, 'alignment' => 1, // 'zoom' => 2,
409 'maptype' => 1, 'controltype' => 1, 'macro' => 2,
410 );
411 $form = gmap_macro_builder_form($ndefs, $hide);
412
413 // remove/hide unwanted parts of form
414 $mf =& $form['macroform'];
415 $mf['#title'] = t('Select map view');
416 unset($mf['overlayedit'], $mf['address']);
417
418 foreach ($mf as $key => $val) {
419 if ($key[0] == '#') continue;
420 $mf['#tree'] = true;
421 $mf['#parents'] = array($field['field_name']);
422 }
423
424 $form[$field['field_name']] = $form['macroform'];
425 unset($form['macroform']);
426
427 if (isset($gpx_support)) {
428 $form['gpx_support'] = $gpx_support;
429 }
430
431 return $form;
432
433 case 'process form values':
434 // TODO: if ($field['multiple']) ...
435 // get the values and build serialized array for db-save
436 /* $ms = '[gmap zoom='. $items['zoom'] .'|center='.
437 $items['latlong'] .'|width='. $field['width'] .'|height='.
438 $field['height'] .'|id=gmap_'. $field['field_name'] .'|control='.
439 $field['controltype'] .'|type='. $field['maptype'] .']';
440 */
441 $v = array('zoom' => $items['zoom'], 'latlong' => $items['latlong']);
442 // TODO: add more props like 'markers', gpx-file, ...
443 foreach ($items as $delta => $item) {
444 unset($items[$delta]);
445 }
446
447 // show some gpx-data?
448 if (!empty($field['gpx'])) {
449 _gmap_cck_check_gpx_source($v, $field, $node);
450 }
451
452 $items[0]['value'] = serialize($v);// $ms;
453 break;
454 }
455 }
456
457 /**
458 * @} End of "addtogroup hooks".
459 */
460
461 function _gmap_cck_check_gpx_source(&$data, &$field, &$node) {
462 $r = true;
463 if ($field['gpx'] == 'filefield') {
464 $fname = 'field_'. $field['gpx_src'];
465 $ff =& $node->$fname;
466 $r = (isset($ff) && _gmap_cck_gpxdata_filefield($data, $ff));
467 }
468 if (!$r) {
469 // TODO: ev. try to use $data['gpx']['file']
470 unset($data['gpx']);
471 }
472 return $r;
473 }
474
475 /**
476 * try to always get filedata from filefield, even if we're in preview mode
477 */
478 function _gmap_cck_gpxdata_filefield(&$v, &$filefield) {
479 foreach ($filefield as $i => $data) {
480 if (!isset($data['filepath'])) continue;
481 $v['gpx'] = array(
482 'type' => 'file',
483 'file' => $data['filepath'],
484 );
485 return true;
486 }
487 return false;
488 }
489
490 /**
491 * process gpx-parameter to show something on the map
492 */
493 function _gmap_cck_get_gpx(&$settings, &$field, &$node) {
494 require_once('gmap_gpx.inc');
495 if ($settings['gpx']['type'] == 'file') {
496 $f = $settings['gpx']['file'];
497 if (!file_exists($f)) { // was in temp location last time we looked?
498 if (!isset($field) || !isset($node)) return false;
499 if (!_gmap_cck_check_gpx_source($settings, $field, $node)) return false;
500 $f = $settings['gpx']['file'];
501 }
502 gmap_gpx_parse_file($f);
503 gmap_gpx_data2map($settings);
504 gmap_gpx_cleanup();
505 }
506 unset($settings['gpx']);
507 return true;
508 }
509
510 /**
511 * load locations from nodes pointed at with noderef field, show markers
512 */
513 function _gmap_cck_noderef_markers(&$settings, &$field, &$node) {
514 $fname = 'field_'. $field['marker_noderef'];
515 $nrf =& $node->$fname;
516 $nids = array();
517 foreach ($nrf as $delta => $item) {
518 if (!empty($item['nid']) && is_numeric($item['nid'])) {
519 $nids[] = $item['nid'];
520 $n = node_load($item['nid']);
521 if ($n) {
522 $settings['markers'][] = array(
523 'label' => $n->title,
524 'opts' => array('title' => $n->title),
525 'latitude' => $n->locations[0]['latitude'],
526 'longitude' => $n->locations[0]['longitude'],
527 'markername' => variable_get('gmap_node_marker_'. $n->type, 'drupal'),
528 'text' => theme('gmapnodelabel', $n), // TODO:
529 //'popuplink' => url('map/query/node/'. $n->nid),
530 );
531 }
532 }
533 }
534 /* TODO: go this route if we have too many (how many?) nodes
535 if (count($nids)) {
536 $nidstr = implode(',', $nids);
537 //$res = db_query("SELECT * FROM {location} l , {node_revisions} nr WHERE".
538 // " l.type = 'node' AND l.eid = nr.vid AND nr.nid IN('$nidstr')");
539 $res = db_query("SELECT nr.title, n.nid, n.type, max(nr.vid) vid,".
540 " l.latitude, l.longitude FROM location l, node n, node_revisions nr".
541 " WHERE l.type = 'node' AND l.eid = nr.vid AND n.nid = nr.nid AND".
542 " nr.nid IN($nidstr) GROUP BY n.nid");
543 $locs = array();
544 while ($nl = db_fetch_object($res)) {
545 if (!isset($locs[$nl->nid]) || ($locs[$nl->nid]->timestamp < $nl->timestamp)) {
546 $locs[$nl->nid] = $nl;
547 }
548 }
549 foreach ($locs as $nid => $nl) {
550 $settings['markers'][] = array(
551 'label' => $nl->title,
552 'latitude' => $nl->latitude,
553 'longitude' => $nl->longitude,
554 'markername' => variable_get('gmap_node_marker_'. $nl->type, 'drupal'),
555 //'text' => theme('gmapnodelabel',$nl), // TODO:
556 'popuplink' => url('map/query/node/'. $nl->nid),
557 );
558 }
559 }
560 */
561 }

  ViewVC Help
Powered by ViewVC 1.1.2