/[drupal]/contributions/modules/annotationfield/annotationfield.module
ViewVC logotype

Contents of /contributions/modules/annotationfield/annotationfield.module

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


Revision 1.5 - (show annotations) (download) (as text)
Tue May 27 15:54:48 2008 UTC (18 months ago) by schuyler1d
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +2 -2 lines
File MIME type: text/x-php
fix http://drupal.org/node/259293 warning on install
1 <?php
2 // $Id
3
4 /**
5 * @file
6 * Defines an API for annotation fields which annotate particular field
7 * types on an arbitrary node
8 *
9 * In order to make a single content type able to modify all kinds of types
10 * we have a different annotation module:
11 *
12 * annotation module would provide here
13 * 1. fields nid, vid, fieldname, annotation_type, start, end, morehooks
14 * 2. particular annotation fields may just annotate a subset of
15 * available fieldtypes, widget types,
16 *
17 * Then video annotation just provides:
18 * 1. how to FILL the start/end/morehooks fields
19 * 2. ui widget (maybe even a modify on the three fields on the form)
20 inputs: which fields should/can we annotate?
21 * 3. validate morehooks field
22 * 4. define field type that we annotate
23 * 4.1 response hook that a node/field is annotatable with this widget
24 * 5. provide output version of annotated node (?or just js)
25 * 6. what to display in view-mode
26 * 7. Javascript Functions:
27 * init(contentfield,start,end,morehooks)--shows annotation
28 * prep_edit(contentfield,start-field,end-field,morehooks-field)
29 * 8. what an aggregate view of annotations on a single node should
30 * look like.
31 * Policies:
32 * just one type
33 * wherever 'focus' is?
34 * fieldname per type
35 * fieldtype priority (video,audio,image,text)
36 *
37 * sub-module hooks:
38 * - annotationfield_view
39 * - annotationfield_form
40 * - annotationfield_form_submit
41 * - annotationfield_annotatable_fields
42 * -
43 * -
44 * Any way to leverage reference node cck type?
45 * Well, what if there's more than one on the type, and
46 * even then, we'll probably have to do something significantly
47 * different when displaying the node.
48 *
49 how to annotate:
50 'click annotate'
51 on field
52 benefit of widget knowing what to work on/pay attention
53 a page reload for starting to annotate?
54 on node
55 when does widget get dipatched?
56 annotation framework helps?
57
58
59 So one order:
60 1. annotation module looks at each field
61 and determines which annotator will be used for each field
62 2. load the annotators
63 2.1 annotators load js with a hook to be called when 'annotate' is clicked
64
65 3. -annotate click links created
66 4.
67
68
69 */
70
71
72
73 /**
74 * Implementation of hook_menu().
75 */
76 function annotationfield_menu($may_cache) {
77 /* adds tab-style menu items to annotatable nodes for each
78 * content-type that
79 */
80 $items = array();
81 if (!$may_cache) {
82 if (arg(0) == 'node' && is_numeric(arg(1))) {
83 $node = node_load(arg(1));
84 foreach (annotationfield_annotatable($node) as $annotator_cname => $annotator_ctype) {
85 $items[] = array('path' => 'node/' . arg(1) .'/annotate/'. $annotator_cname,
86 'title' => t('Add @ctype', array('@ctype' => $annotator_ctype['name'])),
87 'callback' => 'annotationfield_node_annotate',
88 'access' => user_access('access content') && user_access('create '. $annotator_cname .' content'),
89 'weight' => 5,
90 'type' => MENU_LOCAL_TASK, // :MENU_CALLBACK
91 );
92 }
93 }
94 }
95 return $items;
96 }
97
98
99
100 /**
101 * Implementation of hook_field_info().
102 */
103 function annotationfield_field_info() {
104 return array(
105 'annotation_field' => array('label' => 'Annotation on a Node Field'),
106 );
107 }
108
109 /**
110 * Implementation of hook_field_settings().
111 */
112 function annotationfield_field_settings($op, $field) {
113 switch ($op) {
114 case 'form':
115 ///additions to the field configuration on a particular type
116 $form['referenceable_types'] = array(
117 '#type' => 'checkboxes',
118 '#title' => t('Content types that can be referenced'),
119 '#multiple' => TRUE,
120 '#default_value' => isset($field['referenceable_types']) ? $field['referenceable_types'] : array(),
121 '#options' => node_get_types('names'),
122 );
123
124 $annotators = module_invoke_all('annotationfield_annotator');
125 $form['annotator_types'] = array(
126 '#type' => 'checkboxes',
127 '#title' => t('Annotator types'),
128 '#multiple' => TRUE,
129 '#default_value' => isset($field['annotator_types']) ? $field['annotator_types'] : array_keys($annotators),
130 '#options' => $annotators,
131 );
132 $form['annotatee_fields'] = array('#tree' => TRUE,
133 '#type' =>'fieldset',
134 '#title'=>'For each content type, which fields',
135 );
136 $ref_types = (isset($field['referenceable_types'])) ?
137 $field['referenceable_types'] : array_keys(node_get_types('names'));
138
139 foreach ($ref_types as $nodetype) {
140 if (!$nodetype) continue;/// when type is not chosen it's set to int(0)
141
142 $node_fields = annotationfield_annotatable_fields($field, $nodetype);
143 $fieldnames = array_values($node_fields['fields']);
144 if (!empty($fieldnames)) {
145 $form['annotatee_fields'][$nodetype] = array(
146 '#collapsible'=>TRUE,
147 '#collapsed'=>TRUE,
148 '#type' => 'checkboxes',
149 '#multiple' => TRUE,
150 '#title' => t('Fields for @nodetype',array('@nodetype' => $nodetype)),
151 '#default_value' => isset($field['annotatee_fields'][$nodetype]) ? $field['annotatee_fields'][$nodetype] : $fieldnames,
152 '#options' => array_combine($fieldnames,$fieldnames),
153 );
154 }
155 }
156
157 return $form;
158 case 'save':
159 ///returns a list of additional options on a field (processed by $op=form)
160 $settings = array('referenceable_types','annotator_types','annotatee_fields');
161 return $settings;
162 case 'database columns':
163 //assume nid, vid (version id), and fieldname
164 $columns = array(
165 'nid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'),
166 'vid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'),
167 /*based off of content_install */
168 'fieldname' => array('type' => 'varchar', 'length' => 32, 'not null' => FALSE, 'default' => NULL),
169 'fielditem' => array('type' => 'int', 'not null' => FALSE, 'default' => '0'),
170 /*call this 'annotator' instead? */
171 'annotator' => array('type' => 'varchar', 'length' => 127, 'not null' => FALSE, 'default' => NULL),
172 /* range1 is either start or x or similar,
173 range2 is end,y,etc
174 morehooks is a json/php object with with any more annotation info
175 */
176 'range1' => array('type' => 'float', 'not null' => FALSE, 'default' => NULL),
177 'range2' => array('type' => 'float', 'not null' => FALSE, 'default' => NULL),
178 'morehooks' => array('type' => 'mediumtext', 'not null' => FALSE, 'default' => NULL),
179 );
180 return $columns;
181
182 case 'filters':
183 ///array for views to filter based on a function here
184 return;
185 }
186 }
187
188 /**
189 * Implementation of hook_field_formatter_info().
190 * - options available for the nodereference field display in
191 * a View
192 */
193 function annotationfield_field_formatter_info() {
194 return array(
195 'default' => array(
196 'label' => 'Annotated Field',
197 'field types' => array('annotation_field'),
198 ),
199 'fragment' => array(
200 'label' => 'Annotated Fragment',
201 'field types' => array('annotation_field'),
202 ),
203 'full' => array(
204 'label' => 'Annotated Node (all fields)',
205 'field types' => array('annotation_field'),
206 ),
207 'noderef_link' => array(
208 'label' => 'Link to annotated node',
209 'field types' => array('annotation_field', 'nodereference'),
210 ),
211 'noderef_nolink' => array(
212 'label' => "Annotated node's title (no link)",
213 'field types' => array('annotation_field', 'nodereference'),
214 ),
215 );
216 }
217
218
219 /**
220 * Implementation of hook_field_formatter().
221 */
222 function annotationfield_field_formatter($field, $item, $formatter, $node) {
223 /* returns text to display when this field is included in a view
224 @param formatter: the key chosen in field_formatter_info
225
226 */
227 $annotatee_node = node_load($item['nid']);
228
229 ///must precede annotator JS
230 drupal_add_js(drupal_get_path('module','annotationfield').'/js/annotator.js');
231 $data = annotationfield_invoke_data('view', $annotatee_node, $field, $item);
232 if ($item['annotator']) {
233 //just allows drupal_add_js(), etc.
234 $discard = module_invoke($item['annotator'], 'annotationfield_view', $item, $annotatee_node);
235 }
236 ///if we haven't specified the fieldname, then we can't just show the field!
237 if (!$item['fieldname'] && $formatter==='default') {
238 $formatter = 'noderef_link';
239 }
240 $html_class_selector = annotationfield_onpage_counter();
241 $annotatee_class = "annotationfield-annotatee-".$html_class_selector;
242
243 switch($formatter) {
244 case 'default':
245 case 'fragment':/*TODO:NOT IMPLEMENTED*/
246 $annotatee_field = annotationfield_annotatee_field_content($annotatee_node, $item['fieldname'], $item['fielditem']);
247 theme('annotationfield_annotatee_js',$html_class_selector, 'view', $annotatee_class, $data, null, $item['annotator']);
248 $rv = theme('annotationfield_annotatee',$annotatee_class, $annotatee_field);
249 break;
250 case 'full':
251 ///cck findable with .field-field-{fieldname}
252 $annotatee_node = node_view($annotatee_node, FALSE, TRUE, FALSE);
253 theme('annotationfield_annotatee_js',$html_class_selector, 'view', $annotatee_class, $data, null, $item['annotator']);
254 $rv = theme('annotationfield_annotatee',$annotatee_class, $annotatee_node);
255 break;
256 case 'noderef_link':
257 $rv = l($annotatee_node->title,'node/'.$annotatee_node->nid);
258 break;
259 }
260
261 return $rv;
262 ///1. include the noderef page
263 ///2. send JS hook to annotator for decoration
264 /// ALT 1: send this to an annotator php method?
265 /// This would mean we have to do 'display' twice, however
266 /// ALT 2: defer to theme() method.
267 }
268
269 /**
270 * Implementation of hook_widget_info().
271 */
272 function annotationfield_widget_info() {
273 /*
274 Options available when configuring the field in content-types
275 */
276 return array(
277 'annotation_field' => array(
278 'label' => 'Annotation on a Node Field',
279 'field types' => array('annotation_field'),
280 ),
281 );
282 }
283
284 /**
285 * Implementation of hook_widget().
286 */
287 function annotationfield_widget($op, &$node, $field, &$items) {
288 switch ($op) {
289 case 'prepare form values':
290 /* What presumptions/help should we have here
291 * - if there's a specific node, then prepare that
292 * also--only include annotators that can help with that node
293 * ^^^^--this might be presumptuous, but we can weaken this
294 * assumption later
295 * - if there's only one annotator/field possible
296 * then *default* to that. (later someone could manually
297 * switch with the UI
298 * - only include annotators that can help with a
299 */
300 //$items_transposed = content_transpose_array_rows_cols($items);
301
302 ///nodereference combines the 'nids' into one field
303 ///as a multiselect. We would never do it that way
304 ///even if we did have multiple values, because
305 /// other data is per-node.
306 //$items['default nids'] = $items_transposed['nid'];
307 if ($dest_node = $node->annotationhook['node']) {
308 ///It can get easy to get bogged down in the possibilities
309 ///for multi-field issues. Probably should ignore
310 ///for now, but consider an 'annotation' type that
311 ///compares to nodes side by side. then how would this work?
312 ///We could defer to client-side setting/fixing
313 /// but then, we have to at least avoid clobbering
314 /// old values here.
315 $new_item = array();
316 $new_item['nid'] = $dest_node->nid;
317 $new_item['vid'] = $dest_node->vid;
318 //fieldname, type, (range1, range2, morehooks)
319 $node->annotationhook['annotatables'] = $annotatables = annotationfield_annotatable_fields($field, $dest_node->type, $dest_node);
320 switch(count($annotatables['annotators'])) {
321 case 1:
322 $new_item['annotator'] = current($annotatables['annotators']);
323 $new_item['fieldname'] = current($annotatables['fields']);
324 ///TODO:what about more than one annotatable field rather than one annotator
325 break;
326 ///TODO:case 0
327 ///TODO:case many
328 }
329 //$new_item['annotator'] = 'videoannotation'; ///GENERALIZE
330 //$new_item['fieldname'] = "field_video";//'mediaref'; ///GENERALIZE
331 $items[] = $new_item;
332
333 }
334 break;
335
336 case 'form':
337 $form = array();
338 $form[$field['field_name']]['#tree'] = TRUE;
339
340 /*
341 * TODO: array_merge, and call fields based on field type
342 */
343 //var_dump($items);
344 $mode = ($node->nid) ? 'edit':'create';
345 drupal_add_js(drupal_get_path('module','annotationfield').'/js/annotator.js');
346
347 ///add form keys for fields included in form to fill out
348 ///this will probably have some real meat for annotations
349 //var_dump($node->annotationhook['node'],$node);
350 foreach ($items as $i => $item) {
351 if (!is_int($i)) {
352 continue;
353 }
354
355 $html_class_selector = annotationfield_onpage_counter();
356
357 $form[$field['field_name']][$i] = array(
358 '#type' => 'fieldset',
359 '#attributes' => array('class' => 'annotationfield annotationfield-'.$html_class_selector),
360 '#tree' => TRUE
361 );
362
363 if (is_numeric($item['nid'])) {
364 $annotatee_node = node_load($item['nid']);//, $rid, TRUE);
365 $annotatables = ($node->annotationhook['annotatables']) ? $node->annotationhook['annotatables'] : annotationfield_annotatable_fields($field, $annotatee_node->type, $annotatee_node);
366
367
368 if (!$item['vid']) {
369 $item['vid'] = $annotatee_node->vid;
370 }
371 //signal for annotationfield_nodeapi(); still necessary?
372 $annotatee_node->annotatee = array();
373
374 $form[$field['field_name']][$i]['annotatee'] = array(
375 '#type'=> 'markup',
376 '#prefix' => '<div class="annotatee-'.$html_class_selector.'">',
377 '#suffix' => '</div>',
378 '#value' => annotationfield_annotatee_annotatables($annotatee_node, $annotatables['fields']),
379
380 //'#attributes' => array('class' => 'annotatee-'.$html_class_selector ),//doesn't seem to work
381
382 );
383 //should theme() be here or elsewhere? should we pass the node content?
384 //theme fieldtype+annotator+'_widget'
385 $data = null; //mode=create means no data
386 if ($mode === 'edit') {
387 $data = annotationfield_invoke_data($mode, $annotatee_node, $field, $item);
388 }
389 theme('annotationfield_annotatee_js',$html_class_selector, $mode, 'annotatee-'.$html_class_selector, $data);
390 } /** NOTE EITHER-OR ^-v **/
391 else {
392 ///no annotatee
393 theme('annotationfield_annotatee_js',$html_class_selector, $mode);
394 }
395
396 $form[$field['field_name']][$i]['annotator_fields'] = array('#prefix' => '<div class="annotationfield-available-annotators">',
397 '#suffix' => '</div>');
398
399 foreach( $annotatables['annotators'] as $ator) {
400 ///note:this hierarchy is currently a contract with the $ator in hook_annotationfield_form_submit
401 /// if we just gave them their fields, then we wouldn't have to do this
402 $form[$field['field_name']][$i]['annotator_fields'][$ator] = module_invoke($ator, 'annotationfield_form', $item);
403 }
404
405 if (!$item['annotator'] && count($annotatables['annotators']) == 1) {
406 $item['annotator'] = $annotatables['annotators'][0];
407 }
408
409 $form[$field['field_name']][$i]['nid'] = array(
410 '#type' => 'hidden',
411 '#default_value' => $item['nid'],
412 '#attributes' => array('class' => 'annotationfield-nid'),
413 );
414 //TODO:eventually, we'll have to figure out how to communicate a new version
415 //and what to do.
416 $form[$field['field_name']][$i]['vid'] = array(
417 '#type' => 'hidden',
418 '#default_value' => $item['vid'],
419 '#attributes' => array('class' => 'annotationfield-vid'),
420 );
421 $form[$field['field_name']][$i]['fieldname'] = array(
422 '#type' => 'hidden',
423 '#default_value' => $item['fieldname'],
424 '#attributes' => array('class' => 'annotationfield-fieldname'),
425 );
426 //for multiple, if any
427 $form[$field['field_name']][$i]['fielditem'] = array(
428 '#type' => 'hidden',
429 '#default_value' => $item['fielditem'],
430 '#attributes' => array('class' => 'annotationfield-fielditem'),
431 );
432 $form[$field['field_name']][$i]['annotator'] = array(
433 '#type' => 'hidden',
434 '#default_value' => $item['annotator'],
435 '#attributes' => array('class' => 'annotationfield-annotator'),
436 );
437 }
438 //if no items set...weirdly expressed, because there may be non-numerical item values
439 if (!isset($items[0])
440 ///BUGFIX:is_array($node) indicates default_value widget for field
441 ///there should never be a default value for an annotation field (right now, anyway)
442 && !is_array($node)
443 ) {
444 $options = _nodereference_potential_references($field, TRUE);
445
446 foreach ($options as $key => $value) {
447 $options[$key] = _nodereference_item($field, $value);
448 }
449
450 if (!$field['required']) {
451 //$options = array(0 => t('<none>')) + $options;
452 }
453 $form[$field['field_name']]['nids'] = array(
454 '#type' => 'select',
455 '#title' => t($field['widget']['label']),
456 '#default_value' => $items['default nid'],
457 '#size' => 0,
458 '#options' => $options,
459 '#required' => $field['required'],
460 '#description' => t($field['widget']['description']),
461 );
462 }
463 return $form;
464 case 'validate':
465 //foreach $items...
466 //TODO:make sure nid exists
467 //TODO:make sure each item annotator is a proper annotator
468 break;
469 case 'process form values':
470 /// for each item send it to the right annotator
471 foreach ($items as $i => $item) {
472 if ($item['annotator']) {
473 $ator_vals = module_invoke($item['annotator'],'annotationfield_form_submit',
474 $op, $node, $field, $item);//notice singular
475 //var_dump($ator_vals);
476 if (isset($ator_vals['morehooks'])) {
477 $ator_vals['morehooks'] = serialize($ator_vals['morehooks']);
478 }
479 $items[$i] = array_merge($item,$ator_vals);
480 /*OLD WAY
481 $annotator = $item['annotator'] . '_annotationfield_form_submit';
482 if (function_exists($annotator)) {
483 $items[$i] = array_merge($item,$annotator($op, $node, $field, $item));//notice singular
484 }*/
485 }
486 else {
487 ///TODO:no annotator assigned. do we clean up here? maybe nothing is necessary
488 }
489 }
490
491 ///? for multiple option
492 if (!empty($items['nids'])) {
493 $new_item['nid'] = $items['nids'];
494 //$new_item['vid'] = $items['vid'];
495 $items[] = $new_item;
496 unset($items['nids']);
497 }
498 break;
499 }
500 }
501
502
503
504 /**
505 * Implementation of hook_nodeapi().
506 */
507 function annotationfield_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
508 /*
509 This hook, though promising is pretty useless. Since CCK decorates the node content
510 too late (during op==alter), we can't really update it any further. Also, many types
511 (like the video module), configure hook_view() so even the body field is lost.
512 Therefore, perhaps annotation on nodes should be restricted to hooks with a View(module)
513 rather than the node_view (pretty annoying). OR we let the annotator do what it can for particular
514 views. we could in theory set a hook here, which the annotator module could simply see, and then
515 only perform its logic when we're actually annotating the view.
516 */
517 static $annotatees = array();
518 static $info = false;
519 //var_dump('OP',$op,$node);
520
521 /* note: eventually, we'll want to add $op == 'edit' case too, for self-annotating nodes (e.g. footnotes)
522 */
523 if (isset($node->annotatee) && $op == 'view') {
524 if (!$info) { $info = _content_type_info(); }
525
526 //var_dump(annotationfield_annotator_content_types(), $info["fields"]);
527 //var_dump(content_fields(NULL, 'ann'));
528 //var_dump($node->type,$info['content types']['media']['fields']/*$node,content_fields(NULL, $node->type)*/);
529 /* For CCK
530 $info['content types'][$node->type]['fields'][$field_name]['type'] == 'video_cck'
531 */
532 //var_dump($node->content);
533 // $node->content['']['#value'] = '<div class="hi">hi'. $node->content['body']['#value'] .'hi</div>';
534
535 //$node->content['body']['#value'] = '<div class="hi">altered body: '. $node->content['body']['#value'] .' END</div>';
536 //var_dump($node);
537 //If annotators/annotatees are delegated for this specific type/content:
538
539 if (true) {
540 //GENERALIZE
541 //drupal_add_js("\$(document).ready(function(){\$('//.field-field-mediaref').append('<button>blah</button>')});",'inline');
542 //var_dump($info['content types'][$node->type]['fields']);
543 foreach ($info['content types'][$node->type]['fields']
544 as $field_name => $f_info) {
545 //$field_name = 'field_mediaref';
546 $annotatees[$field_name] = $info['content types'][$node->type]['fields'][$field_name]['type'];
547 drupal_add_js('AnnotationController.annotatees["'. $node->nid .'"] = ' . drupal_to_js($annotatees),'inline');
548 }
549 }
550
551 }
552 }
553
554 function annotationfield_invoke_data($mode, &$annotatee_node, $field, &$item) {
555 if ($item['annotator']) {
556 $item['morehooks'] = unserialize($item['morehooks']);
557 return module_invoke($item['annotator'], 'annotationfield_data', $mode, $annotatee_node, $field, $item);
558 }
559 return NULL;
560 }
561
562 ///@return node content for the fields in @param fieldname_array
563 function annotationfield_annotatee_annotatables($node, $fieldname_array) {
564 $rv = '';
565 foreach($fieldname_array as $field) {
566 $rv .= annotationfield_annotatee_field_content($node, $field);
567 }
568 return $rv;
569 }
570
571 ///@return the content of a node for a particular field--shouldn't this be easy!
572 function annotationfield_annotatee_field_content($node, $fieldname, $fielditem=NULL) {
573 $annotatee_field = content_fields($fieldname, $node->type);
574 //$annotatee_field = content_fields('field_video', $annotatee_node->type);///GENERALIZE-done
575 ///Using CCK
576 if ($annotatee_field) {
577 $annotatee_field_value = $node->$fieldname;
578 $delta = (is_null($fielditem))?0:$fielditem;
579 $items[0]['view'] = content_format($annotatee_field, $annotatee_field_value[$delta], 'default', $node);
580 $annotatee_output = theme('annotatee_field', $node, $annotatee_field, $items, 0, 1);
581 //return content_format(content_fields('field_video', $annotatee_node->type), $annotatee_node->field_video[$delta], 'default', $annotatee_node);
582 return $annotatee_output;
583 }
584 ///No CCK
585 else {///stolen from node_view() code
586 //OLD:node_view($annotatee_node, FALSE, TRUE, FALSE),
587 //TODO:need to set page==true for video module, e.g. to completely trigger
588 node_build_content($node, FALSE, FALSE);
589 node_invoke_nodeapi($node, 'alter', FALSE, FALSE);
590 $items[0]['view'] = $node->content[$fieldname]['#value'];
591 $fake_field['field_name'] = $fieldname;
592 $fake_field['widget']['label'] = $fieldname;
593 $annotatee_output = theme('annotatee_field', $node, $fake_field, $items, 0, 1);
594 return $annotatee_output;
595 //return $annotatee_node->content['body']['#value'];
596 }
597 }
598
599 function theme_annotatee_field(&$node, &$field, &$items, $teaser, $page) {
600 ///watch out! non-CCK fields flow here through a hack, too
601 ///our contract assumes $field['fieldname'], $field['widget']['label'] and $items[i]['view'] only
602 return theme('field', $node, $field, $items, 0, 1);
603 }
604
605 /*
606 * @return array('annotators'=>[list of ators for node],'fields'=>[list of annable field names])
607 * @param $node, provided when deciding what to do for a particular node
608 */
609 function annotationfield_annotatable_fields($field, $nodetype, $node=NULL) {
610 /*TODO: This needs some love. we shouldn't make sub modules do all the work
611 instead we should cache results of module_invoke_all('annotationfield_provides'
612 then
613 */
614 $cck_info = content_types($nodetype);
615 $ftype_names = array();
616 $rv = array('fields'=>array(),'annotators'=>array());
617 if (is_array($cck_info['fields'])) {
618 foreach($cck_info['fields'] as $fname => $f) {
619 $ftype_names[$f['type']][] = $fname;
620 }
621 }
622 $annotator_opinion = array();
623
624 ///it won't be set if the field isn't configured yet
625 $annotator_types = (isset($field['annotator_types'])) ?
626 $field['annotator_types'] : array_keys(module_invoke_all('annotationfield_annotator'));
627
628 foreach($annotator_types as $ator) {//instead of module_invoke_all, just the enabled ones
629 if ($ator) {///$ator===0 when it's not selected
630 $annotator_opinion = array_merge($annotator_opinion, module_invoke($ator, 'annotationfield_annotatable_fields', $nodetype, $ftype_names, $node));
631 }
632 }
633 $field_annotator_list = array();
634
635
636 if ($node && $field["annotatee_fields"][$nodetype]) {
637 ///filter out the fields that admin has UNchecked
638 $filterfields = array_filter($field["annotatee_fields"][$nodetype]);
639 }
640
641 foreach ($annotator_opinion as $ator_name => $afields) {
642 ///intersect with filter list
643 if (is_array($filterfields)) {
644 $afields = array_intersect($afields, $filterfields);
645 }
646 if (count($afields)) {
647 $rv['annotators'][] = $ator_name;
648 $rv['fields'] = array_merge($rv['fields'], $afields);
649 }
650 }
651 return $rv;
652 }
653
654 function annotationfield_formfields($type) {
655 // Create a dummy node and form and call hook_form_alter()
656 // to produce an array of fields and weights added to the node by all modules.
657 $dummy_node = new stdClass();
658 $dummy_node->type = $type;
659
660 // Some modules (userreview...) "hide" their node forms, resulting in no field
661 // being listed. We set a special flag to inform them this form is special.
662 $dummy_node->cck_dummy_node_form = TRUE;
663
664 $dummy_form_id = $type .'_node_form';
665 $dummy_form = node_form($dummy_node);
666 foreach (module_implements('form_alter') as $module) {
667 $function = $module .'_form_alter';
668 $function($dummy_form_id, $dummy_form);
669 }
670 return $dummy_form;
671 }
672
673 /*
674 * @return Array of content types that can annotate this node
675 */
676 function annotationfield_annotatable($node) {
677 $ator_ctypes = annotationfield_annotator_content_types();
678 $rv = array();
679 foreach($ator_ctypes as $cname => $annfields) {
680 $first_field = current($annfields);
681 if ($first_field["referenceable_types"][$node->type]) {
682 $rv[$cname] = content_types($cname);
683 }
684 }
685 return $rv;
686 }
687
688 /// @return Array of content types that have annotation fields
689 function annotationfield_annotator_content_types() {
690 static $content_types = false;
691 if ($content_types) {
692 return $content_types;
693 }
694 $content_types = array();
695
696 $ann_fields = annotationfield_annotator_fields();
697 foreach (content_types() as $cname => $ctype) {
698 $c_ann_fields = array_intersect_key($ann_fields, $ctype['fields']);
699 if (count($c_ann_fields)) {
700 $content_types[$cname] = $c_ann_fields;
701 }
702 }
703 return $content_types;
704 }
705 /// @return all annotationfields in the system
706 function annotationfield_annotator_fields() {
707 static $ann_fields = false;
708 if ($ann_fields) {
709 return $ann_fields;
710 }
711
712 $ann_fields = array();
713 foreach ( content_fields() as $fname => $field) {
714 if ($field['type'] == 'annotation_field') {
715 $ann_fields[$fname] = $field;
716 }
717 }
718 return $ann_fields;
719 }
720
721 function annotationfield_onpage_counter() {
722 static $html_class_selector = 0;
723 return ++$html_class_selector;
724 }
725
726 function theme_annotationfield_annotatee($annotatee_class, $annotatee_content) {
727 return '<div class="annotationfield-annotatee-annotated '. check_plain($annotatee_class).'">'. $annotatee_content .'</div>';
728 }
729
730 function theme_annotationfield_annotatee_js($onpage_id, $mode, $annotatee_selector=NULL, $data=NULL, $options=NULL, $ator=NULL) {
731 $js = sprintf('jQuery(function($){AnnotationController.initField("%s", %d', $mode, $onpage_id);
732 if ($annotatee_selector) {
733 $js .= ',".'. $annotatee_selector .'"';
734 if ($data) {
735 $js .= ',' . drupal_to_js($data);
736 $js .= ',' . drupal_to_js($options);
737 if ($ator) {
738 $js .= ',' . drupal_to_js($ator);
739 }
740 }
741 }
742 $js .= ');});';
743 drupal_add_js($js,'inline');
744 }
745
746 function annotationfield_node_annotate() {
747 /* So far this function only knows that it's annotating a particular
748 node with a certain type. We don't know what the annotation
749 field is here.
750 */
751
752 global $user;
753 $nid = arg(1);
754 //$rid = arg(3);
755 $annotation_type = arg(3);
756
757 $field_annotatee = arg(4); //should be UNREQUIRED
758 $output = '';
759
760 if (is_numeric($nid)) {
761 $node = node_load($nid);//, $rid, TRUE);
762 $node->annotatee = array(); //signal for annotationfield_nodeapi()
763 }
764 $annotator_node = array('uid' => $user->uid,
765 'name' => $user->name,
766 'type' => $annotation_type,
767 'annotationhook' => array('node' => $node,
768 ),
769 );
770 $output .= drupal_get_form($annotation_type .'_node_form', $annotator_node);
771
772 return $output;
773 }

  ViewVC Help
Powered by ViewVC 1.1.2