Projet

Général

Profil

Paste
Télécharger (29 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / fivestar / includes / fivestar.field.inc @ 4853591f

1
<?php
2

    
3
/**
4
 * @file
5
 * Provides CCK integration for fivestar module
6
 */
7

    
8
/**
9
 * Implementation of hook_field_info().
10
 */
11
function fivestar_field_info() {
12
  return array(
13
    'fivestar' => array(
14
      'label' => t('Fivestar Rating'),
15
      'description' => t('Store a rating for this piece of content.'),
16
      'default_widget' => 'exposed',
17
      'default_formatter' => 'fivestar_formatter_default',
18
      'settings' => array(
19
        'axis' => 'vote',
20
      ),
21
      'instance_settings' => array(
22
        'stars' => 5,
23
      ),
24
      'property_type' => 'fivestar',
25
      'property_callbacks' => array('fivestar_property_info_callback'),
26
      'microdata' => TRUE,
27
    ),
28
  );
29
}
30

    
31
function fivestar_form_field_ui_field_edit_form_alter(&$form, $form_state) {
32
  $field = $form['#field'];
33
  $instance = $form['#instance'];
34
  if ($field['type'] == 'fivestar') {
35
    // Multiple values is not supported with Fivestar.
36
    $form['field']['cardinality']['#access'] = FALSE;
37
    $form['field']['cardinality']['#value'] = 1;
38
    // Setting "default value" here is confusing and for all practical purposes
39
    // with existing widgets provided by fivestar (and anything else available
40
    // in contrib) meaningless.
41
    $form['instance']['default_value_widget']['#access'] = FALSE;
42
  }
43
}
44

    
45
/**
46
 * Implementation of hook_field_settings_form().
47
 */
48
function fivestar_field_settings_form($field, $instance) {
49
  $form['axis'] = array(
50
    '#type' => 'select',
51
    '#required' => TRUE,
52
    '#title' => 'Voting Tag',
53
    '#options' => fivestar_get_tags(),
54
    '#description' => t('The tag this rating will affect. Enter a property on which that this rating will affect, such as <em>quality</em>, <em>satisfaction</em>, <em>overall</em>, etc.'),
55
    '#default_value' => isset($field['settings']['axis']) ? $field['settings']['axis'] : '',
56
    '#disabled' => field_has_data($field),
57
  );
58

    
59
  return $form;
60
}
61

    
62
function fivestar_field_instance_settings_form($field, $instance) {
63
  $form = array();
64

    
65
  $widget_title = ($instance['widget']['type'] == 'select') ? t('Number of options') : t('Number of stars');
66
  $form['stars'] = array(
67
    '#type' => 'select',
68
    '#title' => check_plain($widget_title),
69
    '#options' => drupal_map_assoc(range(1, 10)),
70
    '#default_value' => isset($instance['settings']['stars']) ? $instance['settings']['stars'] : 5,
71
  );
72

    
73
  $form['allow_clear'] = array(
74
    '#type' => 'checkbox',
75
    '#title' => t('Allow users to cancel their ratings.'),
76
    '#default_value' => isset($instance['settings']['allow_clear']) ? $instance['settings']['allow_clear'] : FALSE,
77
    '#return_value' => 1,
78
  );
79

    
80
  $options = fivestar_get_targets($field, $instance);
81
  $form['target'] = array(
82
    '#title' => t('Voting target'),
83
    '#type' => 'select',
84
    '#default_value' => (isset($instance['settings']['target']) && $instance['widget']['type'] != 'exposed') ? $instance['settings']['target'] : 'none',
85
    '#options' => $options,
86
    '#description' => t('The voting target will make the value of this field cast a vote on another node. Use node reference fields module to create advanced reviews. Use the Parent Node Target when using fivestar with comments. More information available on the <a href="http://drupal.org/handbook/modules/fivestar">Fivestar handbook page</a>.'),
87
    '#access' => (count($options) > 1 && $instance['widget']['type'] != 'exposed'),
88
  );
89

    
90
  return $form;
91
}
92

    
93
/**
94
 * Implementation of hook_field_insert().
95
 */
96
function fivestar_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
97
  _fivestar_field_helper($entity_type, $entity, $field, $instance, $langcode, $items);
98
}
99

    
100
/**
101
 * Implementation of hook_field_update().
102
 */
103
function fivestar_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
104
  _fivestar_field_helper($entity_type, $entity, $field, $instance, $langcode, $items);
105
}
106

    
107
/**
108
 * Implementation of hook_field_delete().
109
 */
110
function fivestar_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
111
  _fivestar_field_helper($entity_type, $entity, $field, $instance, $langcode, $items, 'delete');
112
}
113

    
114
function _fivestar_field_helper($entity_type, $entity, $field, $instance, $langcode, &$items, $op = '') {
115
  foreach ($items as $delta => $item) {
116
    if ((isset($entity->status) && !$entity->status) || $op == 'delete') {
117
      $rating = 0;
118
    }
119
    else {
120
      $rating = (isset($items[$delta]['rating'])) ? $items[$delta]['rating'] : 0;
121
    }
122
    $target = _fivestar_field_target($entity, $field, $instance, $item, $langcode);
123
    if (!empty($target)) {
124
      _fivestar_cast_vote($target['entity_type'], $target['entity_id'], $rating, $field['settings']['axis'], $entity->uid, TRUE);
125
      votingapi_recalculate_results($target['entity_type'], $target['entity_id']);
126
    }
127
    // The original callback is only called for a single updated field, but the Field API
128
    // then updates all fields of the entity. For an update, the Field API first deletes
129
    // the equivalent row in the database and then adds a new row based on the
130
    // information in $items here. If there are multiple Fivestar fields on an entity, the
131
    // one being updated is handled ok ('rating' having already been set to the new value),
132
    // but other Fivestar fields are set to NULL as 'rating' isn't set - not what an update
133
    // would be expected to do. So set 'rating' for all of the Fivestar fields from the
134
    // existing user data in $items. This preserves the user vote thru Field API's
135
    // delete/re-insert process.
136
    if (!isset($items[$delta]['rating'])) {
137
      $items[$delta]['rating'] = $items[$delta]['user'];
138
    }
139
  }
140
}
141

    
142
/**
143
 * Helper function to find the id that should be rated when a field is changed.
144
 */
145
function _fivestar_field_target($entity, $field, $instance, $item, $langcode) {
146
  if ($instance['widget']['type'] == 'exposed') {
147
    return NULL;
148
  }
149
  if (isset($instance['settings']['target'])) {
150
    $target = fivestar_get_targets($field, $instance, $instance['settings']['target'], $entity, $langcode);
151
  }
152
  else {
153
    // If all else fails, default to voting on the instance the field is attached to.
154
    list($id, $vid, $bundle) = entity_extract_ids($instance['entity_type'], $entity);
155
    $target = array(
156
      'entity_id' => $id,
157
      'entity_type' => $instance['entity_type'],
158
    );
159
  }
160
  return $target;
161
}
162

    
163
/**
164
 * Helper function to store a rating into the field storage.
165
 */
166
function _fivestar_update_field_value($entity_type, $entity, $field_name, $langcode, $value) {
167
  $entity->{$field_name}[$langcode][0]['rating'] = $value;
168
  $entity->original = isset($entity->original) ? $entity->original : NULL;
169
  field_attach_presave($entity_type, $entity);
170
  field_attach_update($entity_type, $entity);
171
}
172

    
173
/**
174
 * Implementation of hook_field_is_empty().
175
 */
176
function fivestar_field_is_empty($item, $field) {
177
  return empty($item['rating']) || $item['rating'] == '-';
178
}
179

    
180
/**
181
 * Implementation of hook_field_widget_info().
182
 */
183
function fivestar_field_widget_info() {
184
  return array(
185
    'exposed' => array(
186
      'label' => t('Stars (rated while viewing)'),
187
      'field types' => array('fivestar'),
188
      'behaviors' => array('multiple values' => FIELD_BEHAVIOR_NONE),
189
    ),
190
    'stars' => array(
191
      'label' => t('Stars (rated while editing)'),
192
      'field types' => array('fivestar'),
193
      'behaviors' => array('multiple values' => FIELD_BEHAVIOR_NONE),
194
      'settings' => array(
195
        'widget' => array(
196
          'fivestar_widget' => 'default',
197
        )
198
      )
199
    ),
200
    'fivestar_select' => array(
201
      'label' => t('Select list (rated while editing)'),
202
      'field types' => array('fivestar'),
203
      'behaviors' => array('multiple values' => FIELD_BEHAVIOR_NONE),
204
    ),
205
  );
206
}
207

    
208
/**
209
 * Implementation of hook_field_widget_settings_form().
210
 */
211
function fivestar_field_widget_settings_form($field, $instance) {
212
  $form = array();
213
  if ($instance['widget']['type'] == 'stars') {
214
    $form['widget'] = array(
215
      '#tree' => TRUE,
216
      '#type' => 'fieldset',
217
      '#title' => t('Star display options'),
218
      '#description' => t('Choose a style for your widget.'),
219
      '#weight' => -2,
220
      '#collapsible' => TRUE,
221
      '#collapsed' => TRUE,
222
    );
223

    
224
    $widgets = module_invoke_all('fivestar_widgets');
225

    
226
    $form['widget']['fivestar_widget'] = array(
227
      '#type' => 'radios',
228
      '#options' => array('default' => t('Default')) + $widgets,
229
      '#default_value' => isset($instance['widget']['settings']['widget']['fivestar_widget']) ? $instance['widget']['settings']['widget']['fivestar_widget'] : 'default',
230
      '#attributes' => array('class' => array('fivestar-widgets', 'clearfix')),
231
      '#pre_render' => array('fivestar_previews_expand'),
232
      '#attached' => array('css' => array(drupal_get_path('module', 'fivestar') . '/css/fivestar-admin.css')),
233
    );
234
  }
235

    
236
  return $form;
237
}
238

    
239
function fivestar_previews_expand($element) {
240

    
241
  foreach (element_children($element) as $css) {
242
    $vars = array(
243
      'css' => $css,
244
      'name' => strtolower($element[$css]['#title']),
245
    );
246
    $element[$css]['#description'] = theme('fivestar_preview_widget', $vars);
247
  }
248

    
249
  return $element;
250
}
251

    
252
/**
253
 * Implementation of hook_field_widget_form().
254
 */
255
function fivestar_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
256
  $element['#tree'] = TRUE;
257
  $i18n = function_exists('i18n_field_translate_property');
258
  if ($instance['widget']['type'] == 'fivestar_select' || ($instance['widget']['type'] == 'stars' && isset($form['#title']) && $form['#title'] == 'Default value')) {
259
    $options = array(0 => t('No stars'));
260
    if (empty($instance['settings']['stars'])) {
261
      $instance['settings']['stars'] = 5;
262
    }
263
    for ($i = 1; $i <= $instance['settings']['stars']; $i++) {
264
      $percentage = ceil($i * 100 / $instance['settings']['stars']);
265
      $options[$percentage] = format_plural($i, '1 star', '@count stars');
266
    }
267
    $element['rating'] = array(
268
      '#type' => 'select',
269
      '#title' => isset($instance['label']) ? (($i18n) ? i18n_field_translate_property($instance, 'label') : t($instance['label'])) : FALSE,
270
      '#options' => $options,
271
      '#default_value' => isset($items[$delta]['rating']) ? $items[$delta]['rating'] : NULL,
272
      '#description' => isset($instance['description']) ? (($i18n) ? i18n_field_translate_property($instance, 'description') : t($instance['description'])) : FALSE,
273
      '#required' => isset($instance['required']) ? $instance['required'] : FALSE,
274
    );
275
  }
276

    
277
  elseif ($instance['widget']['type'] == 'stars') {
278
    $widgets = module_invoke_all('fivestar_widgets');
279
    $active = isset($instance['widget']['settings']['widget']['fivestar_widget']) ? $instance['widget']['settings']['widget']['fivestar_widget'] : 'default';
280
    $widget = array(
281
      'name' => isset($widgets[$active]) ? strtolower($widgets[$active]) : 'default',
282
      'css' => $active,
283
    );
284

    
285
    $values = array(
286
      'user' => 0,
287
      'average' => 0,
288
      'count' => 0,
289
    );
290

    
291
    $settings = array(
292
      'stars' => $instance['settings']['stars'],
293
      'allow_clear' => !empty($instance['settings']['allow_clear']) ? $instance['settings']['allow_clear'] : FALSE,
294
      'style' => 'user',
295
      'text' => 'none',
296
      'widget' => $widget,
297
    );
298

    
299
    $element['rating'] = array(
300
      '#type'=> 'fivestar',
301
      '#title' => isset($instance['label']) ? (($i18n) ? i18n_field_translate_property($instance, 'label') : t($instance['label'])) : FALSE,
302
      '#stars' => isset($instance['settings']['stars']) ? $instance['settings']['stars'] : 5,
303
      '#allow_clear' => isset($instance['settings']['allow_clear']) ? $instance['settings']['allow_clear'] : FALSE,
304
      '#default_value' => isset($items[$delta]['rating']) ? $items[$delta]['rating'] : (isset($instance['default_value'][$delta]['rating']) ? $instance['default_value'][$delta]['rating'] : 0),
305
      '#widget' => $widget,
306
      '#settings' => $settings,
307
      '#values' => $values,
308
      '#description' => isset($instance['description']) ? (($i18n) ? i18n_field_translate_property($instance, 'description') : t($instance['description'])) : FALSE,
309
      '#required' => isset($instance['required']) ? $instance['required'] : FALSE,
310
    );
311
  }
312

    
313
  return array($element);
314
}
315

    
316
/**
317
 * Implementation of hook_field_formatter_info().
318
 */
319
function fivestar_field_formatter_info() {
320
  return array(
321
    'fivestar_formatter_default' => array(
322
      'label' => t('As Stars'),
323
      'field types' => array('fivestar'),
324
      'settings' =>  array(
325
        // Note: Do not set to widget to 'default' by
326
        // default. "Stars (rated while editing)" should
327
        // default to whatever was selected as a widget
328
        // setting. Let hook_field_formatter_view() handle
329
        // defaults for instances that aren't set to anything.
330
        'widget' => array('fivestar_widget' => NULL),
331
        'style' => 'average',
332
        'text' => 'average',
333
        'expose' => TRUE,
334
      ),
335
    ),
336
    'fivestar_formatter_rating' => array(
337
      'label' => t('Rating (i.e. 4.2/5)'),
338
      'field types' => array('fivestar'),
339
    ),
340
    'fivestar_formatter_percentage' => array(
341
      'label' => t('Percentage (i.e. 92)'),
342
      'field types' => array('fivestar'),
343
    ),
344
  );
345
}
346

    
347
/**
348
 * Implements hook_field_formatter_settings_form().
349
 */
350
function fivestar_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
351
  $display = $instance['display'][$view_mode];
352
  $settings = $display['settings'];
353

    
354
  if ($display['type'] != 'fivestar_formatter_default') {
355
    return;
356
  }
357

    
358
  $element['widget'] = array(
359
    '#tree' => TRUE,
360
    '#type' => 'fieldset',
361
    '#title' => t('Star display options'),
362
    '#description' => t('Choose a style for your widget.'),
363
    '#weight' => -2,
364
    '#collapsible' => TRUE,
365
    '#collapsed' => TRUE,
366
  );
367

    
368
  $widgets = module_invoke_all('fivestar_widgets');
369

    
370
  $element['widget']['fivestar_widget'] = array(
371
    '#type' => 'radios',
372
    '#options' => array('default' => t('Default')) + $widgets,
373
    '#default_value' => isset($settings['widget']['fivestar_widget']) ? $settings['widget']['fivestar_widget'] : 'default',
374
    '#attributes' => array('class' => array('fivestar-widgets', 'clearfix')),
375
    '#pre_render' => array('fivestar_previews_expand'),
376
    '#attached' => array('css' => array(drupal_get_path('module', 'fivestar') . '/css/fivestar-admin.css')),
377
  );
378

    
379
  if ($instance['widget']['type'] == 'exposed') {
380
    $element['expose'] = array(
381
      '#type' => 'checkbox',
382
      '#title' => t('Allow voting on the entity.'),
383
      '#default_value' => $settings['expose'],
384
      '#return_value' => 1
385
    );
386
  }
387

    
388
  $element['style'] = array(
389
    '#type' => 'select',
390
    '#title' => t('Value to display as stars'),
391
    '#default_value' => $settings['style'],
392
    '#options' => array(
393
      'average' => t('Average vote'),
394
      'user'    => t("User's vote"),
395
      'smart'   => t("User's vote if available, average otherwise"),
396
      'dual'    => t("Both user's and average vote"),
397
    ),
398
  );
399
  $element['text'] = array(
400
    '#type' => 'select',
401
    '#title' => t('Text to display under the stars'),
402
    '#default_value' => $settings['text'],
403
    '#options' => array(
404
      'none'    => t('No text'),
405
      'average' => t('Average vote'),
406
      'user'    => t("User's vote"),
407
      'smart'   => t("User's vote if available, average otherwise"),
408
      'dual'    => t("Both user's and average vote"),
409
    ),
410
  );
411

    
412
  return $element;
413
}
414

    
415
/**
416
 * Implements hook_field_formatter_settings_summary().
417
 */
418
function fivestar_field_formatter_settings_summary($field, $instance, $view_mode) {
419
  $display = $instance['display'][$view_mode];
420
  $settings = $display['settings'];
421

    
422
  if ($display['type'] != 'fivestar_formatter_default') {
423
    return;
424
  }
425

    
426
  $widgets = module_invoke_all('fivestar_widgets');
427

    
428
  if ($instance['widget']['type'] == 'exposed') {
429
    $summary = t("Style: @widget, Exposed: @expose, Stars display: @style, Text display: @text", array(
430
      '@widget' => isset($widgets[$settings['widget']['fivestar_widget']]) ? strtolower($widgets[$settings['widget']['fivestar_widget']]) : t('default'),
431
      '@expose' => ($settings['expose']) ? 'yes' : 'no',
432
      '@style' => strtolower($settings['style']),
433
      '@text' => strtolower($settings['text'])));
434
    return $summary;
435
  }
436

    
437
  $summary = t("Style: @widget, Stars display: @style, Text display: @text", array(
438
    '@widget' => isset($widgets[$settings['widget']['fivestar_widget']]) ? $widgets[$settings['widget']['fivestar_widget']] : t('default'),
439
    '@style' => strtolower($settings['style']),
440
    '@text' => strtolower($settings['text'])));
441

    
442
  return $summary;
443
}
444

    
445
/**
446
 * Implements hook_field_formatter_view().
447
 *
448
 * This function returns a renderable array for each fivestar field
449
 * to be displayed when viewing a node (in any view mode).
450
 * The render array will be either a form array created with
451
 * drupal_get_form() or a custom render array, to be sent to a
452
 * fivestar theme function.
453
 *
454
 * @param $items
455
 *  Array. Generated by fivestar_field_prepare_view(). This array contains
456
 *  processed voting info.
457
 *
458
 * @return $element
459
 *  Renderable array. This array will always be $element[0], with only one
460
 *  top level item, because Fivestar does not offer multi-value fields.
461
 */
462
function fivestar_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
463
  $element = array();
464
  $settings = $display['settings'];
465
  $widgets = module_invoke_all('fivestar_widgets');
466
  $widget = _fivestar_get_widget($widgets, $display, $instance);
467
  $values = $items[0];
468

    
469
  // Determine if any set of stars to be displayed need to be
470
  // displayed in a form. (That is, can the user click the stars
471
  // to cast a vote?) If yes, hand off everything we know to the
472
  // fivestar_custom_widget form, and let it take care of the rest.
473
  // Note: Stars will only be displayed in a form in the following circumstance:
474
  // - Fivestar widget selected is "Stars (rated while viewing)"
475
  // - Fivestar display setting = "exposed"
476
  $is_form = ($instance['widget']['type'] == 'exposed'
477
              && user_access('rate content')
478
              && $display['type'] == 'fivestar_formatter_default'
479
              && $display['settings']['expose']) ? TRUE : FALSE;
480
  if ($is_form) {
481
    // TODO. Get rid of voting categories setting, then change this so
482
    // axis = field name.
483
    $tag = (isset($field['settings']['axis'])) ? $field['settings']['axis'] : 'vote';
484
    list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
485
    $settings = _fivestar_custom_widget_settings($entity_type, $instance, $display, $id, $tag, $widget);
486
    // Store entity and field data for later reuse.
487
    $settings += array(
488
      'entity' => $entity,
489
      'field_name' => $instance['field_name'],
490
      'langcode' => $langcode,
491
    );
492
    // If microdata module is enabled, attach the microdata attributes.
493
    $settings['microdata'] = module_exists('microdata') ? $entity->microdata[$field['field_name']] : array();
494

    
495
    $element[0] = drupal_get_form('fivestar_custom_widget', $values, $settings);
496
    // Our work here is done.
497
    return $element;
498
  }
499

    
500
  // No stars will be displayed in a form. Build a renderable array.
501
  $element[0] = array(
502
    // Add a container div around this field with the clearfix class on it.
503
    '#attributes' => array('class' => array('clearfix')),
504
    '#theme_wrappers' => array('container'),
505
  );
506

    
507
  // Determine if we are going to display stars, rating or percentage.
508
  $formatter = $display['type'];
509
  if ($formatter == 'fivestar_formatter_percentage' || $formatter == 'fivestar_formatter_rating') {
510
    $element[0]['user'] = array(
511
      '#theme' => $formatter,
512
      '#instance_settings' => $instance['settings'],
513
      '#display_settings' => $settings,
514
      '#item' => $values,
515
    );
516
    // No stars to display. Our work here is done.
517
    return $element;
518
  }
519

    
520
  // Determine which sets of stars are going to be displayed.
521
  // Options:
522
  // - Only show average of all votes.
523
  // - Only show the user his/her own vote.
524
  // - Show both the average and the user's own votes.
525
  $style = $display['settings']['style'];
526
  $show_average_stars = ($style == 'average' || $style == 'dual' || ($style == 'smart' && empty($values['user'])));
527
  $show_user_stars = ($style == 'user' || $style == 'dual' || ($style == 'smart' && !empty($values['user'])));
528
  if ($show_user_stars) {
529
    $element[0]['user'] = array(
530
      '#theme' => $display['type'],
531
      '#rating' => $values['user'],
532
      '#instance_settings' => $instance['settings'],
533
      '#display_settings' => $settings,
534
      '#widget' => $widget,
535
    );
536
    $element[0]['#attributes']['class'][] = 'fivestar-user-stars';
537
  }
538
  if ($show_average_stars) {
539
    $element[0]['average'] = array(
540
      '#theme' => $display['type'],
541
      '#rating' => $values['average'],
542
      '#instance_settings' => $instance['settings'],
543
      '#display_settings' => $settings,
544
      '#widget' => $widget,
545
    );
546
    $element[0]['#attributes']['class'][] = 'fivestar-average-stars';
547
  }
548
  if ($style === 'smart') {
549
    $element[0]['#attributes']['class'][] = 'fivestar-smart-stars';
550
  }
551
  elseif ($style === 'dual') {
552
    $element[0]['#attributes']['class'][] = 'fivestar-combo-stars';
553
  }
554

    
555
  // Determine which text is to be displayed.
556
  $text = $display['settings']['text'];
557
  $summary_options = array(
558
    'stars' => $instance['settings']['stars'],
559
    'votes' => NULL,
560
  );
561

    
562
 $summary_options['microdata'] = _fivestar_get_microdata_property_info($entity_type, $entity, $field, $instance);
563

    
564
  // If we're displaying both user and average ratings, add a description to
565
  // both the 'user' and 'average' elements.
566
  if ($style === 'dual') {
567
    $element[0]['user']['#description'] = theme('fivestar_summary', array(
568
      'user_rating' => $values['user'],
569
    ) + $summary_options);
570
    $element[0]['average']['#description'] = theme('fivestar_summary', array(
571
      'average_rating' => $values['average'],
572
      'votes' => $values['count'],
573
    ) + $summary_options);
574
  }
575
  // If we're only creating one element (either 'user' or 'average'), prepare
576
  // the correct description, and place it on that element.
577
  else {
578
    // Prepare the description.
579
    $show_average_text = ($text === 'average' || $text === 'dual' || ($text === 'smart' && empty($values['user'])));
580
    $show_user_text = ($text === 'user' || $text === 'dual' || ($text === 'smart' && !empty($values['user'])));
581
    if ($show_user_text) {
582
      $summary_options['user_rating'] = $values['user'];
583
      $element[0]['#attributes']['class'][] = 'fivestar-user-text';
584
    }
585
    if ($show_average_text) {
586
      $summary_options['average_rating'] = $values['average'];
587
      $summary_options['votes'] = $values['count'];
588
      $element[0]['#attributes']['class'][] = 'fivestar-average-text';
589
    }
590
    if ($text === 'smart') {
591
      $element[0]['#attributes']['class'][] = 'fivestar-smart-text';
592
    }
593
    elseif ($text === 'dual') {
594
      $element[0]['#attributes']['class'][] = 'fivestar-combo-text';
595
    }
596
    // Add the description to the set of stars. It might be named either 'user'
597
    // or 'average', so first figure out its name.
598
    $children = element_children($element[0]);
599
    $name = reset($children);
600
    $element[0][$name]['#description'] = theme('fivestar_summary', $summary_options);
601
  }
602

    
603
  return $element;
604
}
605

    
606
/**
607
 * Generate the $settings parameter to be passed to fivestar_custom_widget().
608
 *
609
 * @params
610
 *
611
 * @return $settings
612
 *  Array. @see fivestar_custom_widget().
613
 */
614
function _fivestar_custom_widget_settings($entity_type, $instance, $display, $id, $tag, $widget) {
615
  $settings = $display['settings'];
616
  $settings = array(
617
    'stars' => (!empty($instance['settings']['stars'])) ? $instance['settings']['stars'] : 5,
618
    'allow_clear' => (!empty($instance['settings']['allow_clear'])) ? $instance['settings']['allow_clear'] : 0,
619
    'style' => $settings['style'],
620
    'text' => $settings['text'],
621
    'content_type' => $entity_type,
622
    'content_id' => $id,
623
    'tag' => $tag,
624
    'autosubmit' => TRUE,
625
    'title' => FALSE,
626
    'labels_enable' => FALSE,
627
    'labels' => array(),
628
    'widget' => $widget,
629
    'description' => $instance['description'],
630
  );
631

    
632
  return $settings;
633
}
634

    
635
/**
636
 * @param $widgets
637
 *  Array, $widgets = module_invoke_all('fivestar_widgets');
638
 *  $widgets = array('path/to/css' => 'Widget Name', 'path/to/more/css' => 'Widget 2');
639
 *
640
 * @param $display
641
 *  Array. This is the $display parameter passed to fivestar_field_formatter_view().
642
 *
643
 * @param $instance
644
 *  Array. This is the $instance parameter passed to fivestar_field_formatter_view().
645
 *
646
 * @return $widget
647
 *  Array. $widget = array('name' => 'my widget', 'css' => 'sites/all/mymodule/mywidget.css');
648
 */
649
function _fivestar_get_widget($widgets, $display, $instance) {
650
  // If the type doesn't required widgets lets get out of here.
651
  // TODO: Implement this WAY better.
652
  if (in_array($display['type'], array('fivestar_formatter_rating', 'fivestar_formatter_percentage'))) {
653
    return FALSE;
654
  }
655

    
656
  // Stars (rated while viewing) is $type = 'exposed'.
657
  // Stars (rated while editing) is $type = 'stars'.
658
  $type = $instance['widget']['type'];
659

    
660
  // Determine which widget to display.
661
  if (!$fivestar_widget = $display['settings']['widget']['fivestar_widget']) {
662
    // No display has been selected and saved by the user.
663
    if ($type == 'exposed') {
664
      // Stars rated while viewing, that is, $type = 'exposed', fall backs on 'default'
665
      // (which is the same as nothing).
666
      $fivestar_widget = 'default';
667
    }
668
    elseif ($type == 'stars') {
669
      // Stars rated while editing, that is, $type = stars,
670
      // falls back on whatever the user selected to be displayed on node/add and node/%/edit
671
      $fivestar_widget = $instance['widget']['settings']['widget']['fivestar_widget'];
672
    }
673
  }
674

    
675
  $widget = array(
676
    'name' => isset($widgets[$fivestar_widget]) ? strtolower($widgets[$fivestar_widget]) : 'default',
677
    'css' => $fivestar_widget,
678
  );
679

    
680
  return $widget;
681
}
682

    
683
/**
684
 * Implements hook_field_prepare_view().
685
 */
686
function fivestar_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
687
  // TODO: Clean this function up!
688
  foreach ($entities as $id => $entity) {
689
    // Ensure the items aren't processed twice.
690
    if (!isset($items[$id][0]['count'])) {
691
      // Populating the $items[$id] array even for items with no value forces
692
      // the render system to output a widget.
693
      if ($instances[$id]['widget']['type'] == 'exposed') {
694
        // If the widget type is exposed then we want to look up the voting api
695
        // values.
696
        $tag = $field['settings']['axis'];
697
        $votes = fivestar_get_votes($entity_type, $id, $tag);
698
        $values['user'] = isset($votes['user']['value']) ? $votes['user']['value'] : 0;
699
        $values['average'] = isset($votes['average']['value']) ? $votes['average']['value'] : 0;
700
        $values['count'] = isset($votes['count']['value']) ? $votes['count']['value'] : 0;
701
        $items[$id] = array($values);
702
      }
703
      else {
704
        // If the widget type is not exposed, then the count is always 1 or 0.
705
        // The count is pointless to display.
706
        if (!empty($items[$id][0]['rating'])) {
707
          $values['count'] = 1;
708
          $values['user'] = $items[$id][0]['rating'];
709
          $values['average'] = $items[$id][0]['rating'];
710
        }
711
        else {
712
          $values['count'] = 0;
713
          $values['user'] = 0;
714
          $values['average'] = 0;
715
        }
716
        $items[$id] = array($values);
717
      }
718
    }
719
  }
720
}
721

    
722
/**
723
 * Implements hook_microdata_value_type_alter().
724
 */
725
function fivestar_microdata_value_types_alter(&$types) {
726
  $types['fivestar'] = 'item_option';
727
}
728

    
729
/**
730
 * Callback to alter the property info of fivestar fields.
731
 */
732
function fivestar_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
733
  $name = $field['field_name'];
734
  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
735

    
736
  $property['property info'] = array(
737
    'average_rating' => array(
738
      'label' => t('Average Rating'),
739
      'type' => 'text',
740
      'microdata' => TRUE,
741
    ),
742
    'user_rating' => array(
743
      'label' => t('User\'s Rating'),
744
      'type' => 'text',
745
      'microdata' => TRUE,
746
    ),
747
  );
748
}
749

    
750
/**
751
 * Get microdata attributes for Fivestar field.
752
 */
753
function _fivestar_get_microdata_property_info($entity_type, $entity, $field, $instance) {
754
  // If microdata module is enabled, attach the microdata attributes the module
755
  // adds to the entity object.
756
  if (module_exists('microdata')) {
757
    $microdata = $entity->microdata[$field['field_name']];
758
  }
759
  // If microdata is not enabled, add empty arrays for each property so we
760
  // don't have to check later in the theme functions.
761
  else {
762
    $microdata = array(
763
      '#attributes' => array(),
764
    );
765
    // If Entity API is enabled, we can use that to get the properties.
766
    // Otherwise, replicate the Entity API logic for getting the properties.
767
    if (module_exists('entity')) {
768
      $entity_info = entity_get_all_property_info($entity_type);
769
    }
770
    else {
771
      $info = array();
772
      $info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']] = array();
773
      fivestar_property_info_callback($info, $entity_type, $field, $instance, 'fivestar');
774
      $entity_info = $info[$entity_type]['bundles'][$instance['bundle']]['properties'];
775
    }
776
    foreach ($entity_info[$field['field_name']]['property info'] as $property_name => $property) {
777
      $microdata[$property_name]['#attributes'] = array();
778
    }
779
  }
780

    
781
  return $microdata;
782
}