Projet

Général

Profil

Paste
Télécharger (58,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / views / handlers / views_handler_field.inc @ 4003efde

1 85ad3d82 Assos Assos
<?php
2
3
/**
4
 * @file
5 5d12d676 Assos Assos
 * Definition of views_handler_field.
6 85ad3d82 Assos Assos
 */
7
8
/**
9
 * @defgroup views_field_handlers Views field handlers
10
 * @{
11
 * Handlers to tell Views how to build and display fields.
12
 */
13
14
/**
15
 * Indicator of the render_text() method for rendering a single item.
16 5d12d676 Assos Assos
 *
17
 * If no render_item() is present.
18 85ad3d82 Assos Assos
 */
19
define('VIEWS_HANDLER_RENDER_TEXT_PHASE_SINGLE_ITEM', 0);
20
21
/**
22
 * Indicator of the render_text() method for rendering the whole element.
23 5d12d676 Assos Assos
 *
24
 * if no render_item() method is available.
25 85ad3d82 Assos Assos
 */
26
define('VIEWS_HANDLER_RENDER_TEXT_PHASE_COMPLETELY', 1);
27
28
/**
29
 * Indicator of the render_text() method for rendering the empty text.
30
 */
31
define('VIEWS_HANDLER_RENDER_TEXT_PHASE_EMPTY', 2);
32
33
/**
34
 * Base field handler that has no options and renders an unformatted field.
35
 *
36
 * Definition terms:
37
 * - additional fields: An array of fields that should be added to the query
38 5d12d676 Assos Assos
 *   for some purpose. The array is in the form of:
39
 *   array(
40
 *     'identifier' => array(
41
 *       'table' => tablename,
42
 *       'field' => fieldname,
43
 *     )
44
 *   );
45
 *   with as many fields as are necessary may be in this array.
46 85ad3d82 Assos Assos
 * - click sortable: If TRUE, this field may be click sorted.
47
 *
48
 * @ingroup views_field_handlers
49
 */
50
class views_handler_field extends views_handler {
51 5d12d676 Assos Assos
52
  /**
53
   *
54
   */
55
  public $field_alias = 'unknown';
56
57
  /**
58
   *
59
   */
60
  public $aliases = array();
61 85ad3d82 Assos Assos
62
  /**
63
   * The field value prior to any rewriting.
64
   *
65
   * @var mixed
66
   */
67
  public $original_value = NULL;
68
69
  /**
70
   * @var array
71 8be7bf84 Assos Assos
   * Stores additional fields which get added to the query.
72 85ad3d82 Assos Assos
   * The generated aliases are stored in $aliases.
73
   */
74 5d12d676 Assos Assos
  public $additional_fields = array();
75 85ad3d82 Assos Assos
76
  /**
77
   * Construct a new field handler.
78
   */
79 5d12d676 Assos Assos
  public function construct() {
80 85ad3d82 Assos Assos
    parent::construct();
81
82
    $this->additional_fields = array();
83
    if (!empty($this->definition['additional fields'])) {
84
      $this->additional_fields = $this->definition['additional fields'];
85
    }
86
87
    if (!isset($this->options['exclude'])) {
88
      $this->options['exclude'] = '';
89
    }
90
  }
91
92
  /**
93
   * Determine if this field can allow advanced rendering.
94
   *
95 5d12d676 Assos Assos
   * Fields can set this to FALSE if they do not wish to allow token based
96
   * rewriting or link-making.
97 85ad3d82 Assos Assos
   */
98 5d12d676 Assos Assos
  public function allow_advanced_render() {
99 85ad3d82 Assos Assos
    return TRUE;
100
  }
101
102 5d12d676 Assos Assos
  /**
103
   * {@inheritdoc}
104
   */
105
  public function init(&$view, &$options) {
106 85ad3d82 Assos Assos
    parent::init($view, $options);
107
  }
108
109
  /**
110
   * Called to add the field to a query.
111
   */
112 5d12d676 Assos Assos
  public function query() {
113 85ad3d82 Assos Assos
    $this->ensure_my_table();
114
    // Add the field.
115
    $params = $this->options['group_type'] != 'group' ? array('function' => $this->options['group_type']) : array();
116
    $this->field_alias = $this->query->add_field($this->table_alias, $this->real_field, NULL, $params);
117
118
    $this->add_additional_fields();
119
  }
120
121
  /**
122
   * Add 'additional' fields to the query.
123
   *
124 5d12d676 Assos Assos
   * @param array $fields
125
   *   An array of fields. The key is an identifier used to later find the field
126
   *   alias used. The value is either a string in which case it's assumed to be
127
   *   a field on this handler's table; or it's an array in the form of
128
   *   @code array('table' => $tablename, 'field' => $fieldname) @endcode
129 85ad3d82 Assos Assos
   */
130 5d12d676 Assos Assos
  public function add_additional_fields($fields = NULL) {
131 85ad3d82 Assos Assos
    if (!isset($fields)) {
132 5d12d676 Assos Assos
      // Notice check.
133 85ad3d82 Assos Assos
      if (empty($this->additional_fields)) {
134
        return;
135
      }
136
      $fields = $this->additional_fields;
137
    }
138
139
    $group_params = array();
140
    if ($this->options['group_type'] != 'group') {
141
      $group_params = array(
142
        'function' => $this->options['group_type'],
143
      );
144
    }
145
146
    if (!empty($fields) && is_array($fields)) {
147
      foreach ($fields as $identifier => $info) {
148
        if (is_array($info)) {
149
          if (isset($info['table'])) {
150
            $table_alias = $this->query->ensure_table($info['table'], $this->relationship);
151
          }
152
          else {
153
            $table_alias = $this->table_alias;
154
          }
155
156
          if (empty($table_alias)) {
157 5d12d676 Assos Assos
            $t_args = array(
158
              '@handler' => $this->definition['handler'],
159
              '@identifier' => $identifier,
160
              '@table' => $info['table'],
161
            );
162 4003efde Assos Assos
            debug(t('Handler @handler tried to add additional field @identifier but @table could not be added.', $t_args));
163 85ad3d82 Assos Assos
            $this->aliases[$identifier] = 'broken';
164
            continue;
165
          }
166
167
          $params = array();
168
          if (!empty($info['params'])) {
169
            $params = $info['params'];
170
          }
171
172
          $params += $group_params;
173
          $this->aliases[$identifier] = $this->query->add_field($table_alias, $info['field'], NULL, $params);
174
        }
175
        else {
176
          $this->aliases[$info] = $this->query->add_field($this->table_alias, $info, NULL, $group_params);
177
        }
178
      }
179
    }
180
  }
181
182
  /**
183
   * Called to determine what to tell the clicksorter.
184
   */
185 5d12d676 Assos Assos
  public function click_sort($order) {
186 85ad3d82 Assos Assos
    if (isset($this->field_alias)) {
187
      // Since fields should always have themselves already added, just
188
      // add a sort on the field.
189
      $params = $this->options['group_type'] != 'group' ? array('function' => $this->options['group_type']) : array();
190
      $this->query->add_orderby(NULL, NULL, $order, $this->field_alias, $params);
191
    }
192
  }
193
194
  /**
195
   * Determine if this field is click sortable.
196
   */
197 5d12d676 Assos Assos
  public function click_sortable() {
198 85ad3d82 Assos Assos
    return !empty($this->definition['click sortable']);
199
  }
200
201
  /**
202
   * Get this field's label.
203
   */
204 5d12d676 Assos Assos
  public function label() {
205 85ad3d82 Assos Assos
    if (!isset($this->options['label'])) {
206
      return '';
207
    }
208
    return $this->options['label'];
209
  }
210
211
  /**
212
   * Return an HTML element based upon the field's element type.
213
   */
214 5d12d676 Assos Assos
  public function element_type($none_supported = FALSE, $default_empty = FALSE, $inline = FALSE) {
215 85ad3d82 Assos Assos
    if ($none_supported) {
216
      if ($this->options['element_type'] === '0') {
217
        return '';
218
      }
219
    }
220
    if ($this->options['element_type']) {
221
      return check_plain($this->options['element_type']);
222
    }
223
224
    if ($default_empty) {
225
      return '';
226
    }
227
228
    if ($inline) {
229
      return 'span';
230
    }
231
232
    if (isset($this->definition['element type'])) {
233
      return $this->definition['element type'];
234
    }
235
236
    return 'span';
237
  }
238
239
  /**
240
   * Return an HTML element for the label based upon the field's element type.
241
   */
242 5d12d676 Assos Assos
  public function element_label_type($none_supported = FALSE, $default_empty = FALSE) {
243 85ad3d82 Assos Assos
    if ($none_supported) {
244
      if ($this->options['element_label_type'] === '0') {
245
        return '';
246
      }
247
    }
248
    if ($this->options['element_label_type']) {
249
      return check_plain($this->options['element_label_type']);
250
    }
251
252
    if ($default_empty) {
253
      return '';
254
    }
255
256
    return 'span';
257
  }
258
259
  /**
260
   * Return an HTML element for the wrapper based upon the field's element type.
261
   */
262 5d12d676 Assos Assos
  public function element_wrapper_type($none_supported = FALSE, $default_empty = FALSE) {
263 85ad3d82 Assos Assos
    if ($none_supported) {
264
      if ($this->options['element_wrapper_type'] === '0') {
265
        return 0;
266
      }
267
    }
268
    if ($this->options['element_wrapper_type']) {
269
      return check_plain($this->options['element_wrapper_type']);
270
    }
271
272
    if ($default_empty) {
273
      return '';
274
    }
275
276
    return 'div';
277
  }
278
279
  /**
280
   * Provide a list of elements valid for field HTML.
281
   *
282 5d12d676 Assos Assos
   * This function can be overridden by fields that want more or fewer elements
283
   * available, though this seems like it would be an incredibly rare occurence.
284 85ad3d82 Assos Assos
   */
285 5d12d676 Assos Assos
  public function get_elements() {
286 85ad3d82 Assos Assos
    static $elements = NULL;
287
    if (!isset($elements)) {
288
      $elements = variable_get('views_field_rewrite_elements', array(
289
        '' => t('- Use default -'),
290
        '0' => t('- None -'),
291
        'div' => 'DIV',
292
        'span' => 'SPAN',
293
        'h1' => 'H1',
294
        'h2' => 'H2',
295
        'h3' => 'H3',
296
        'h4' => 'H4',
297
        'h5' => 'H5',
298
        'h6' => 'H6',
299
        'p' => 'P',
300
        'strong' => 'STRONG',
301
        'em' => 'EM',
302
      ));
303
    }
304
305
    return $elements;
306
  }
307
308
  /**
309
   * Return the class of the field.
310
   */
311 5d12d676 Assos Assos
  public function element_classes($row_index = NULL) {
312 85ad3d82 Assos Assos
    $classes = explode(' ', $this->options['element_class']);
313
    foreach ($classes as &$class) {
314
      $class = $this->tokenize_value($class, $row_index);
315
      $class = views_clean_css_identifier($class);
316
    }
317
    return implode(' ', $classes);
318
  }
319
320
  /**
321
   * Replace a value with tokens from the last field.
322
   *
323
   * This function actually figures out which field was last and uses its
324
   * tokens so they will all be available.
325
   */
326 5d12d676 Assos Assos
  public function tokenize_value($value, $row_index = NULL) {
327 85ad3d82 Assos Assos
    if (strpos($value, '[') !== FALSE || strpos($value, '!') !== FALSE || strpos($value, '%') !== FALSE) {
328
      $fake_item = array(
329
        'alter_text' => TRUE,
330
        'text' => $value,
331
      );
332
333 5d12d676 Assos Assos
      // Use isset() because empty() will trigger on 0 and 0 is the first row.
334 85ad3d82 Assos Assos
      if (isset($row_index) && isset($this->view->style_plugin->render_tokens[$row_index])) {
335
        $tokens = $this->view->style_plugin->render_tokens[$row_index];
336
      }
337
      else {
338
        // Get tokens from the last field.
339
        $last_field = end($this->view->field);
340
        if (isset($last_field->last_tokens)) {
341
          $tokens = $last_field->last_tokens;
342
        }
343
        else {
344
          $tokens = $last_field->get_render_tokens($fake_item);
345
        }
346
      }
347
348
      $value = strip_tags($this->render_altered($fake_item, $tokens));
349
      if (!empty($this->options['alter']['trim_whitespace'])) {
350
        $value = trim($value);
351
      }
352
    }
353
354
    return $value;
355
  }
356
357
  /**
358
   * Return the class of the field's label.
359
   */
360 5d12d676 Assos Assos
  public function element_label_classes($row_index = NULL) {
361 85ad3d82 Assos Assos
    $classes = explode(' ', $this->options['element_label_class']);
362
    foreach ($classes as &$class) {
363
      $class = $this->tokenize_value($class, $row_index);
364
      $class = views_clean_css_identifier($class);
365
    }
366
    return implode(' ', $classes);
367
  }
368
369
  /**
370
   * Return the class of the field's wrapper.
371
   */
372 5d12d676 Assos Assos
  public function element_wrapper_classes($row_index = NULL) {
373 85ad3d82 Assos Assos
    $classes = explode(' ', $this->options['element_wrapper_class']);
374
    foreach ($classes as &$class) {
375
      $class = $this->tokenize_value($class, $row_index);
376
      $class = views_clean_css_identifier($class);
377
    }
378
    return implode(' ', $classes);
379
  }
380
381
  /**
382
   * Get the value that's supposed to be rendered.
383
   *
384
   * This api exists so that other modules can easy set the values of the field
385
   * without having the need to change the render method as well.
386
   *
387 5d12d676 Assos Assos
   * @param object $values
388 85ad3d82 Assos Assos
   *   An object containing all retrieved values.
389 5d12d676 Assos Assos
   * @param string $field
390 85ad3d82 Assos Assos
   *   Optional name of the field where the value is stored.
391
   */
392 5d12d676 Assos Assos
  public function get_value($values, $field = NULL) {
393 85ad3d82 Assos Assos
    $alias = isset($field) ? $this->aliases[$field] : $this->field_alias;
394
    if (isset($values->{$alias})) {
395
      return $values->{$alias};
396
    }
397
  }
398
399
  /**
400
   * Determines if this field will be available as an option to group the result
401
   * by in the style settings.
402
   *
403
   * @return bool
404 5d12d676 Assos Assos
   *   TRUE if this field handler is groupable, otherwise FALSE.
405 85ad3d82 Assos Assos
   */
406 5d12d676 Assos Assos
  public function use_string_group_by() {
407 85ad3d82 Assos Assos
    return TRUE;
408
  }
409
410 5d12d676 Assos Assos
  /**
411
   * {@inheritdoc}
412
   */
413
  public function option_definition() {
414 85ad3d82 Assos Assos
    $options = parent::option_definition();
415
416
    $options['label'] = array('default' => $this->definition['title'], 'translatable' => TRUE);
417
    $options['exclude'] = array('default' => FALSE, 'bool' => TRUE);
418
    $options['alter'] = array(
419
      'contains' => array(
420
        'alter_text' => array('default' => FALSE, 'bool' => TRUE),
421
        'text' => array('default' => '', 'translatable' => TRUE),
422
        'make_link' => array('default' => FALSE, 'bool' => TRUE),
423
        'path' => array('default' => ''),
424
        'absolute' => array('default' => FALSE, 'bool' => TRUE),
425
        'external' => array('default' => FALSE, 'bool' => TRUE),
426
        'replace_spaces' => array('default' => FALSE, 'bool' => TRUE),
427 8be7bf84 Assos Assos
        'unwanted_characters' => array('default' => ''),
428 85ad3d82 Assos Assos
        'path_case' => array('default' => 'none', 'translatable' => FALSE),
429
        'trim_whitespace' => array('default' => FALSE, 'bool' => TRUE),
430
        'alt' => array('default' => '', 'translatable' => TRUE),
431
        'rel' => array('default' => ''),
432
        'link_class' => array('default' => ''),
433
        'prefix' => array('default' => '', 'translatable' => TRUE),
434
        'suffix' => array('default' => '', 'translatable' => TRUE),
435
        'target' => array('default' => ''),
436
        'nl2br' => array('default' => FALSE, 'bool' => TRUE),
437
        'max_length' => array('default' => ''),
438
        'word_boundary' => array('default' => TRUE, 'bool' => TRUE),
439
        'ellipsis' => array('default' => TRUE, 'bool' => TRUE),
440
        'more_link' => array('default' => FALSE, 'bool' => TRUE),
441
        'more_link_text' => array('default' => '', 'translatable' => TRUE),
442
        'more_link_path' => array('default' => ''),
443
        'strip_tags' => array('default' => FALSE, 'bool' => TRUE),
444
        'trim' => array('default' => FALSE, 'bool' => TRUE),
445
        'preserve_tags' => array('default' => ''),
446
        'html' => array('default' => FALSE, 'bool' => TRUE),
447
      ),
448
    );
449
    $options['element_type'] = array('default' => '');
450
    $options['element_class'] = array('default' => '');
451
452
    $options['element_label_type'] = array('default' => '');
453
    $options['element_label_class'] = array('default' => '');
454
    $options['element_label_colon'] = array('default' => TRUE, 'bool' => TRUE);
455
456
    $options['element_wrapper_type'] = array('default' => '');
457
    $options['element_wrapper_class'] = array('default' => '');
458
459
    $options['element_default_classes'] = array('default' => TRUE, 'bool' => TRUE);
460
461
    $options['empty'] = array('default' => '', 'translatable' => TRUE);
462
    $options['hide_empty'] = array('default' => FALSE, 'bool' => TRUE);
463
    $options['empty_zero'] = array('default' => FALSE, 'bool' => TRUE);
464
    $options['hide_alter_empty'] = array('default' => TRUE, 'bool' => TRUE);
465
466
    return $options;
467
  }
468
469
  /**
470
   * Performs some cleanup tasks on the options array before saving it.
471
   */
472 5d12d676 Assos Assos
  public function options_submit(&$form, &$form_state) {
473 85ad3d82 Assos Assos
    $options = &$form_state['values']['options'];
474 5d12d676 Assos Assos
    $types = array(
475
      'element_type',
476
      'element_label_type',
477
      'element_wrapper_type',
478
    );
479
    $base_types = array(
480
      'element_class',
481
      'element_label_class',
482
      'element_wrapper_class',
483
    );
484
    $classes = array_combine($base_types, $types);
485 85ad3d82 Assos Assos
486
    foreach ($types as $type) {
487
      if (!$options[$type . '_enable']) {
488
        $options[$type] = '';
489
      }
490
    }
491
492
    foreach ($classes as $class => $type) {
493
      if (!$options[$class . '_enable'] || !$options[$type . '_enable']) {
494
        $options[$class] = '';
495
      }
496
    }
497
498
    if (empty($options['custom_label'])) {
499
      $options['label'] = '';
500
      $options['element_label_colon'] = FALSE;
501
    }
502
  }
503
504
  /**
505 5d12d676 Assos Assos
   * Default options form provides the label widget that all fields should have.
506 85ad3d82 Assos Assos
   */
507 5d12d676 Assos Assos
  public function options_form(&$form, &$form_state) {
508 85ad3d82 Assos Assos
    parent::options_form($form, $form_state);
509
510
    $label = $this->label();
511
    $form['custom_label'] = array(
512
      '#type' => 'checkbox',
513
      '#title' => t('Create a label'),
514
      '#description' => t('Enable to create a label for this field.'),
515
      '#default_value' => $label !== '',
516
      '#weight' => -103,
517
    );
518
    $form['label'] = array(
519
      '#type' => 'textfield',
520
      '#title' => t('Label'),
521
      '#default_value' => $label,
522
      '#dependency' => array(
523
        'edit-options-custom-label' => array(1),
524
      ),
525
      '#weight' => -102,
526
    );
527
    $form['element_label_colon'] = array(
528
      '#type' => 'checkbox',
529
      '#title' => t('Place a colon after the label'),
530
      '#default_value' => $this->options['element_label_colon'],
531
      '#dependency' => array(
532
        'edit-options-custom-label' => array(1),
533
      ),
534
      '#weight' => -101,
535
    );
536
537
    $form['exclude'] = array(
538
      '#type' => 'checkbox',
539
      '#title' => t('Exclude from display'),
540
      '#default_value' => $this->options['exclude'],
541
      '#description' => t('Enable to load this field as hidden. Often used to group fields, or to use as token in another field.'),
542
      '#weight' => -100,
543
    );
544
545
    $form['style_settings'] = array(
546
      '#type' => 'fieldset',
547
      '#title' => t('Style settings'),
548
      '#collapsible' => TRUE,
549
      '#collapsed' => TRUE,
550
      '#weight' => 99,
551
    );
552
553
    $form['element_type_enable'] = array(
554
      '#type' => 'checkbox',
555
      '#title' => t('Customize field HTML'),
556
      '#default_value' => !empty($this->options['element_type']) || (string) $this->options['element_type'] == '0' || !empty($this->options['element_class']) || (string) $this->options['element_class'] == '0',
557
      '#fieldset' => 'style_settings',
558
    );
559
    $form['element_type'] = array(
560
      '#title' => t('HTML element'),
561
      '#options' => $this->get_elements(),
562
      '#type' => 'select',
563
      '#default_value' => $this->options['element_type'],
564
      '#description' => t('Choose the HTML element to wrap around this field, e.g. H1, H2, etc.'),
565
      '#dependency' => array(
566
        'edit-options-element-type-enable' => array(1),
567
      ),
568
      '#fieldset' => 'style_settings',
569
    );
570
571
    $form['element_class_enable'] = array(
572
      '#type' => 'checkbox',
573
      '#title' => t('Create a CSS class'),
574
      '#dependency' => array(
575
        'edit-options-element-type-enable' => array(1),
576
      ),
577
      '#default_value' => !empty($this->options['element_class']) || (string) $this->options['element_class'] == '0',
578
      '#fieldset' => 'style_settings',
579
    );
580
    $form['element_class'] = array(
581
      '#title' => t('CSS class'),
582
      '#description' => t('You may use token substitutions from the rewriting section in this class.'),
583
      '#type' => 'textfield',
584
      '#default_value' => $this->options['element_class'],
585
      '#dependency' => array(
586
        'edit-options-element-class-enable' => array(1),
587
        'edit-options-element-type-enable' => array(1),
588
      ),
589
      '#dependency_count' => 2,
590
      '#fieldset' => 'style_settings',
591
    );
592
593
    $form['element_label_type_enable'] = array(
594
      '#type' => 'checkbox',
595
      '#title' => t('Customize label HTML'),
596
      '#default_value' => !empty($this->options['element_label_type']) || (string) $this->options['element_label_type'] == '0' || !empty($this->options['element_label_class']) || (string) $this->options['element_label_class'] == '0',
597
      '#fieldset' => 'style_settings',
598
    );
599
    $form['element_label_type'] = array(
600
      '#title' => t('Label HTML element'),
601
      '#options' => $this->get_elements(FALSE),
602
      '#type' => 'select',
603
      '#default_value' => $this->options['element_label_type'],
604
      '#description' => t('Choose the HTML element to wrap around this label, e.g. H1, H2, etc.'),
605
      '#dependency' => array(
606
        'edit-options-element-label-type-enable' => array(1),
607
      ),
608
      '#fieldset' => 'style_settings',
609
    );
610
    $form['element_label_class_enable'] = array(
611
      '#type' => 'checkbox',
612
      '#title' => t('Create a CSS class'),
613
      '#dependency' => array(
614 5d12d676 Assos Assos
        'edit-options-element-label-type-enable' => array(1),
615 85ad3d82 Assos Assos
      ),
616
      '#default_value' => !empty($this->options['element_label_class']) || (string) $this->options['element_label_class'] == '0',
617
      '#fieldset' => 'style_settings',
618
    );
619
    $form['element_label_class'] = array(
620
      '#title' => t('CSS class'),
621
      '#description' => t('You may use token substitutions from the rewriting section in this class.'),
622
      '#type' => 'textfield',
623
      '#default_value' => $this->options['element_label_class'],
624
      '#dependency' => array(
625
        'edit-options-element-label-class-enable' => array(1),
626
        'edit-options-element-label-type-enable' => array(1),
627
      ),
628
      '#dependency_count' => 2,
629
      '#fieldset' => 'style_settings',
630
    );
631
632
    $form['element_wrapper_type_enable'] = array(
633
      '#type' => 'checkbox',
634
      '#title' => t('Customize field and label wrapper HTML'),
635
      '#default_value' => !empty($this->options['element_wrapper_type']) || (string) $this->options['element_wrapper_type'] == '0' || !empty($this->options['element_wrapper_class']) || (string) $this->options['element_wrapper_class'] == '0',
636
      '#fieldset' => 'style_settings',
637
    );
638
    $form['element_wrapper_type'] = array(
639
      '#title' => t('Wrapper HTML element'),
640
      '#options' => $this->get_elements(FALSE),
641
      '#type' => 'select',
642
      '#default_value' => $this->options['element_wrapper_type'],
643
      '#description' => t('Choose the HTML element to wrap around this field and label, e.g. H1, H2, etc. This may not be used if the field and label are not rendered together, such as with a table.'),
644
      '#dependency' => array(
645
        'edit-options-element-wrapper-type-enable' => array(1),
646
      ),
647
      '#fieldset' => 'style_settings',
648
    );
649
650
    $form['element_wrapper_class_enable'] = array(
651
      '#type' => 'checkbox',
652
      '#title' => t('Create a CSS class'),
653
      '#dependency' => array(
654
        'edit-options-element-wrapper-type-enable' => array(1),
655
      ),
656
      '#default_value' => !empty($this->options['element_wrapper_class']) || (string) $this->options['element_wrapper_class'] == '0',
657
      '#fieldset' => 'style_settings',
658
    );
659
    $form['element_wrapper_class'] = array(
660
      '#title' => t('CSS class'),
661
      '#description' => t('You may use token substitutions from the rewriting section in this class.'),
662
      '#type' => 'textfield',
663
      '#default_value' => $this->options['element_wrapper_class'],
664
      '#dependency' => array(
665
        'edit-options-element-wrapper-class-enable' => array(1),
666
        'edit-options-element-wrapper-type-enable' => array(1),
667
      ),
668
      '#dependency_count' => 2,
669
      '#fieldset' => 'style_settings',
670
    );
671
672
    $form['element_default_classes'] = array(
673
      '#type' => 'checkbox',
674
      '#title' => t('Add default classes'),
675
      '#default_value' => $this->options['element_default_classes'],
676
      '#description' => t('Use default Views classes to identify the field, field label and field content.'),
677
      '#fieldset' => 'style_settings',
678
    );
679
680
    $form['alter'] = array(
681
      '#title' => t('Rewrite results'),
682
      '#type' => 'fieldset',
683
      '#collapsible' => TRUE,
684
      '#collapsed' => TRUE,
685
      '#weight' => 100,
686
    );
687
688
    if ($this->allow_advanced_render()) {
689
      $form['alter']['#tree'] = TRUE;
690
      $form['alter']['alter_text'] = array(
691
        '#type' => 'checkbox',
692
        '#title' => t('Rewrite the output of this field'),
693
        '#description' => t('Enable to override the output of this field with custom text or replacement tokens.'),
694
        '#default_value' => $this->options['alter']['alter_text'],
695
      );
696
697
      $form['alter']['text'] = array(
698
        '#title' => t('Text'),
699
        '#type' => 'textarea',
700
        '#default_value' => $this->options['alter']['text'],
701
        '#description' => t('The text to display for this field. You may include HTML. You may enter data from this view as per the "Replacement patterns" below.'),
702
        '#dependency' => array(
703
          'edit-options-alter-alter-text' => array(1),
704
        ),
705
      );
706
707
      $form['alter']['make_link'] = array(
708
        '#type' => 'checkbox',
709
        '#title' => t('Output this field as a link'),
710
        '#description' => t('If checked, this field will be made into a link. The destination must be given below.'),
711
        '#default_value' => $this->options['alter']['make_link'],
712
      );
713
      $form['alter']['path'] = array(
714
        '#title' => t('Link path'),
715
        '#type' => 'textfield',
716
        '#default_value' => $this->options['alter']['path'],
717
        '#description' => t('The Drupal path or absolute URL for this link. You may enter data from this view as per the "Replacement patterns" below.'),
718
        '#dependency' => array(
719
          'edit-options-alter-make-link' => array(1),
720
        ),
721
        '#maxlength' => 255,
722
      );
723
      $form['alter']['absolute'] = array(
724
        '#type' => 'checkbox',
725
        '#title' => t('Use absolute path'),
726
        '#default_value' => $this->options['alter']['absolute'],
727
        '#dependency' => array(
728
          'edit-options-alter-make-link' => array(1),
729
        ),
730
      );
731
      $form['alter']['replace_spaces'] = array(
732
        '#type' => 'checkbox',
733
        '#title' => t('Replace spaces with dashes'),
734
        '#default_value' => $this->options['alter']['replace_spaces'],
735
        '#dependency' => array(
736 5d12d676 Assos Assos
          'edit-options-alter-make-link' => array(1),
737 85ad3d82 Assos Assos
        ),
738
      );
739
      $form['alter']['external'] = array(
740
        '#type' => 'checkbox',
741
        '#title' => t('External server URL'),
742
        '#default_value' => $this->options['alter']['external'],
743
        '#description' => t("Links to an external server using a full URL: e.g. 'http://www.example.com' or 'www.example.com'."),
744
        '#dependency' => array(
745
          'edit-options-alter-make-link' => array(1),
746
        ),
747
      );
748 8be7bf84 Assos Assos
      $form['alter']['unwanted_characters'] = array(
749
        '#type' => 'textfield',
750
        '#title' => t('Remove unwanted characters'),
751
        '#description' => t('Space-separated list of characters to remove from the URL path'),
752
        '#default_value' => $this->options['alter']['unwanted_characters'],
753
        '#dependency' => array(
754
          'edit-options-alter-make-link' => array(1)
755
        ),
756
        '#maxlength' => 255,
757
      );
758 85ad3d82 Assos Assos
      $form['alter']['path_case'] = array(
759
        '#type' => 'select',
760
        '#title' => t('Transform the case'),
761
        '#description' => t('When printing url paths, how to transform the case of the filter value.'),
762
        '#dependency' => array(
763
          'edit-options-alter-make-link' => array(1),
764
        ),
765 5d12d676 Assos Assos
        '#options' => array(
766 85ad3d82 Assos Assos
          'none' => t('No transform'),
767
          'upper' => t('Upper case'),
768
          'lower' => t('Lower case'),
769
          'ucfirst' => t('Capitalize first letter'),
770
          'ucwords' => t('Capitalize each word'),
771
        ),
772
        '#default_value' => $this->options['alter']['path_case'],
773
      );
774
      $form['alter']['link_class'] = array(
775
        '#title' => t('Link class'),
776
        '#type' => 'textfield',
777
        '#default_value' => $this->options['alter']['link_class'],
778
        '#description' => t('The CSS class to apply to the link.'),
779
        '#dependency' => array(
780
          'edit-options-alter-make-link' => array(1),
781
        ),
782
      );
783
      $form['alter']['alt'] = array(
784
        '#title' => t('Title text'),
785
        '#type' => 'textfield',
786
        '#default_value' => $this->options['alter']['alt'],
787
        '#description' => t('Text to place as "title" text which most browsers display as a tooltip when hovering over the link.'),
788
        '#dependency' => array(
789
          'edit-options-alter-make-link' => array(1),
790
        ),
791
      );
792
      $form['alter']['rel'] = array(
793
        '#title' => t('Rel Text'),
794
        '#type' => 'textfield',
795
        '#default_value' => $this->options['alter']['rel'],
796 8be7bf84 Assos Assos
        '#description' => t('Include Rel attribute for use in lightbox2 or other JavaScript utility.'),
797 85ad3d82 Assos Assos
        '#dependency' => array(
798
          'edit-options-alter-make-link' => array(1),
799
        ),
800
      );
801
      $form['alter']['prefix'] = array(
802
        '#title' => t('Prefix text'),
803
        '#type' => 'textfield',
804
        '#default_value' => $this->options['alter']['prefix'],
805
        '#description' => t('Any text to display before this link. You may include HTML.'),
806
        '#dependency' => array(
807
          'edit-options-alter-make-link' => array(1),
808
        ),
809
      );
810
      $form['alter']['suffix'] = array(
811
        '#title' => t('Suffix text'),
812
        '#type' => 'textfield',
813
        '#default_value' => $this->options['alter']['suffix'],
814
        '#description' => t('Any text to display after this link. You may include HTML.'),
815
        '#dependency' => array(
816
          'edit-options-alter-make-link' => array(1),
817
        ),
818
      );
819
      $form['alter']['target'] = array(
820
        '#title' => t('Target'),
821
        '#type' => 'textfield',
822
        '#default_value' => $this->options['alter']['target'],
823
        '#description' => t("Target of the link, such as _blank, _parent or an iframe's name. This field is rarely used."),
824
        '#dependency' => array(
825
          'edit-options-alter-make-link' => array(1),
826
        ),
827
      );
828
829
830
      // Get a list of the available fields and arguments for token replacement.
831
      $options = array();
832
      foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
833
        $options[t('Fields')]["[$field]"] = $handler->ui_name();
834
        // We only use fields up to (and including) this one.
835
        if ($field == $this->options['id']) {
836
          break;
837
        }
838
      }
839 5d12d676 Assos Assos
      // This lets us prepare the key as we want it printed.
840
      $count = 0;
841 85ad3d82 Assos Assos
      foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
842
        $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->ui_name()));
843
        $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->ui_name()));
844
      }
845
846
      $this->document_self_tokens($options[t('Fields')]);
847
848
      // Default text.
849
      $output = t('<p>You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.</p>');
850
      // We have some options, so make a list.
851
      if (!empty($options)) {
852
        $output = t('<p>The following tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.
853
If you would like to have the characters \'[\' and \']\' please use the html entity codes \'%5B\' or  \'%5D\' or they will get replaced with empty space.</p>');
854
        foreach (array_keys($options) as $type) {
855
          if (!empty($options[$type])) {
856
            $items = array();
857
            foreach ($options[$type] as $key => $value) {
858
              $items[] = $key . ' == ' . check_plain($value);
859
            }
860
            $output .= theme('item_list',
861
              array(
862
                'items' => $items,
863 5d12d676 Assos Assos
                'type' => $type,
864 85ad3d82 Assos Assos
              ));
865
          }
866
        }
867
      }
868
      // This construct uses 'hidden' and not markup because process doesn't
869 5d12d676 Assos Assos
      // run. It also has an extra div because the dependency wants to hide the
870
      // parent in situations like this, so we need a second div to make this
871
      // work.
872 85ad3d82 Assos Assos
      $form['alter']['help'] = array(
873
        '#type' => 'fieldset',
874
        '#title' => t('Replacement patterns'),
875
        '#collapsible' => TRUE,
876
        '#collapsed' => TRUE,
877
        '#value' => $output,
878
        '#dependency' => array(
879
          'edit-options-alter-make-link' => array(1),
880
          'edit-options-alter-alter-text' => array(1),
881
          'edit-options-alter-more-link' => array(1),
882
        ),
883
      );
884
885
      $form['alter']['trim'] = array(
886
        '#type' => 'checkbox',
887
        '#title' => t('Trim this field to a maximum length'),
888
        '#description' => t('Enable to trim the field to a maximum length of characters'),
889
        '#default_value' => $this->options['alter']['trim'],
890
      );
891
892
      $form['alter']['max_length'] = array(
893
        '#title' => t('Maximum length'),
894
        '#type' => 'textfield',
895
        '#default_value' => $this->options['alter']['max_length'],
896
        '#description' => t('The maximum number of characters this field can be.'),
897
        '#dependency' => array(
898
          'edit-options-alter-trim' => array(1),
899
        ),
900
      );
901
902
      $form['alter']['word_boundary'] = array(
903
        '#type' => 'checkbox',
904
        '#title' => t('Trim only on a word boundary'),
905
        '#description' => t('If checked, this field be trimmed only on a word boundary. This is guaranteed to be the maximum characters stated or less. If there are no word boundaries this could trim a field to nothing.'),
906
        '#default_value' => $this->options['alter']['word_boundary'],
907
        '#dependency' => array(
908
          'edit-options-alter-trim' => array(1),
909
        ),
910
      );
911
912
      $form['alter']['ellipsis'] = array(
913
        '#type' => 'checkbox',
914
        '#title' => t('Add an ellipsis'),
915
        '#description' => t('If checked, a "..." will be added if a field was trimmed.'),
916
        '#default_value' => $this->options['alter']['ellipsis'],
917
        '#dependency' => array(
918
          'edit-options-alter-trim' => array(1),
919
        ),
920
      );
921
922
      $form['alter']['more_link'] = array(
923
        '#type' => 'checkbox',
924
        '#title' => t('Add a read-more link if output is trimmed.'),
925
        '#description' => t('If checked, a read-more link will be added at the end of the trimmed output'),
926
        '#default_value' => $this->options['alter']['more_link'],
927
        '#dependency' => array(
928
          'edit-options-alter-trim' => array(1),
929
        ),
930
      );
931
932
      $form['alter']['more_link_text'] = array(
933
        '#type' => 'textfield',
934
        '#title' => t('More link text'),
935
        '#default_value' => $this->options['alter']['more_link_text'],
936
        '#description' => t('The text which will be displayed on the more link. You may enter data from this view as per the "Replacement patterns" above.'),
937
        '#dependency_count' => 2,
938
        '#dependency' => array(
939
          'edit-options-alter-trim' => array(1),
940
          'edit-options-alter-more-link' => array(1),
941
        ),
942
      );
943
      $form['alter']['more_link_path'] = array(
944
        '#type' => 'textfield',
945
        '#title' => t('More link path'),
946
        '#default_value' => $this->options['alter']['more_link_path'],
947
        '#description' => t('The path which is used for the more link. You may enter data from this view as per the "Replacement patterns" above.'),
948
        '#dependency_count' => 2,
949
        '#dependency' => array(
950
          'edit-options-alter-trim' => array(1),
951
          'edit-options-alter-more-link' => array(1),
952
        ),
953
      );
954
955
      $form['alter']['html'] = array(
956
        '#type' => 'checkbox',
957
        '#title' => t('Field can contain HTML'),
958
        '#description' => t('If checked, HTML corrector will be run to ensure tags are properly closed after trimming.'),
959
        '#default_value' => $this->options['alter']['html'],
960
        '#dependency' => array(
961
          'edit-options-alter-trim' => array(1),
962
        ),
963
      );
964
965
      $form['alter']['strip_tags'] = array(
966
        '#type' => 'checkbox',
967
        '#title' => t('Strip HTML tags'),
968
        '#description' => t('If checked, all HTML tags will be stripped.'),
969
        '#default_value' => $this->options['alter']['strip_tags'],
970
      );
971
972
      $form['alter']['preserve_tags'] = array(
973
        '#type' => 'textfield',
974
        '#title' => t('Preserve certain tags'),
975
        '#description' => t('List the tags that need to be preserved during the stripping process. example &quot;&lt;p&gt; &lt;br&gt;&quot; which will preserve all p and br elements'),
976
        '#default_value' => $this->options['alter']['preserve_tags'],
977
        '#dependency' => array(
978
          'edit-options-alter-strip-tags' => array(1),
979
        ),
980
      );
981
982
      $form['alter']['trim_whitespace'] = array(
983
        '#type' => 'checkbox',
984
        '#title' => t('Remove whitespace'),
985
        '#description' => t('If checked, all whitespaces at the beginning and the end of the output will be removed.'),
986
        '#default_value' => $this->options['alter']['trim_whitespace'],
987
      );
988
989
      $form['alter']['nl2br'] = array(
990
        '#type' => 'checkbox',
991
        '#title' => t('Convert newlines to HTML &lt;br&gt; tags'),
992
        '#description' => t('If checked, all newlines chars (e.g. \n) are converted into HTML &lt;br&gt; tags.'),
993
        '#default_value' => $this->options['alter']['nl2br'],
994
      );
995
    }
996
997
    $form['empty_field_behavior'] = array(
998
      '#type' => 'fieldset',
999
      '#title' => t('No results behavior'),
1000
      '#collapsible' => TRUE,
1001
      '#collapsed' => TRUE,
1002
      '#weight' => 100,
1003
    );
1004
1005
    $form['empty'] = array(
1006
      '#type' => 'textarea',
1007
      '#title' => t('No results text'),
1008
      '#default_value' => $this->options['empty'],
1009
      '#description' => t('Provide text to display if this field contains an empty result. You may include HTML. You may enter data from this view as per the "Replacement patterns" in the "Rewrite Results" section below.'),
1010
      '#fieldset' => 'empty_field_behavior',
1011
    );
1012
1013
    $form['empty_zero'] = array(
1014
      '#type' => 'checkbox',
1015
      '#title' => t('Count the number 0 as empty'),
1016
      '#default_value' => $this->options['empty_zero'],
1017
      '#description' => t('Enable to display the "no results text" if the field contains the number 0.'),
1018
      '#fieldset' => 'empty_field_behavior',
1019
    );
1020
1021
    $form['hide_empty'] = array(
1022
      '#type' => 'checkbox',
1023
      '#title' => t('Hide if empty'),
1024
      '#default_value' => $this->options['hide_empty'],
1025
      '#description' => t('Enable to hide this field if it is empty. Note that the field label or rewritten output may still be displayed. To hide labels, check the style or row style settings for empty fields. To hide rewritten content, check the "Hide rewriting if empty" checkbox.'),
1026
      '#fieldset' => 'empty_field_behavior',
1027
    );
1028
1029
    $form['hide_alter_empty'] = array(
1030
      '#type' => 'checkbox',
1031
      '#title' => t('Hide rewriting if empty'),
1032
      '#default_value' => $this->options['hide_alter_empty'],
1033
      '#description' => t('Do not display rewritten content if this field is empty.'),
1034
      '#fieldset' => 'empty_field_behavior',
1035
    );
1036
  }
1037
1038
  /**
1039
   * Provide extra data to the administration form
1040
   */
1041 5d12d676 Assos Assos
  public function admin_summary() {
1042 85ad3d82 Assos Assos
    return $this->label();
1043
  }
1044
1045
  /**
1046
   * Run before any fields are rendered.
1047
   *
1048 5d12d676 Assos Assos
   * This gives the handlers some time to set up before any handler has been
1049
   * rendered.
1050 85ad3d82 Assos Assos
   *
1051 5d12d676 Assos Assos
   * @param array $values
1052 85ad3d82 Assos Assos
   *   An array of all objects returned from the query.
1053
   */
1054 5d12d676 Assos Assos
  public function pre_render(&$values) {
1055
  }
1056 85ad3d82 Assos Assos
1057
  /**
1058
   * Render the field.
1059
   *
1060 5d12d676 Assos Assos
   * @param array $values
1061 85ad3d82 Assos Assos
   *   The values retrieved from the database.
1062
   */
1063 5d12d676 Assos Assos
  public function render($values) {
1064 85ad3d82 Assos Assos
    $value = $this->get_value($values);
1065
    return $this->sanitize_value($value);
1066
  }
1067
1068
  /**
1069
   * Render a field using advanced settings.
1070
   *
1071
   * This renders a field normally, then decides if render-as-link and
1072
   * text-replacement rendering is necessary.
1073
   */
1074 5d12d676 Assos Assos
  public function advanced_render($values) {
1075 85ad3d82 Assos Assos
    if ($this->allow_advanced_render() && method_exists($this, 'render_item')) {
1076
      $raw_items = $this->get_items($values);
1077
      // If there are no items, set the original value to NULL.
1078
      if (empty($raw_items)) {
1079
        $this->original_value = NULL;
1080
      }
1081
    }
1082
    else {
1083
      $value = $this->render($values);
1084
      if (is_array($value)) {
1085
        $value = drupal_render($value);
1086
      }
1087
      $this->last_render = $value;
1088
      $this->original_value = $value;
1089
    }
1090
1091
    if ($this->allow_advanced_render()) {
1092
      $tokens = NULL;
1093
      if (method_exists($this, 'render_item')) {
1094
        $items = array();
1095
        foreach ($raw_items as $count => $item) {
1096
          $value = $this->render_item($count, $item);
1097
          if (is_array($value)) {
1098
            $value = drupal_render($value);
1099
          }
1100
          $this->last_render = $value;
1101
          $this->original_value = $this->last_render;
1102
1103
          $alter = $item + $this->options['alter'];
1104
          $alter['phase'] = VIEWS_HANDLER_RENDER_TEXT_PHASE_SINGLE_ITEM;
1105
          $items[] = $this->render_text($alter);
1106
        }
1107
1108
        $value = $this->render_items($items);
1109
      }
1110
      else {
1111
        $alter = array('phase' => VIEWS_HANDLER_RENDER_TEXT_PHASE_COMPLETELY) + $this->options['alter'];
1112
        $value = $this->render_text($alter);
1113
      }
1114
1115
      if (is_array($value)) {
1116
        $value = drupal_render($value);
1117
      }
1118
      // This happens here so that render_as_link can get the unaltered value of
1119
      // this field as a token rather than the altered value.
1120
      $this->last_render = $value;
1121
    }
1122
1123
    if (empty($this->last_render)) {
1124
      if ($this->is_value_empty($this->last_render, $this->options['empty_zero'], FALSE)) {
1125
        $alter = $this->options['alter'];
1126
        $alter['alter_text'] = 1;
1127
        $alter['text'] = $this->options['empty'];
1128
        $alter['phase'] = VIEWS_HANDLER_RENDER_TEXT_PHASE_EMPTY;
1129
        $this->last_render = $this->render_text($alter);
1130
      }
1131
    }
1132
1133
    return $this->last_render;
1134
  }
1135
1136
  /**
1137
   * Checks if a field value is empty.
1138
   *
1139 5d12d676 Assos Assos
   * @param mixed $value
1140 85ad3d82 Assos Assos
   *   The field value.
1141
   * @param bool $empty_zero
1142
   *   Whether or not this field is configured to consider 0 as empty.
1143
   * @param bool $no_skip_empty
1144
   *   Whether or not to use empty() to check the value.
1145
   *
1146
   * @return bool
1147 5d12d676 Assos Assos
   *   TRUE if the value is considered empty, FALSE otherwise.
1148 85ad3d82 Assos Assos
   */
1149 5d12d676 Assos Assos
  public function is_value_empty($value, $empty_zero, $no_skip_empty = TRUE) {
1150 85ad3d82 Assos Assos
    if (!isset($value)) {
1151
      $empty = TRUE;
1152
    }
1153
    else {
1154
      $empty = ($empty_zero || ($value !== 0 && $value !== '0'));
1155
    }
1156
1157
    if ($no_skip_empty) {
1158
      $empty = empty($value) && $empty;
1159
    }
1160
    return $empty;
1161
  }
1162
1163
  /**
1164
   * Perform an advanced text render for the item.
1165
   *
1166
   * This is separated out as some fields may render lists, and this allows
1167
   * each item to be handled individually.
1168
   */
1169 5d12d676 Assos Assos
  public function render_text($alter) {
1170 85ad3d82 Assos Assos
    $value = $this->last_render;
1171
1172
    if (!empty($alter['alter_text']) && $alter['text'] !== '') {
1173
      $tokens = $this->get_render_tokens($alter);
1174
      $value = $this->render_altered($alter, $tokens);
1175
    }
1176
1177
    if (!empty($this->options['alter']['trim_whitespace'])) {
1178
      $value = trim($value);
1179
    }
1180
1181
    // Check if there should be no further rewrite for empty values.
1182
    $no_rewrite_for_empty = $this->options['hide_alter_empty'] && $this->is_value_empty($this->original_value, $this->options['empty_zero']);
1183
1184 5d12d676 Assos Assos
    // Check whether the value is empty and return nothing, so the field isn't
1185
    // rendered. First check whether the field should be hidden if the
1186
    // value(hide_alter_empty = TRUE) /the rewrite is empty (hide_alter_empty =
1187
    // FALSE). For numeric values you can specify whether "0"/0 should be empty.
1188 85ad3d82 Assos Assos
    if ((($this->options['hide_empty'] && empty($value))
1189
        || ($alter['phase'] != VIEWS_HANDLER_RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty))
1190
      && $this->is_value_empty($value, $this->options['empty_zero'], FALSE)) {
1191
      return '';
1192
    }
1193
    // Only in empty phase.
1194
    if ($alter['phase'] == VIEWS_HANDLER_RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty) {
1195
      // If we got here then $alter contains the value of "No results text"
1196
      // and so there is nothing left to do.
1197
      return $value;
1198
    }
1199
1200
    if (!empty($alter['strip_tags'])) {
1201
      $value = strip_tags($value, $alter['preserve_tags']);
1202
    }
1203
1204
    $suffix = '';
1205
    if (!empty($alter['trim']) && !empty($alter['max_length'])) {
1206
      $length = strlen($value);
1207
      $value = $this->render_trim_text($alter, $value);
1208
      if ($this->options['alter']['more_link'] && strlen($value) < $length) {
1209
        $tokens = $this->get_render_tokens($alter);
1210
        $more_link_text = $this->options['alter']['more_link_text'] ? $this->options['alter']['more_link_text'] : t('more');
1211
        $more_link_text = strtr(filter_xss_admin($more_link_text), $tokens);
1212
        $more_link_path = $this->options['alter']['more_link_path'];
1213
        $more_link_path = strip_tags(decode_entities(strtr($more_link_path, $tokens)));
1214
1215 5d12d676 Assos Assos
        // Take sure that paths which was runned through url() does work as
1216
        // well.
1217 85ad3d82 Assos Assos
        $base_path = base_path();
1218
        // Checks whether the path starts with the base_path.
1219
        if (strpos($more_link_path, $base_path) === 0) {
1220
          $more_link_path = drupal_substr($more_link_path, drupal_strlen($base_path));
1221
        }
1222
1223
        $more_link = l($more_link_text, $more_link_path, array('attributes' => array('class' => array('views-more-link'))));
1224
1225
        $suffix .= " " . $more_link;
1226
      }
1227
    }
1228
1229
    if (!empty($alter['nl2br'])) {
1230
      $value = nl2br($value);
1231
    }
1232
    $this->last_render_text = $value;
1233
1234
    if (!empty($alter['make_link']) && !empty($alter['path'])) {
1235
      if (!isset($tokens)) {
1236 5d12d676 Assos Assos
        $tokens = $this->get_render_tokens($alter);
1237 85ad3d82 Assos Assos
      }
1238
      $value = $this->render_as_link($alter, $value, $tokens);
1239
    }
1240
1241
    return $value . $suffix;
1242
  }
1243
1244
  /**
1245
   * Render this field as altered text, from a fieldset set by the user.
1246
   */
1247 5d12d676 Assos Assos
  public function render_altered($alter, $tokens) {
1248 8be7bf84 Assos Assos
    // We trust admins so we allow any tag content. This is important for
1249
    // displays such as XML where we should not mess with tags.
1250
    $value = $alter['text'];
1251 85ad3d82 Assos Assos
    $value = strtr($value, $tokens);
1252 4003efde Assos Assos
    // User might already used '%5B' and '%5D' instead of literal [ and ].
1253
    // After token replacements, we need to convert those codes to literal
1254
    // square bracket characters. Otherwise problems like comment #5 and #6 of
1255
    // https://www.drupal.org/node/578772 will happen.
1256
    // We could have used rawurldecode() also, but not sure about the consequences.
1257
    $value = strtr($value, array('%5B' => '[', '%5D' => ']'));
1258 85ad3d82 Assos Assos
1259
    return $value;
1260
  }
1261
1262
  /**
1263
   * Trim the field down to the specified length.
1264
   */
1265 5d12d676 Assos Assos
  public function render_trim_text($alter, $value) {
1266 85ad3d82 Assos Assos
    if (!empty($alter['strip_tags'])) {
1267
      // NOTE: It's possible that some external fields might override the
1268 5d12d676 Assos Assos
      // element type so if someone from, say, CCK runs into a bug here, this
1269
      // may be why =)
1270 85ad3d82 Assos Assos
      $this->definition['element type'] = 'span';
1271
    }
1272
    return views_trim_text($alter, $value);
1273
  }
1274
1275
  /**
1276 5d12d676 Assos Assos
   * Render this field as a link, with info from a fieldset set by the user.
1277 85ad3d82 Assos Assos
   */
1278 5d12d676 Assos Assos
  public function render_as_link($alter, $text, $tokens) {
1279 85ad3d82 Assos Assos
    $value = '';
1280
1281
    if (!empty($alter['prefix'])) {
1282
      $value .= filter_xss_admin(strtr($alter['prefix'], $tokens));
1283
    }
1284
1285
    $options = array(
1286
      'html' => TRUE,
1287
      'absolute' => !empty($alter['absolute']) ? TRUE : FALSE,
1288
    );
1289
1290
    // $path will be run through check_url() by l() so we do not need to
1291
    // sanitize it ourselves.
1292
    $path = $alter['path'];
1293
1294
    // strip_tags() removes <front>, so check whether its different to front.
1295
    if ($path != '<front>') {
1296 5d12d676 Assos Assos
      // Use strip tags as there should never be HTML in the path. However, we
1297
      // need to preserve special characters like " that were removed by
1298
      // check_plain().
1299 85ad3d82 Assos Assos
      $path = strip_tags(decode_entities(strtr($path, $tokens)));
1300
1301
      if (!empty($alter['path_case']) && $alter['path_case'] != 'none') {
1302
        $path = $this->case_transform($path, $this->options['alter']['path_case']);
1303
      }
1304
1305
      if (!empty($alter['replace_spaces'])) {
1306
        $path = str_replace(' ', '-', $path);
1307
      }
1308 8be7bf84 Assos Assos
1309
      if (!empty($alter['unwanted_characters'])) {
1310
        foreach (explode(' ', $alter['unwanted_characters']) as $unwanted) {
1311
          $path = str_replace($unwanted, '', $path);
1312
        }
1313
      }
1314 85ad3d82 Assos Assos
    }
1315
1316
    // Parse the URL and move any query and fragment parameters out of the path.
1317
    $url = parse_url($path);
1318
1319
    // Seriously malformed URLs may return FALSE or empty arrays.
1320
    if (empty($url)) {
1321
      return $text;
1322
    }
1323
1324
    // If the path is empty do not build a link around the given text and return
1325 5d12d676 Assos Assos
    // it as is. http://www.example.com URLs will not have a $url['path'], so
1326
    // check host as well.
1327 85ad3d82 Assos Assos
    if (empty($url['path']) && empty($url['host']) && empty($url['fragment'])) {
1328
      return $text;
1329
    }
1330
1331
    // If no scheme is provided in the $path, assign the default 'http://'.
1332 5d12d676 Assos Assos
    // This allows a url of 'www.example.com' to be converted to
1333
    // 'http://www.example.com'. Only do this on for external URLs.
1334
    if ($alter['external']) {
1335 85ad3d82 Assos Assos
      if (!isset($url['scheme'])) {
1336
        // There is no scheme, add the default 'http://' to the $path.
1337
        $path = "http://$path";
1338
        // Reset the $url array to include the new scheme.
1339
        $url = parse_url($path);
1340
      }
1341
    }
1342
1343
    if (isset($url['query'])) {
1344
      $path = strtr($path, array('?' . $url['query'] => ''));
1345
      $query = drupal_get_query_array($url['query']);
1346
      // Remove query parameters that were assigned a query string replacement
1347
      // token for which there is no value available.
1348
      foreach ($query as $param => $val) {
1349
        if ($val == '%' . $param) {
1350
          unset($query[$param]);
1351
        }
1352
      }
1353
      $options['query'] = $query;
1354
    }
1355
    if (isset($url['fragment'])) {
1356
      $path = strtr($path, array('#' . $url['fragment'] => ''));
1357
      // If the path is empty we want to have a fragment for the current site.
1358
      if ($path == '') {
1359
        $options['external'] = TRUE;
1360
      }
1361
      $options['fragment'] = $url['fragment'];
1362
    }
1363
1364
    $alt = strtr($alter['alt'], $tokens);
1365
    // Set the title attribute of the link only if it improves accessibility
1366
    if ($alt && $alt != $text) {
1367
      $options['attributes']['title'] = decode_entities($alt);
1368
    }
1369
1370
    $class = strtr($alter['link_class'], $tokens);
1371
    if ($class) {
1372
      $options['attributes']['class'] = array($class);
1373
    }
1374
1375
    if (!empty($alter['rel']) && $rel = strtr($alter['rel'], $tokens)) {
1376
      $options['attributes']['rel'] = $rel;
1377
    }
1378
1379 5d12d676 Assos Assos
    $target = check_plain(trim(strtr($alter['target'], $tokens)));
1380 85ad3d82 Assos Assos
    if (!empty($target)) {
1381
      $options['attributes']['target'] = $target;
1382
    }
1383
1384 5d12d676 Assos Assos
    // Allow the addition of arbitrary attributes to links. Additional
1385
    // attributes currently can only be altered in preprocessors and not within
1386
    // the UI.
1387 85ad3d82 Assos Assos
    if (isset($alter['link_attributes']) && is_array($alter['link_attributes'])) {
1388
      foreach ($alter['link_attributes'] as $key => $attribute) {
1389
        if (!isset($options['attributes'][$key])) {
1390
          $options['attributes'][$key] = strtr($attribute, $tokens);
1391
        }
1392
      }
1393
    }
1394
1395
    // If the query and fragment were programatically assigned overwrite any
1396
    // parsed values.
1397
    if (isset($alter['query'])) {
1398
      // Convert the query to a string, perform token replacement, and then
1399
      // convert back to an array form for l().
1400
      $options['query'] = drupal_http_build_query($alter['query']);
1401
      $options['query'] = strtr($options['query'], $tokens);
1402
      $options['query'] = drupal_get_query_array($options['query']);
1403
    }
1404
    if (isset($alter['alias'])) {
1405
      // Alias is a boolean field, so no token.
1406
      $options['alias'] = $alter['alias'];
1407
    }
1408
    if (isset($alter['fragment'])) {
1409
      $options['fragment'] = strtr($alter['fragment'], $tokens);
1410
    }
1411
    if (isset($alter['language'])) {
1412
      $options['language'] = $alter['language'];
1413
    }
1414
1415
    // If the url came from entity_uri(), pass along the required options.
1416
    if (isset($alter['entity'])) {
1417
      $options['entity'] = $alter['entity'];
1418
    }
1419
    if (isset($alter['entity_type'])) {
1420
      $options['entity_type'] = $alter['entity_type'];
1421
    }
1422
1423
    $value .= l($text, $path, $options);
1424
1425
    if (!empty($alter['suffix'])) {
1426
      $value .= filter_xss_admin(strtr($alter['suffix'], $tokens));
1427
    }
1428
1429
    return $value;
1430
  }
1431
1432
  /**
1433
   * Get the 'render' tokens to use for advanced rendering.
1434
   *
1435 5d12d676 Assos Assos
   * This runs through all of the fields and arguments that are available and
1436
   * gets their values. This will then be used in one giant str_replace().
1437 85ad3d82 Assos Assos
   */
1438 5d12d676 Assos Assos
  public function get_render_tokens($item) {
1439 85ad3d82 Assos Assos
    $tokens = array();
1440
    if (!empty($this->view->build_info['substitutions'])) {
1441
      $tokens = $this->view->build_info['substitutions'];
1442
    }
1443
    $count = 0;
1444
    foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
1445
      $token = '%' . ++$count;
1446
      if (!isset($tokens[$token])) {
1447
        $tokens[$token] = '';
1448
      }
1449
1450 5d12d676 Assos Assos
      // Use strip tags as there should never be HTML in the path. However, we
1451
      // need to preserve special characters like " that were removed by
1452
      // check_plain().
1453 85ad3d82 Assos Assos
      $tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(decode_entities($this->view->args[$count - 1])) : '';
1454
    }
1455
1456
    // Get flattened set of tokens for any array depth in $_GET parameters.
1457
    $tokens += $this->get_token_values_recursive($_GET);
1458
1459
    // Now add replacements for our fields.
1460
    foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
1461
      if (isset($handler->last_render)) {
1462
        $tokens["[$field]"] = $handler->last_render;
1463
      }
1464
      else {
1465
        $tokens["[$field]"] = '';
1466
      }
1467
      if (!empty($item)) {
1468
        $this->add_self_tokens($tokens, $item);
1469
      }
1470
1471
      // We only use fields up to (and including) this one.
1472
      if ($field == $this->options['id']) {
1473
        break;
1474
      }
1475
    }
1476
1477
    // Store the tokens for the row so we can reference them later if necessary.
1478
    $this->view->style_plugin->render_tokens[$this->view->row_index] = $tokens;
1479
    $this->last_tokens = $tokens;
1480
1481
    return $tokens;
1482
  }
1483
1484
  /**
1485
   * Recursive function to add replacements for nested query string parameters.
1486
   *
1487
   * E.g. if you pass in the following array:
1488
   *   array(
1489
   *     'foo' => array(
1490
   *       'a' => 'value',
1491
   *       'b' => 'value',
1492
   *     ),
1493
   *     'bar' => array(
1494
   *       'a' => 'value',
1495
   *       'b' => array(
1496
   *         'c' => value,
1497
   *       ),
1498
   *     ),
1499
   *   );
1500
   *
1501
   * Would yield the following array of tokens:
1502
   *   array(
1503
   *     '%foo_a' => 'value'
1504
   *     '%foo_b' => 'value'
1505
   *     '%bar_a' => 'value'
1506
   *     '%bar_b_c' => 'value'
1507
   *   );
1508
   *
1509 5d12d676 Assos Assos
   * @param array $array
1510 85ad3d82 Assos Assos
   *   An array of values.
1511 5d12d676 Assos Assos
   * @param array $parent_keys
1512 85ad3d82 Assos Assos
   *   An array of parent keys. This will represent the array depth.
1513
   *
1514 5d12d676 Assos Assos
   * @return array
1515
   *   An array of available tokens, with nested keys representative of the
1516
   *   array structure.
1517 85ad3d82 Assos Assos
   */
1518 5d12d676 Assos Assos
  public function get_token_values_recursive(array $array, array $parent_keys = array()) {
1519 85ad3d82 Assos Assos
    $tokens = array();
1520
1521
    foreach ($array as $param => $val) {
1522
      if (is_array($val)) {
1523 5d12d676 Assos Assos
        // Copy parent_keys array, so we don't afect other elements of this
1524
        // iteration.
1525
        $child_parent_keys = $parent_keys;
1526
        $child_parent_keys[] = $param;
1527
        // Get the child tokens.
1528
        $child_tokens = $this->get_token_values_recursive($val, $child_parent_keys);
1529
        // Add them to the current tokens array.
1530
        $tokens += $child_tokens;
1531 85ad3d82 Assos Assos
      }
1532
      else {
1533
        // Create a token key based on array element structure.
1534
        $token_string = !empty($parent_keys) ? implode('_', $parent_keys) . '_' . $param : $param;
1535
        $tokens['%' . $token_string] = strip_tags(decode_entities($val));
1536
      }
1537
    }
1538
1539
    return $tokens;
1540
  }
1541
1542
  /**
1543
   * Add any special tokens this field might use for itself.
1544
   *
1545 5d12d676 Assos Assos
   * This method is intended to be overridden by items that generate fields as a
1546
   * list. For example, the field that displays all terms on a node might have
1547
   * tokens for the tid and the term.
1548 85ad3d82 Assos Assos
   *
1549 5d12d676 Assos Assos
   * By convention, tokens should follow the format of [token-subtoken] where
1550
   * token is the field ID and subtoken is the field. If the field ID is terms,
1551
   * then the tokens might be [terms-tid] and [terms-name].
1552 85ad3d82 Assos Assos
   */
1553 5d12d676 Assos Assos
  public function add_self_tokens(&$tokens, $item) {
1554
  }
1555 85ad3d82 Assos Assos
1556
  /**
1557
   * Document any special tokens this field might use for itself.
1558
   *
1559
   * @see add_self_tokens()
1560
   */
1561 5d12d676 Assos Assos
  public function document_self_tokens(&$tokens) {
1562
  }
1563 85ad3d82 Assos Assos
1564
  /**
1565 5d12d676 Assos Assos
   * Call out to the theme() function.
1566
   *
1567
   * It probably just calls render() but allows sites to override output fairly
1568
   * easily.
1569 85ad3d82 Assos Assos
   */
1570 5d12d676 Assos Assos
  public function theme($values) {
1571 85ad3d82 Assos Assos
    return theme($this->theme_functions(),
1572
      array(
1573
        'view' => $this->view,
1574
        'field' => $this,
1575 5d12d676 Assos Assos
        'row' => $values,
1576 85ad3d82 Assos Assos
      ));
1577
  }
1578
1579 5d12d676 Assos Assos
  /**
1580
   * Build a list of suitable theme functions for this view.
1581
   */
1582
  public function theme_functions() {
1583 85ad3d82 Assos Assos
    $themes = array();
1584
    $hook = 'views_view_field';
1585
1586
    $display = $this->view->display[$this->view->current_display];
1587
1588
    if (!empty($display)) {
1589 5d12d676 Assos Assos
      $themes[] = $hook . '__' . $this->view->name . '__' . $display->id . '__' . $this->options['id'];
1590
      $themes[] = $hook . '__' . $this->view->name . '__' . $display->id;
1591 85ad3d82 Assos Assos
      $themes[] = $hook . '__' . $display->id . '__' . $this->options['id'];
1592
      $themes[] = $hook . '__' . $display->id;
1593
      if ($display->id != $display->display_plugin) {
1594 5d12d676 Assos Assos
        $themes[] = $hook . '__' . $this->view->name . '__' . $display->display_plugin . '__' . $this->options['id'];
1595
        $themes[] = $hook . '__' . $this->view->name . '__' . $display->display_plugin;
1596 85ad3d82 Assos Assos
        $themes[] = $hook . '__' . $display->display_plugin . '__' . $this->options['id'];
1597
        $themes[] = $hook . '__' . $display->display_plugin;
1598
      }
1599
    }
1600
    $themes[] = $hook . '__' . $this->view->name . '__' . $this->options['id'];
1601
    $themes[] = $hook . '__' . $this->view->name;
1602
    $themes[] = $hook . '__' . $this->options['id'];
1603
    $themes[] = $hook;
1604
1605
    return $themes;
1606
  }
1607
1608 5d12d676 Assos Assos
  /**
1609
   * {@inheritdoc}
1610
   */
1611
  public function ui_name($short = FALSE) {
1612 85ad3d82 Assos Assos
    return $this->get_field(parent::ui_name($short));
1613
  }
1614 5d12d676 Assos Assos
1615 85ad3d82 Assos Assos
}
1616
1617
/**
1618
 * A special handler to take the place of missing or broken handlers.
1619
 *
1620
 * @ingroup views_field_handlers
1621
 */
1622
class views_handler_field_broken extends views_handler_field {
1623 5d12d676 Assos Assos
1624
  /**
1625
   * {@inheritdoc}
1626
   */
1627
  public function ui_name($short = FALSE) {
1628 85ad3d82 Assos Assos
    return t('Broken/missing handler');
1629
  }
1630
1631 5d12d676 Assos Assos
  /**
1632
   * {@inheritdoc}
1633
   */
1634
  public function ensure_my_table() {
1635
    // No table to ensure!
1636
  }
1637
1638
  /**
1639
   * {@inheritdoc}
1640
   */
1641
  public function query($group_by = FALSE) {
1642
    // No query to run.
1643
  }
1644
1645
  /**
1646
   * {@inheritdoc}
1647
   */
1648
  public function options_form(&$form, &$form_state) {
1649 85ad3d82 Assos Assos
    $form['markup'] = array(
1650
      '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
1651
    );
1652
  }
1653
1654
  /**
1655 5d12d676 Assos Assos
   * {@inheritdoc}
1656 85ad3d82 Assos Assos
   */
1657 5d12d676 Assos Assos
  public function broken() {
1658
    return TRUE;
1659
  }
1660
1661 85ad3d82 Assos Assos
}
1662
1663
/**
1664
 * Render a numeric value as a size.
1665
 *
1666
 * @ingroup views_field_handlers
1667
 */
1668
class views_handler_field_file_size extends views_handler_field {
1669 5d12d676 Assos Assos
1670
  /**
1671
   * {@inheritdoc}
1672
   */
1673
  public function option_definition() {
1674 85ad3d82 Assos Assos
    $options = parent::option_definition();
1675
1676
    $options['file_size_display'] = array('default' => 'formatted');
1677
1678
    return $options;
1679
  }
1680
1681 5d12d676 Assos Assos
  /**
1682
   * {@inheritdoc}
1683
   */
1684
  public function options_form(&$form, &$form_state) {
1685 85ad3d82 Assos Assos
    parent::options_form($form, $form_state);
1686
    $form['file_size_display'] = array(
1687
      '#title' => t('File size display'),
1688
      '#type' => 'select',
1689
      '#options' => array(
1690
        'formatted' => t('Formatted (in KB or MB)'),
1691
        'bytes' => t('Raw bytes'),
1692
      ),
1693
    );
1694
  }
1695
1696 5d12d676 Assos Assos
  /**
1697
   * {@inheritdoc}
1698
   */
1699
  public function render($values) {
1700 85ad3d82 Assos Assos
    $value = $this->get_value($values);
1701
    if ($value) {
1702
      switch ($this->options['file_size_display']) {
1703
        case 'bytes':
1704
          return $value;
1705
        case 'formatted':
1706
        default:
1707
          return format_size($value);
1708
      }
1709
    }
1710
    else {
1711
      return '';
1712
    }
1713
  }
1714 5d12d676 Assos Assos
1715 85ad3d82 Assos Assos
}
1716
1717
/**
1718
 * A handler to run a field through simple XSS filtering.
1719
 *
1720
 * @ingroup views_field_handlers
1721
 */
1722
class views_handler_field_xss extends views_handler_field {
1723 5d12d676 Assos Assos
1724
  /**
1725
   * {@inheritdoc}
1726
   */
1727
  public function render($values) {
1728 85ad3d82 Assos Assos
    $value = $this->get_value($values);
1729
    return $this->sanitize_value($value, 'xss');
1730
  }
1731 5d12d676 Assos Assos
1732 85ad3d82 Assos Assos
}
1733
1734
/**
1735
 * @}
1736
 */